1 /* sdif2adsyn.c: convert SDIF 1TRC additive synthesis data to Csound adsyn format
2 * v1.0 Richard W Dobson August 4 2000
3
4 Copyright (c) 2000 Richard Dobson
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <string.h>
28
29 #include "sdif.h"
30 #include "sdif-mem.h"
31
32 #ifndef max
33 #define max(x,y) ((x)>(y) ? (x) : (y))
34 #endif
35 #ifndef min
36 #define min(x,y) ((x)>(y) ? (y) : (x))
37 #endif
38
39 /* SDIF indices start from 1 */
40 #define MAXPARTIALS (1025)
41 /* some old but worthy CNMAT functions */
42
43 typedef struct {
44 sdif_float32 index, freq, amp, phase;
45 } SDIF_RowOf1TRC;
46
47 int32_t
SDIF_Read1TRCVals(FILE * f,sdif_float32 * indexp,sdif_float32 * freqp,sdif_float32 * ampp,sdif_float32 * phasep)48 SDIF_Read1TRCVals(FILE *f,
49 sdif_float32 *indexp, sdif_float32 *freqp,
50 sdif_float32 *ampp, sdif_float32 *phasep) {
51 SDIF_RowOf1TRC data;
52
53 #ifdef LITTLE_ENDIAN
54 if (SDIF_Read4(&data, 4, f) != ESDIF_SUCCESS) return -1;
55 #else
56 if (fread(&data, sizeof(data), 1, f) != 1) return -1;
57 #endif
58
59 *indexp = data.index;
60 *freqp = data.freq;
61 *ampp = data.amp;
62 *phasep = data.phase;
63
64 return 0;
65
66 }
67
usage(void)68 void usage(void)
69 {
70 printf("SDIF2ADS v1.0: convert sdif 1TRC data to Csound hetro data file.\n"
71 "usage: [-sN][-pN] sdif2adsyn infile.sdif outfile.ads\n"
72 " -s : apply amplitude scale factor N\n"
73 " -p : keep only the first N partials.\n"
74 " (limit: 1024 partials)\n"
75 " NB: the source partial track indices are used directly\n"
76 " to select internal storage.\n"
77 " As these can be arbitrary values, the maximum\n"
78 " of 1024 partials may not be realized in all cases.\n");
79 }
80
81 typedef struct partial_point{
82 float amp;
83 float freq;
84 float pos;
85 struct partial_point *next;
86 } P_POINT;
87
88 typedef struct partial_props {
89 int64_t numpoints;
90 float maxamp;
91 float maxfreq;
92 float minfreq;
93 P_POINT *head;
94 } PPROPS;
95
96 int32_t write_partial(FILE *fp,const P_POINT *partial,float sfac,int32_t do_scale)
97 ;
98
new_ppoint(float amp,float freq,float pos)99 P_POINT *new_ppoint(float amp,float freq,float pos)
100 {
101 P_POINT *point;
102
103 point = (P_POINT *) malloc(sizeof(P_POINT));
104 if (point) {
105 point->amp = amp;
106 point->freq = freq;
107 point->pos = pos;
108 point->next = NULL;
109 }
110 return point;
111 }
112
113 /* if anyone wants it, there is enough information to select a
114 frequency range to output.*/
115
new_pprops(void)116 PPROPS *new_pprops(void)
117 {
118 PPROPS *prop;
119 prop = (PPROPS *) malloc(sizeof(PPROPS));
120 if (prop) {
121 prop->numpoints = 0;
122 prop->maxamp = 0.0f;
123 prop->maxfreq = 0.0f;
124 prop->minfreq = 0.0f;
125 prop->head = NULL; /* will point to head of partial[n] */
126 }
127 return prop;
128 }
129
main(int argc,char ** argv)130 int main(int argc, char **argv)
131 {
132 int32_t i,framecount, partials_written = 0;
133 int32_t result, iindex;
134 int32_t max_partials = MAXPARTIALS;
135 int32_t n_partials = 0, maxpoints = 0;
136 sdif_int32 frame_id = -1;
137 SDIF_FrameHeader fh;
138 SDIF_MatrixHeader mh;
139
140 FILE *infile,*outfile;
141 P_POINT **partials;
142 PPROPS **pprops;
143 sdif_float32 index,amp,freq,phase;
144
145 float thistime = 0.0f;
146 float maxfreq = 0.0f, minfreq = 100000.0f, maxamp = 0.0f;
147 float scalefac = 1.0;
148 int32_t doscale = 0;
149 short stemp; /* to write partial count to adsyn file */
150
151 if (argc < 2) {
152 usage();
153 exit(1);
154 }
155 printf("SDIF2ADS v1.1\n");
156
157 if (SDIF_Init() != ESDIF_SUCCESS) {
158 fprintf(stderr,"OOPS: SDIF does not work on this machine!\n");
159 exit(1);
160 }
161
162 while (argv[1][0]=='-') {
163 switch (argv[1][1]) {
164 case('s'):
165 if (argv[1][2] == '\0') {
166 fprintf(stderr,"-s flag requires parameter.\n");
167 usage();
168 exit(1);
169 }
170 scalefac = (float) atof(&(argv[1][2]));
171 if (scalefac==0.0f) {
172 fprintf(stderr,"silly value for scalefac!\n");
173 exit(1);
174 }
175 doscale = 1;
176 break;
177 case('p'):
178 if (argv[1][2] == '\0') {
179 fprintf(stderr,"-p flag requires parameter.\n");
180 usage();
181 exit(1);
182 }
183 max_partials = atoi(&(argv[1][2]));
184 if (max_partials < 1) {
185 fprintf(stderr, "-p value too low: need at least one partial!\n");
186 usage();
187 exit(1);
188 }
189 if (max_partials > (MAXPARTIALS-1)) {
190 printf("Warning: -p value too high: setting to %d\n",
191 MAXPARTIALS-1);
192 }
193
194 break;
195 default:
196 fprintf(stderr,"\nunrecognized flag option %s",argv[1]);
197 usage();
198 exit(1);
199 }
200 argc--;
201 argv++;
202 }
203 if (argc < 2) {
204 fprintf(stderr,"\nSDIF2ADSYN: insufficient arguments");
205 usage();
206 exit(1);
207 }
208
209 result = SDIF_OpenRead(argv[1],&infile);
210 if (result != ESDIF_SUCCESS) {
211 fprintf(stderr,"Could not open %s: %s\n",
212 argv[1], SDIF_GetErrorString(result));
213 exit(1);
214 }
215
216 if ((outfile = fopen(argv[2],"wb"))==NULL) {
217 fprintf(stderr,"\nunable to open outfile %s",argv[3]);
218 fclose(infile);
219 exit(1);
220 }
221
222 /* initialize partials array */
223 /* NB index value 0 NOT USED */
224 /* allocate for 1024 partials; use user limit on writing outfile */
225 partials = (P_POINT **) malloc(MAXPARTIALS * sizeof(P_POINT *));
226 if (partials==NULL) {
227 puts("No memory for partial data!\n");
228 exit(1);
229 }
230 pprops = (PPROPS **) malloc (MAXPARTIALS * sizeof(PPROPS *));
231 if (pprops==NULL) {
232 puts("No memory for partial data!\n");
233 free(partials);
234 exit(1);
235 }
236
237 for (i=0;i < MAXPARTIALS; i++) {
238 partials[i] = NULL;
239 pprops[i] = NULL;
240 }
241
242 /* STRATEGY: a very straight conversion from a frame structure to
243 * a breakpoint structure. for each new partial in the SDIF file,
244 * we start a new partial in the array, at the given index. when
245 * a partial dies, the amplitude is (presumed to be) zero, but the
246 * list is not terminated. if an SDIF frame with that index
247 * starts a new partial, the partial with that index continues
248 * accordingly.
249 *
250 * Though in most cases, track indices will small and sequential,
251 * this cannot be presumed. If most or all indices are above
252 * MAXPARTIALS, we are b******d.
253 * Of course, the SDIF file will not tell us what the index range is.
254 * That would be too easy.
255 */
256
257 /* main loop to read sdif frames */
258 framecount = 0;
259 /* assume the frame is kosher for now...*/
260 while ((result = SDIF_ReadFrameHeader(&fh, infile))==ESDIF_SUCCESS) {
261
262 if (strncmp(fh.frameType,"1TRC",4))
263 continue;
264
265 /*we can only copy one stream - use the first one! */
266 if (frame_id==-1)
267 frame_id = fh.streamID;
268 else if (frame_id != fh.streamID) {
269 fprintf(stderr,"\nWARNING: multiple stream IDs found - skipping");
270 continue;
271 }
272 #ifdef _DEBUG
273 /*printf("\nReading SDIF Frame %d, time = %.4f",framecount,fh.time); */
274 #endif
275 thistime = (float) fh.time;
276 /* Csound adsyn counts time in msecs, in shorts, so can only have
277 32.767 seconds! */
278 if (thistime > 32.76f) {
279 printf("Sorry! Reached ADSYN limit of 32.76 seconds.\n");
280 break;
281 }
282 framecount++;
283 for (i = 0; i < fh.matrixCount; ++i) {
284 int32_t j;
285
286 if (SDIF_ReadMatrixHeader(&mh,infile) != ESDIF_SUCCESS) {
287 fprintf(stderr,"\nerror reading infile");
288 exit(1);
289 }
290 /* for now, only accept floats */
291 if (mh.matrixDataType != SDIF_FLOAT32) {
292 fprintf(stderr,"\nsorry - data not floats");
293 exit(1);
294 }
295
296 n_partials = mh.rowCount;
297 #ifdef _DEBUG
298 /*printf("\nReading Matrix %d: %d rows",i+1,n_partials); */
299 #endif
300
301 for (j=0;j < n_partials; j++) {
302
303 if (SDIF_Read1TRCVals(infile,&index,&freq,&, &phase)) {
304 fprintf(stderr,"\nerror reading tracks");
305 exit(1);
306 }
307 if (index < 1.0f) {
308 fprintf(stderr,"Illegal partial index %.2f found in frame %d.\n",
309 index,framecount);
310 exit(1);
311 }
312 iindex = (int32_t) index;
313 /* a small (unlikely) sacrifice for the sake of a simple algorithm! */
314 if (iindex >= MAXPARTIALS) {
315 printf("Warning: high partial index %d in frame %d; skipping.\n",
316 iindex,framecount);
317 continue;
318 }
319 /* make a new list if we need it */
320 if (partials[iindex]==NULL) {
321 partials[iindex] = new_ppoint(amp,freq,thistime);
322 if (partials[iindex]==NULL) {
323 puts("No memory for partial data!\n");
324 exit(1);
325 }
326 pprops[iindex] = new_pprops();
327 if (pprops[iindex]==NULL) {
328 puts("No memory for partial data!\n");
329 exit(1);
330 }
331 pprops[iindex]->head = partials[iindex];
332 pprops[iindex]->maxamp = amp;
333 pprops[iindex]->maxfreq = pprops[iindex]->minfreq = freq;
334 pprops[iindex]->numpoints = 1;
335 }
336
337 else {
338 /*attach new point to existing list, and update props */
339 partials[iindex]->next = new_ppoint(amp,freq,thistime);
340 if (partials[iindex]->next==NULL) {
341 puts("No memory for partial data!\n");
342 exit(1);
343 }
344 partials[iindex] = partials[iindex]->next;
345
346 pprops[iindex]->maxamp = max(pprops[iindex]->maxamp,amp);
347 pprops[iindex]->maxfreq = max(pprops[iindex]->maxfreq,freq);
348 pprops[iindex]->minfreq = min(pprops[iindex]->minfreq,freq);
349 pprops[iindex]->numpoints++;
350 }
351 }
352 }
353 }
354 /* maybe a single frame is legit? */
355 if (framecount < 2) {
356 if (framecount==1)
357 fprintf(stderr,"Only one frame found: at least two required.\n");
358 else
359 fprintf(stderr,"No 1TRC frames found in this sdif file.\n");
360 SDIF_CloseRead(infile);
361 fclose(outfile);
362 free(partials);
363 free(pprops);
364 exit(0);
365 }
366
367 /* now we have to write it all out for Csound */
368 /* how many partials do we have, and what might a good srate be?*/
369 n_partials = 0;
370 for (i=0;i < MAXPARTIALS;i++) {
371 if (partials[i] != NULL) {
372 maxfreq = max(maxfreq,pprops[i]->maxfreq);
373 minfreq = min(minfreq,pprops[i]->minfreq);
374 maxamp = max(maxamp,pprops[i]->maxamp);
375 maxpoints = max(maxpoints,pprops[i]->numpoints);
376 n_partials++;
377 }
378 }
379 printf("total partials read = %d\n",n_partials);
380 printf("maximum breakpoints = %d\n",maxpoints);
381 printf("max frequency found = %.4f\n",maxfreq);
382 printf("min frequency found = %.4f\n",minfreq);
383 printf("max partial amp found = %.4f\n",maxamp);
384 printf("last frame time = %.4f\n",thistime);
385
386 /* OK, write this all to adsyn file as shorts (for now....) */
387 stemp = (short) n_partials;
388 stemp = min(stemp,max_partials); /* set user limit, if any */
389 /* write number of partial tracks */
390 if (fwrite((short *) &stemp,sizeof(short),1,outfile) < 1) {
391 fprintf(stderr,"Error writing to outfile.\n");
392 exit(1);
393 }
394 /* now write each set of amp,freq sets */
395
396 for (i=0;i < MAXPARTIALS;i++) {
397 if (partials[i]==NULL)
398 continue;
399 if (write_partial(outfile,pprops[i]->head,scalefac,doscale) < 0) {
400 fprintf(stderr,"Error writing partial %d.\n",i);
401 exit(1);
402 }
403 partials_written++;
404 if (partials_written == (int32_t) stemp)
405 break;
406 }
407
408 /* release linked lists */
409 for (i=0;i < MAXPARTIALS;i++) {
410 P_POINT *tthis,*next;
411 if (partials[i]==NULL)
412 continue;
413 tthis = pprops[i]->head;
414 free(pprops[i]);
415 next = tthis->next;
416 while(next) {
417 free(tthis);
418 tthis = next;
419 next = next->next;
420 }
421 free(tthis);
422 }
423 free(partials);
424 free(pprops);
425 fclose(outfile);
426 printf("File conversion completed.\n");
427 printf("%d partials written to %s\n",(int32_t)stemp,argv[2]);
428 SDIF_CloseRead(infile);
429 return 0;
430 }
431
432 /* pass props->head */
433 /* NB does not check for over-range times */
434 /* it also trusts that there is a freq element matching each amp element */
write_partial(FILE * fp,const P_POINT * partial,float sfac,int32_t do_scale)435 int32_t write_partial(FILE *fp,const P_POINT *partial,float sfac,int32_t do_scale)
436 {
437 int32_t length = 0;
438 const P_POINT *head;
439 float scalefac = 32767.0f;
440 short amp,freq,time;
441 short amptag = -1, freqtag = -2;
442 short trackend = 32767;
443
444 if (fp==NULL)
445 return -1;
446 if (partial==NULL)
447 return -1;
448
449 if (do_scale)
450 scalefac *= sfac;
451
452 head = partial;
453 if ((fwrite((char *)&tag,sizeof(short),1,fp)) < 1)
454 return -1;
455
456 /* nothing clever, just go through each list twice */
457
458 /*write amps, scaled to 32767 (oh for a f/p adsyn format...) */
459 while (head) {
460 time = (short)(1000.0f * head->pos);
461 if ((fwrite((char *) &time,sizeof(short),1,fp)) < 1)
462 return -1;
463 amp = (short) (scalefac * head->amp);
464 if ((fwrite((char *)&,sizeof(short),1,fp)) < 1)
465 return -1;
466 length++;
467 head = head->next;
468 }
469 if ((fwrite(&trackend,sizeof(short),1,fp)) < 1)
470 return -1;
471
472 head = partial;
473 if ((fwrite(&freqtag,sizeof(short),1,fp)) < 1)
474 return -1;
475 while(head) {
476 time = (short)(1000.0f * head->pos);
477 if ((fwrite((char *) &time,sizeof(short),1,fp)) < 1)
478 return -1;
479 freq = (short)(head->freq);
480 if ((fwrite(&freq,sizeof(short),1,fp)) < 1)
481 return -1;
482 head = head->next;
483 }
484 if ((fwrite(&trackend,sizeof(short),1,fp)) < 1)
485 return -1;
486 return length;
487 }
488