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.