ftp.nice.ch/peanuts/GeneralData/Documents/dsp/DSPTutorial.tar.gz#/DSPTutorial/Examples/06_DMA_To_DSP/perso_b.c

This is perso_b.c in view mode; [Download] [Up]

//Written by J. Laroche at the Center for Music Experiment at UCSD, San Diego //California. December 1990.

// A simple example showing how to use host-> DSP DMA transfer. This program 
// plays a sound file through the DSP sending samples using DMA in both 
// directions. Note the use of vm_allocate() and vm_write() since DMA to the
// DSP requires alignment with virtual memory pages. Also, note that the
// sound is not played till the end, since vm_write() can copy only an integer
// number of virtual memory pages. 

// Note that the high water mark used in the driver is set to a high value.
// If you don't do that, playing won't be reliable.

// Note also that when after the whole sound has been sent, the DSP doesn't 
// know that nothing's left, and sends another DMA-in request, like it does
// normally. A reliable C program should send the whole sound, then signal the
// DSP that there's nothing else to come, then send it one buffer of junk 
// values to terminate. This could be done in the write_completed() function.

// To pass parameters to the DSP, it's best not to use host-commands (too
// slow.) For each parameter (here, only the volume) we pass two ints: a header
// indicating what parameter is to be updated, and the value of the parameter.
// The DSP stores them in a queue and updates all parameters according to the
// header. Note that the driver makes sure that there is no data collision 
// between the samples and the parameter values.


#import <sound/sound.h>
#import <sound/sounddriver.h>
#import <mach.h>
#import <stdio.h>


#define Error(A,B) if((A)) {fprintf(stderr,"%s %s\n",B, SNDSoundError((A)));\
mach_error(B,(A)); }

#define DMASIZE 4096

static int done;

static void write_started(void *arg, int tag)
{
    fprintf(stderr,"Starting playing... %d \n",tag);
}

static void write_completed(void *arg, int tag)
{
    fprintf(stderr,"Playing done... %d\n",tag);
    done = 1;
}


static void over_run(void *arg, int tag)
{
    fprintf(stderr,"Under or Over run... %d\n",tag);
}


void main (int argc, char *argv[])
{
    static port_t dev_port, owner_port, cmd_port;
    static port_t reply_port, read_port, write_port;
    int i, protocol;
    kern_return_t k_err;
    snddriver_handlers_t handlers = { 0, 0, 
    		write_started, write_completed,0,0,0,over_run, 0};
    msg_header_t *reply_msg;
    SNDSoundStruct *dspStruct;
    SNDSoundStruct *sound;
    short *location;
    int length;
    int low_water = 48*1024;
    int high_water = 512*1024;	// 64 instead of 512 makes it work like shit!
    short *foo;
    int LENGTH;
    int low_SR = 0;
    int stereo = 0;

    if(argc == 1) { printf("I need a 16bit linear sound file...\n");
    exit(1);}
        

    k_err = SNDAcquire(SND_ACCESS_DSP|SND_ACCESS_OUT,0,0,0,
    	NULL_NEGOTIATION_FUN,0,&dev_port,&owner_port); 
    Error(k_err,"SND and DSP acquisition  ");
    
    k_err = snddriver_get_dsp_cmd_port(dev_port,owner_port,&cmd_port);
    Error(k_err,"Cmd port acquisition  ");

    k_err = SNDReadSoundfile(argv[1], &sound);
    Error(k_err,argv[1]);
    
    low_SR = (sound->samplingRate == SND_RATE_LOW);
    stereo = (sound->channelCount == 2);
    printf("Playing at %d Hz %s\n",((low_SR)?22050:44100),((stereo)?
    	"stereo":"mono"));

    k_err = SNDGetDataPointer(sound,(char**)&location,&length,&i);
    Error(k_err,"Data Pointer");

    
    protocol = SNDDRIVER_DSP_PROTO_RAW;
    k_err = snddriver_stream_setup(dev_port, owner_port,
    				 SNDDRIVER_DMA_STREAM_TO_DSP,
				 DMASIZE,2, 
				 low_water, high_water,
				 &protocol, &read_port);
    Error(k_err,"Stream 1 set_up");
    k_err = snddriver_stream_setup(dev_port, owner_port,((low_SR) ?
			SNDDRIVER_STREAM_DSP_TO_SNDOUT_22:
			SNDDRIVER_STREAM_DSP_TO_SNDOUT_44),
			    	 DMASIZE, 2, 
				 low_water, high_water,
				 &protocol, &write_port);
    Error(k_err,"Stream 2 set_up");
    
    k_err = snddriver_dsp_protocol(dev_port, owner_port, protocol);
    Error(k_err,"Protocol set-up  ");
    
    k_err = port_allocate(task_self(),&reply_port);

    k_err = SNDReadDSPfile("perso_b.lod", &dspStruct, NULL);
    Error(k_err,"Reading .lod file  ");

    k_err = SNDBootDSP(dev_port, owner_port, dspStruct);
    Error(k_err,"Booting DSP  ");
    printf("DSP booted\n");

    if(!stereo)		// If mono, tell it to the DSP!
    k_err = snddriver_dsp_host_cmd(cmd_port,21,SNDDRIVER_LOW_PRIORITY);


    // To use DMA to the DSP, you need alignment with vm pages. Therefore you
    // need to allocate virtual memory, and copy your sound in it. Here, we 
    // just copy an integer number of virtual memory pages. To play the whole
    // sound, you would need to allocate more memory, and copy the rest 
    // in a for loop. vm_page_size is a global variable containing the size of
    // the virtual memory pages (in bytes.)
    
    LENGTH = (length*sizeof(short)/vm_page_size)*vm_page_size/sizeof(short);

    vm_allocate(task_self(),(vm_address_t *)(&foo),2*LENGTH,TRUE);
    Error(k_err,"VM Allocation  ");
    
    vm_write(task_self(), (vm_address_t)(foo), (pointer_t)location,2*LENGTH);
    Error(k_err,"VM Write  ");

    k_err = snddriver_stream_start_writing(read_port,
    					 (void *)foo, LENGTH,
					 1,
					 0,0,
					 1,1,0,0,0,1, reply_port);
    Error(k_err,"Starting writing  ");


    reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX);

    done = 0;
    while (done != 1) 
	{
	int i[2];	// 2 values: the header, and the value
	i[0] = 1;	// 1 stands for volume
	
#if 0	    
	    reply_msg->msg_size = MSG_SIZE_MAX;
	    reply_msg->msg_local_port = reply_port;
	    k_err = msg_receive(reply_msg, MSG_OPTION_NONE, 0);
	    k_err = snddriver_reply_handler(reply_msg,&handlers);
#endif	    
	    printf("Value of the volume (max 8388608)? ");
	    scanf("%d",i+1);
	    k_err = snddriver_dsp_write(cmd_port,i,2,sizeof(int),
   						SNDDRIVER_MED_PRIORITY);
	}
    
}


These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.