This is srconv.c in view mode; [Download] [Up]
// Srconv, a sampling rate conversion program by J. Laroche. June 1991 // Version 1.0 #import <sound/sound.h> #import <sound/sounddriver.h> #include <sys/file.h> #include<defaults.h> #import <mach.h> #import <math.h> #import <stdio.h> #include <strings.h> #define Error(A,B) if((A)) {fprintf(stderr,"%s\n",B); exit(0);} #define MAX(A,B) ((A) < (B) ? (B) : (A)) #define MIN(A,B) ((A) > (B) ? (B) : (A)) #define DMASIZE 2048 #define MAX_ORDER 30 #define MEMMAX 6000 // MAX_ORDER and MEMMAX depend on how much memory you have on your DSP. // These are default values. If you have more memory than 8Kwords, // you should add the difference (in words) to MEMMAX, which would enable // longer filters, and therefore higher ratios. (MEMMAX is the amount of // DSP memory dedicated to the filter coefficients.) offset is the offset // value for cutoff frequency. It also depends on the length of the filter. static int done; static short *read_data; static int read_count; static void recorded_data(void *arg, int tag, void *p, int nbytes) { read_data = (short *)p; read_count = nbytes; done = 1; } static void read_completed(void *arg, int tag) { done = 2; } 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, j, protocol; kern_return_t k_err; SNDSoundStruct *sound; SNDSoundStruct *converted; char *file[10], DSP_file[200]; SNDSoundStruct *dspStruct; snddriver_handlers_t handlers = { 0, 0, 0, read_completed, 0, 0, 0, 0, recorded_data}; msg_header_t *reply_msg; int low_water = 48*1024; int high_water = 64*1024; short *location,*blank; int WRITE_TAG = 1; int READ_TAG = 2; int length; int stereo = 0; int PLAY = 1; int verbose = 0; int P = 0, Q = 0, K = 0; int para[4],rat[2]; int *filtre; float cut, thresh, offset; int S_rateIn, S_rateOut, S=0; void cal_filtre(); void fract(); void usage(); int testfile(); thresh = 0.003; offset=0.02; for(i=1,j=0;i<argc;i++) switch(argv[i][0]) { case '-' : switch(argv[i][1]) { case 'v' : verbose = 1; break ; case 'P' : P = atoi(argv[i]+2); break ; case 'Q' : Q = atoi(argv[i]+2); break ; case 'K' : K = atoi(argv[i]+2); break ; case 'S' : S = atoi(argv[i]+2); break ; case 't' : thresh = atof(argv[i]+2); break ; case 'o' : offset = atof(argv[i]+2); break ; default : usage(); } break ; default : file[j++] = argv[i]; break ; } if(j == 2) PLAY = 0; if(PLAY == 1 && j == 0) usage(); k_err = SNDAcquire(SND_ACCESS_OUT|SND_ACCESS_DSP,0,0,0, NULL_NEGOTIATION_FUN,0,&dev_port,&owner_port); Error(k_err,"DSP Busy\n"); k_err = snddriver_get_dsp_cmd_port(dev_port,owner_port,&cmd_port); k_err = SNDReadSoundfile(file[0], &sound); Error(k_err,"Couldn't open sound file\n"); Error(sound->dataFormat != SND_FORMAT_LINEAR_16, "Bad format: I need 16 bits linear"); S_rateIn = sound->samplingRate; if(S==0 && P == 0 && Q == 0 && PLAY) S = 44100; if(S!=0) { fract((float)S_rateIn/(float)S,rat,thresh); Q = rat[0]; P = rat[1]; } if(P==0) P = 1; if(Q==0) Q = 1; if(P > 100 || Q > 100) Error(1,"Unable to convert: values of P or Q too large.\n"); if(P > MAX_ORDER || Q > MAX_ORDER) printf("Warning! P and Q should not be larger than %d.\n", MAX_ORDER); S_rateOut = (int) floor((float) S_rateIn * (float)P / (float)Q); k_err = SNDGetDataPointer(sound,(char**)&location,&length,&i); stereo = (sound->channelCount == 2); if(verbose) printf("Converting a %s sound, %d echant\n",((stereo)?"stereo":"mono"), length); if(verbose) printf("From %d Hz to %d Hz\n",S_rateIn,S_rateOut); if(PLAY && K == 0) K = MIN(33, MEMMAX / P); else if(K == 0) K = (int) MEMMAX / P; K = MIN(K,200); if(verbose) printf("Filter Length: %d, Up-factor %d, Down-factor %d\n",K,P,Q); para[0] = P; para[1] = Q; para[2] = K-1; para[3] = K*P+2; protocol = SNDDRIVER_DSP_PROTO_RAW; k_err = snddriver_stream_setup(dev_port, owner_port, SNDDRIVER_STREAM_TO_DSP, DMASIZE, 2, low_water, high_water, &protocol, &write_port); Error(k_err,"Stream "); k_err = snddriver_stream_setup(dev_port, owner_port,((PLAY)? SNDDRIVER_STREAM_DSP_TO_SNDOUT_44 : SNDDRIVER_STREAM_FROM_DSP), DMASIZE, 2, low_water, high_water, &protocol, &read_port); Error(k_err,"Stream "); k_err = snddriver_dsp_protocol(dev_port, owner_port, protocol); k_err = port_allocate(task_self(),&reply_port); strcpy(DSP_file,argv[0]); strcat(DSP_file,".lod"); k_err = SNDReadDSPfile(DSP_file, &dspStruct, NULL); if(k_err) { char *path; path = getenv("PATH"); i = NXFilePathSearch(path,path,0,DSP_file,testfile,&dspStruct); Error(i != -2,"Unable to locate file srconv.lod"); } k_err = SNDBootDSP(dev_port, owner_port, dspStruct); if(stereo) k_err = snddriver_dsp_host_cmd(cmd_port,20,SNDDRIVER_LOW_PRIORITY); if(PLAY) k_err = snddriver_dsp_host_cmd(cmd_port,21,SNDDRIVER_LOW_PRIORITY); filtre = (int*) calloc(K*P,sizeof(int)); cut = 3.14159265 * (1/(float) MAX(P,Q) - offset); cal_filtre(filtre, K*P, cut, P); k_err = snddriver_dsp_write(cmd_port,para,4,sizeof(int), SNDDRIVER_HIGH_PRIORITY); for(i=0;i<K*P/20;i++,filtre += 20) k_err = snddriver_dsp_write(cmd_port,filtre,20,sizeof(int), SNDDRIVER_HIGH_PRIORITY); k_err = snddriver_dsp_write(cmd_port,filtre,K*P % 20,sizeof(int), SNDDRIVER_HIGH_PRIORITY); vm_allocate(task_self(), (vm_address_t *)(&blank),(int)(2*Q/P+2)*DMASIZE,TRUE); if(PLAY) k_err = snddriver_stream_start_writing(write_port,blank, (int)(Q/P+1)*DMASIZE, WRITE_TAG,0,0,0,0,0,0,0,0, reply_port); k_err = snddriver_stream_start_writing(write_port,location, length, WRITE_TAG,0,0,0,0,0,0,0,0, reply_port); k_err = snddriver_stream_start_writing(write_port,blank, (int)(Q/P+1)*DMASIZE, WRITE_TAG,0,0,0,1,0,0,0,0, reply_port); if(!PLAY) k_err = snddriver_stream_start_reading(read_port,0, length*P/Q,READ_TAG, 1,0,0,0,0,0, reply_port); reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX); done = 0; while (done != 1) { 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); if(PLAY && done == 2) done = 1; } if(PLAY) exit(0); k_err = SNDAlloc(&converted,2*length*P/Q, sound->dataFormat, S_rateOut, sound->channelCount,4); Error(k_err,"SND Allocation"); k_err = SNDGetDataPointer(converted,(char**)&location,&i,&i); if(verbose) printf("Copying the sound...\n"); for(i=0;i<length*P/Q;i++) *location++ = *read_data++; k_err = SNDWriteSoundfile(file[1], converted); Error(k_err,"Write Sound"); } // Calculates FIR low-pass filter by windowing a sinc with a hamming window, // and normalizing. void cal_filtre(filtre, order, freq_cut, P) int *filtre; int order; float freq_cut; int P; { int i; float scaler; float aux; for(i=1,scaler = 0;i<order/2;i++) { aux = (sin(freq_cut * i) / freq_cut / i * (0.54 + 0.46 * cos(6.28318530*i/(order-2)))); filtre[order/2+i] = filtre[order/2-i] = 8388607 * aux ; scaler += 2 * aux; } scaler = P * 0.9 / (1 + scaler); filtre[order/2] = 8388607 * scaler; for(i=1;i<order/2;i++) filtre[order/2+i] = filtre[order/2-i] = filtre[order/2-i]*scaler; } /* fract(x,rat) returns in rat a ratio that best approximates the real x with an relative error less than thresh, making sure P and Q are less than 100. Thresh is equal to 0.03, the auditory threshold for pitch sensation. */ void fract(x,rat,thresh) float x; int *rat; float thresh; { int i=0,j; float error = 1; float reste; int *A, *p, *q; int prev_p = 1, prev_q = 1; A = (int*) calloc(20,sizeof(int)); p = (int*) calloc(20,sizeof(int)); q = (int*) calloc(20,sizeof(int)); reste = x; while(error/x > thresh) { A[i] = floor(reste); reste = 1 / (reste - A[i]); for(j=i, p[i]=1, q[i]=A[i]; j>0; j--) { p[j-1] = q[j]; q[j-1] = A[j-1] * q[j] + p[j]; } error = fabs((float)q[0]/(float)p[0] - x); if(p[0] < MAX_ORDER && q[0] < MAX_ORDER) { prev_p = p[0]; prev_q = q[0]; } else { printf("Warning, difficult conversion: ideal factors P = %d, Q = %d,\n", p[0],q[0]); p[0] = prev_p; q[0] = prev_q; error = fabs((float)q[0]/(float)p[0] - x); printf("Actual factors: P = %d, Q = %d, \ Resulting Sampling rate error: %.2f %%\n",p[0],q[0],100*error/x); break; } i++; } rat[0] = q[0]; rat[1] = p[0]; } // testfile() tries to load the .lod file and returns -2 if it can int testfile(char *path, SNDSoundStruct **dspStruct) { int k_err; k_err = SNDReadDSPfile(path, dspStruct, NULL); return((k_err == 0) * -2); } void usage() { printf("Usage: srconv \t-[PQSK] sound1 [sound2] \n\t\t\ -S:Output sampling rate\n\t\t\ -P:Up-sampling factor\n\t\t\ -Q:Down-sampling factor\n\t\t\ -K:filter-Order\n\t\t\ -t:Sampling rate accuracy (default 0.003) \n\t\t\ -o:Cut-off frequency offset (default 0.02) \n\t\t\ -v: verbose: indicates conversion parameters\n\t\t\ Example: \n\tTo convert: \tsrconv -S48000 file.snd out.snd\n\t\ \t\tsrconv -P7 -Q2 file.snd out.snd\n\t\ To play: \tsrconv file.snd\n"); exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.