-
Notifications
You must be signed in to change notification settings - Fork 1
/
wsymymf.c
393 lines (353 loc) · 11.8 KB
/
wsymymf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/* This is for use as an oscillator, short values are put in a ring of certain size and
* then this is fed a total number of values requires and it loops around the ring
* until it gets them.
*
* sr0.c is the proof of concept */
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<string.h>
#include<math.h>
#define SRATE 44100.0
#define SILX .25 /* silence to put in between notes */
#define NUMNOTES 8
/* hardcoded number of samples */
#define NCSAMPS 100 /* Number of Channel Samps: will need to be mutliplied by 2 if nhans is 2 */
typedef struct /* time point, tpt */
{
int m, s, h;
} tpt;
struct svals_t /* a struct with 2 floats: rd, and sonicv */
{
float rd; /* float associated with the radial distance */
union {
float sonicv; /* sonic value */
float sonica[2];
} sv;
};
typedef struct /* wavt_t */
{
struct svals_t *d;
float fsamps;
unsigned nsamps;
float stpsz;
} wavt_t;
struct s_r_n /* short int ring node struct */
{
union {
short s;
short sa[2];
} sv;
struct s_r_n *nx;
};
typedef struct s_r_n sr_t;
typedef struct /* srp_t, a struct to hold a ptr to s_r_n and its size */
{
sr_t *sr;
unsigned sz;
} srp_t;
typedef struct /* WAV hdr struct */
{
char id[4]; // should always contain "RIFF"
int glen; // general length: total file length minus 8, could because the types so far seen (id and glen itself) are actually 8 bytes
char fstr[8]; // format string should be "WAVEfmt ": actually two 4chartypes here.
int fmtnum; // format number 16 for PCM format
short pcmnum; // PCM number 1 for PCM format
short nchans; // num channels
int sampfq; // sampling frequency: CD quality is 44100, 48000 is also common.
int byps; // BYtes_Per_Second (aka, BlockAlign) = numchannels* bytes per sample*samplerate. stereo shorts at 44100 . should be 176k.
short bypc; // BYtes_Per_Capture, bipsamp/8 most probably. A capture is the same as a sample if mono, but half a sample if stereo. bypc usually 2, a short.
short bipsamp; // bits_per_sample: CD quality is 16.
char datastr[4]; // should always contain "data"
int byid; // BYtes_In_Data;
} wh_t; /* wav header type */
tpt *s2tp(char *str)
{
tpt *p=malloc(sizeof(tpt));
char *tc, staminchar[5]={0};
if( (tc=strchr(str, ':')) == NULL) {
printf("There are no minutes \n");
p->m=0;
tc=str;
} else {
strncpy(staminchar, str, (int)(tc-str));
p->m=atoi(staminchar);
tc++;
}
char *ttc, stasecchar[5]={0};
if( (ttc=strchr(tc, '.')) == NULL) {
printf("There are no seconds\n");
p->s=0;
ttc=tc;
} else {
strncpy(stasecchar, tc, (int)(ttc-tc));
p->s=atoi(stasecchar);
ttc++;
}
char stahunschar[5]={0};
strcpy(stahunschar, ttc);
p->h=atoi(stahunschar);
if((strlen(stahunschar))==1)
p->h*=10;
return p;
}
unsigned char *xfw(char *inwf, char *tp, wh_t *inhdr, unsigned ncsamps) /* xfw: extract from wav */
{
FILE *inwavfp=fopen(inwf,"rb");
if ( inwavfp == NULL ) {
fprintf(stderr,"Can't open input file %s", inwf);
exit(EXIT_FAILURE);
}
if ( fread(inhdr, sizeof(wh_t), sizeof(char), inwavfp) < 1 ) {
printf("Can't read file header\n");
exit(EXIT_FAILURE);
}
tpt *p=s2tp(tp);
printf("stamin=%u, stasec=%u, stahuns=%u\n", p->m, p->s, p->h);
int point=inhdr->byps*(p->m*60 + p->s) + p->h*inhdr->byps/100;
printf("point to is %i inside %i which is %.1f%% in.\n", point, inhdr->byid, (point*100.)/inhdr->byid);
if(point >= inhdr->byid) {
printf("Timepoint at which to sample is over the size of the wav file. Aborting.\n");
exit(EXIT_FAILURE);
}
/* recreate based on samples taken */
inhdr->byid = inhdr->bypc*inhdr->nchans*ncsamps; /* number of bytes to extract */
inhdr->glen = inhdr->byid+36;
unsigned char *bf=malloc(inhdr->byid);
fseek(inwavfp, point, SEEK_CUR);
if ( fread(bf, inhdr->byid, sizeof(unsigned char), inwavfp) < 1 ) { /* Yup! we slurp in the baby! */
printf("Sorry, trouble putting input file into array. Overshot maybe?\n");
exit(EXIT_FAILURE);
}
fclose(inwavfp);
free(p);
return bf;
}
wh_t *hdr4chunk(int sfre, char nucha, int numsamps) /* a header for a file chunk of certain size */
{
wh_t *wh=malloc(sizeof(wh_t)); /* always 44 of course, but what the heck */
strncpy(wh->id, "RIFF", 4);
strncpy(wh->fstr, "WAVEfmt ", 8);
strncpy(wh->datastr, "data", 4);
wh->fmtnum=16;
wh->pcmnum=1;
wh->nchans=nucha; /* this fed in */
wh->sampfq=sfre; /* fed in to function */
wh->bipsamp=16; /* hard-coded to shorts, no 24bit here */
wh->bypc=wh->bipsamp/8;
wh->byid=numsamps*wh->nchans*wh->bypc;
wh->glen=wh->byid+36;
wh->byps=wh->nchans*wh->sampfq*wh->bypc;
return wh;
}
sr_t *creasrn0(unsigned ssz) /* create empty ring of size ssz */
{
int i;
sr_t *mou /* mouth with a tendency to eat the tail*/, *ttmp /* type temporary */;
mou=malloc(sizeof(sr_t));
mou->nx=NULL;
ttmp=mou;
for(i=1;i<ssz;++i) {
ttmp->nx=malloc(sizeof(sr_t));
ttmp=ttmp->nx; /* with ->nmove on */
}
ttmp->nx=mou;
return mou;
}
void prtring(sr_t *mou, short ncha)
{
sr_t *st=mou;
do {
if(ncha==2)
printf("%d:%d ", st->sv.sa[0], st->sv.sa[1]);
else if(ncha==1)
printf("%d ", st->sv.s);
st=st->nx;
} while (st !=mou);
putchar('\n');
return;
}
void prtimesring(sr_t *mou, unsigned ntimes, short ncha) /* print all values from CYCLING through the ring */
{
unsigned i=0;
sr_t *st=mou;
do {
if(ncha==2)
printf("%d:%d ", st->sv.sa[0], st->sv.sa[1]);
else if(ncha==1)
printf("%d ", st->sv.s);
st=st->nx;
i++;
} while (i !=ntimes);
putchar('\n');
return;
}
void freerestring(sr_t *lastmou, unsigned numrest) /* free the rest of the ring .. but what happens if we eant to maeke it begger? */
{
unsigned i=0;
sr_t *st=lastmou->nx, *nxt;
while(i<numrest) {
nxt=st->nx; /* we store the nx of this nx */
free(st); /* now we can delete it */
i++;
st=nxt;
}
lastmou->nx=st;
}
void freering(sr_t *mou)
{
sr_t *st=mou->nx, *nxt;
while (st !=mou) {
nxt=st->nx; /* we store the nx of this nx */
free(st); /* now we can delete it */
st=nxt;
}
free(mou);
}
short **ring2buftimes(srp_t *sra, unsigned nnotes, unsigned ntimes, short nchans) /* take ntimes steps through ring */
{
unsigned i, j;
unsigned ttimes=ntimes*nchans;
short **sbuf=malloc(nnotes*sizeof(short*));
for(i=0;i<nnotes;++i)
sbuf[i]=malloc(ttimes*sizeof(short));
sr_t *st;
for(j=0;j<nnotes;j++) {
i=0;
st=sra[j].sr;
while(i<ttimes) {
if(nchans ==2) {
sbuf[j][i++]=st->sv.sa[0];
sbuf[j][i++]=st->sv.sa[1];
} else if(nchans ==1)
sbuf[j][i++]=st->sv.s;
st=st->nx;
}
}
return sbuf;
}
int main(int argc, char *argv[])
{
if(argc != 5) {
printf("Program to populate a wavetable from a certain point in a WAV, and generate different frequencies on it.\n");
printf("4 Arguments: 1) input wavfilename 2) mm:ss.hh time at which to start sampling 3) numsamps2extract 4) output wav.\n");
exit(EXIT_FAILURE);
}
int i, ii;
float fqa[NUMNOTES]={440., 480., 520., 551.25, 660., 800., 1100., 1500.};
// float fqa[NUMNOTES]={440.};
unsigned csndlen=11025; /* hard coded for the time being */
/* get our sampels from the wav file */
unsigned ncsamps=atoi(argv[3]);
wh_t *twhdr=malloc(sizeof(wh_t));
unsigned char *bf= xfw(argv[1], argv[2], twhdr, ncsamps);
short *vals=malloc((twhdr->byid/2)*sizeof(short));
for(i=0;i<twhdr->byid;i+=2) {
ii=i/2;
vals[ii]=((short)bf[i+1])<<8;
vals[ii] |=(short)bf[i];
}
free(bf);
/* 1/3. setting up the "model wavetable" */
wavt_t *wt=malloc(sizeof(wavt_t));
wt->nsamps=ncsamps;
wt->d=malloc(wt->nsamps*sizeof(struct svals_t));
wt->stpsz=2.*M_PI/((float)wt->nsamps); /* distance in radians btwn each sampel int he wavelength */
#ifdef DBG
printf("wt->stpsz=%.2f / wt->nsamps=%u\n", wt->stpsz, wt->nsamps);
#endif
/* OK create the wavetable: the shorts in vals[] must be changed to floats */
if(twhdr->nchans ==1) {
wt->d[0].rd = 0.;
wt->d[0].sv.sonicv=(float)vals[0];
for(i=1;i<wt->nsamps;++i) {
wt->d[i].rd =wt->stpsz*i;
wt->d[i].sv.sonicv=(float)vals[i];
}
} else if(twhdr->nchans ==2) {
wt->d[0].rd = 0.;
wt->d[0].sv.sonica[0]=(float)vals[0];
wt->d[0].sv.sonica[1]=(float)vals[1];
for(i=1;i<wt->nsamps;i++) {
ii=2*i;
wt->d[i].rd =wt->stpsz*i;
wt->d[i].sv.sonica[0]=(float)vals[ii];
wt->d[i].sv.sonica[1]=(float)vals[ii+1];
}
}
#ifdef DBG2
printf("Values from wav file stored in wavtable (as floats):\n");
if(twhdr->nchans ==1)
for(i=0;i<wt->nsamps;++i)
printf("%.1f ", wt->d[i].sv.sonicv);
else if(twhdr->nchans ==2)
for(i=0;i<wt->nsamps;++i)
printf("%.1f:%.1f ", wt->d[i].sv.sonica[0], wt->d[i].sv.sonica[1]);
printf("\n");
#endif
/* 2/3: so our wavetable has been created, as you'll note it only has accurately representative values for one frequency,
* but we're still going to use for other frequencies */
float fsamps;
sr_t *tsr;
float stpsz;
int j, k, m;
float kincs, xprop;
srp_t *sra=malloc(NUMNOTES*sizeof(srp_t)); /* array of rings */
unsigned scsamps; /* Single Channel Samps */
for(m=0;m<NUMNOTES;++m) { /* loop for our frequency range */
fsamps=SRATE/fqa[m];
scsamps=(unsigned)(.5+fsamps);
sra[m].sz=scsamps;
sra[m].sr=creasrn0(sra[m].sz);
tsr=sra[m].sr;
stpsz=2.*M_PI/((float)scsamps);
k=0;
for(i=0;i<sra[m].sz;i++) {
kincs=stpsz*i;
for(j=k; j<wt->nsamps-1; j++)
if(kincs>=wt->d[j].rd)
continue;
else
break;
k=j-1;
xprop=(kincs-wt->d[k].rd)/wt->stpsz;
if(twhdr->nchans==2) {
tsr->sv.sa[0]=(short)(.5+wt->d[k].sv.sonica[0] + xprop*(wt->d[j].sv.sonica[0]-wt->d[k].sv.sonica[0]));
tsr->sv.sa[1]=(short)(.5+wt->d[k].sv.sonica[1] + xprop*(wt->d[j].sv.sonica[1]-wt->d[k].sv.sonica[1]));
} else if(twhdr->nchans==1)
tsr->sv.s=(short)(.5+wt->d[k].sv.sonicv + xprop*(wt->d[j].sv.sonicv-wt->d[k].sv.sonicv));
tsr=tsr->nx;
}
#ifdef DBG2
printf("Ring values: these have been calculated from the wavetable:\n");
prtring(tsr, twhdr->nchans);
#endif
}
/* 3/3: our cycle through ring and sound into buffer */
short **sbuf; /* our sound info buffer */
unsigned silsamps=(unsigned)(.5+SILX*SRATE);
short *silbuf=calloc(silsamps*twhdr->nchans,sizeof(short));
sbuf=ring2buftimes(sra, NUMNOTES, csndlen, twhdr->nchans);
wh_t *hdr=hdr4chunk((int)SRATE, twhdr->nchans, (NUMNOTES-1)*silsamps + NUMNOTES*csndlen);
FILE *fout=fopen(argv[4], "wb");
fwrite(hdr, sizeof(char), 44, fout);
for(i=0;i<NUMNOTES;++i) {
fwrite(sbuf[i], sizeof(short), twhdr->nchans*csndlen, fout);
if(i!=NUMNOTES-1)
fwrite(silbuf, sizeof(short), twhdr->nchans*silsamps, fout);
}
fclose(fout);
free(hdr);
free(twhdr);
free(vals);
for(i=0;i<NUMNOTES;++i)
free(sbuf[i]);
free(sbuf);
free(silbuf);
free(wt->d);
free(wt);
for(i=0;i<NUMNOTES;++i)
freering(sra[i].sr);
free(sra);
return 0;
}