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.