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,&amp, &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 *)&amptag,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 *)&amp,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