1 #include "mrilib.h"
2 
3 static byte mulaw( float x ) ; /* prototype for mu-law conversion */
4 
5 #undef  DEFAULT_SRATE
6 #define DEFAULT_SRATE 16000
7 
8                                /* get specific sound recordings */
9 #include "cs_sounds.h"         /* stored in Audio subdirectory */
10 
11 /*--------------------------------------------------------------------------*/
12 /*---------- find a sound playing program ----------*/
13 
14 static int found_pprog = -1 ;
15 static char *pprog      = NULL ;
16 static char *pprog_name = NULL ;
17 
18 static const int DEBUG = 0 ;
19 
get_sound_player(void)20 char * get_sound_player(void)
21 {
22    if( found_pprog < 0 ){
23      char *eee ;
24      eee = getenv("AFNI_SOUND_PLAYER") ;
25      if( eee != NULL || THD_is_executable(eee) ){
26        pprog = strdup(eee) ;
27      } else {
28          pprog = THD_find_executable("play") ;      /* sox */
29        if( pprog == NULL )
30          pprog = THD_find_executable("afplay") ;    /* OS X */
31        if( pprog == NULL )
32          pprog = THD_find_executable("mplayer") ;   /* Linux or Mac */
33        if( pprog == NULL )
34          pprog = THD_find_executable("aplay") ;     /* Linux */
35      }
36 
37      found_pprog = (pprog != NULL) ;
38      if( found_pprog ) pprog_name = THD_trailname(pprog,0) ;
39 
40      if( DEBUG )
41        INFO_message("get_sound_player: %s",(found_pprog)?pprog:"NULL") ;
42    }
43 
44    return pprog ;
45 }
46 
47 /*--------------------------------------------------------------------------*/
48 static char note_type[32] = "pluck" ;
49 static int  gain_value    = -27 ;
50 static int  two_tone      = 0 ;
51 
set_sound_note_type(char * typ)52 void set_sound_note_type( char *typ )
53 {
54    if( typ == NULL || typ[0] == '\0' ){ strcpy(note_type,"pluck"); return; }
55 
56    if( strncmp(typ,"sine",3)      == 0 ||
57        strncmp(typ,"square",3)    == 0 ||
58        strncmp(typ,"triangle",3)  == 0 ||
59        strncmp(typ,"sawtooth",3)  == 0 ||
60        strncmp(typ,"trapezium",3) == 0 ||
61        strncmp(typ,"pluck",3)     == 0   ){
62 
63      strcpy( note_type , typ ) ;
64    } else {
65      WARNING_message("unknown sox note type '%s'",typ) ;
66    }
67 
68    return ;
69 }
70 
71 /*-----*/
72 
set_sound_gain_value(int ggg)73 void set_sound_gain_value( int ggg )
74 {
75    if( ggg < 0 ) gain_value = ggg ;
76    return ;
77 }
78 
79 /*-----*/
80 
set_sound_twotone(int ggg)81 void set_sound_twotone( int ggg )
82 {
83    two_tone = ggg ; return ;
84 }
85 
86 /*-----*/
87 
88 static int psk_set = 0 ;
89 
90 /*-----*/
91 
92 #if 0
93 #define NFORKLIST 4
94 static int  nfork_pg = 0 ;
95 static int  forklist_pg[NFORKLIST] ;
96 
97 void play_sound_killpg(void){
98   int ii ;
99   for( ii=0 ; ii < NFORKLIST ; ii++ ){
100     if( forklist_pg[ii] > 0 ){
101       killpg(forklist_pg[ii],SIGKILL) ;
102     }
103   }
104   return ;
105 }
106 #endif
107 
108 /*-----*/
109 
110 #if 0
111 static int  nfork_id = 0 ;
112 static int  forklist_id[NFORKLIST] ;
113 
114 void play_sound_killid(void)
115 {
116   int ii ;
117 INFO_message("play_sound_killid()") ;
118   for( ii=0 ; ii < NFORKLIST ; ii++ ){
119     if( forklist_id[ii] > 0 ){
120 ININFO_message("try to kill pid %d",forklist_id[ii]) ;
121       kill(forklist_id[ii],SIGKILL) ;
122       forklist_id[ii] = 0 ;
123     }
124   }
125   nfork_id = 0 ;
126   return ;
127 }
128 #endif
129 
130 /*-----*/
131 
kill_sound_players(void)132 void kill_sound_players(void)
133 {
134   char cmd[1024] ;
135   if( pprog_name != NULL ){
136     sprintf(cmd,"tcsh -c 'killall %s >& /dev/null'",pprog_name) ;
137     system(cmd) ;
138   }
139   return ;
140 }
141 
142 /*---------------------------------------------------------------------------*/
143 
144 static char *play_append = NULL ;
mri_sound_play_append(char * app)145 void mri_sound_play_append( char *app )  /* 09 Aug 2019 */
146 {
147    if( play_append != NULL ){ free(play_append) ; play_append = NULL ; }
148    if( app != NULL && *app != '\0' ) play_append = strdup(app) ;
149    return ;
150 }
151 
152 static int play_notify = 0 ;
mri_play_sound_notify(int nn)153 void mri_play_sound_notify(int nn){ play_notify = nn ; return ; }
154 
155 static float play_rate_fac = 1.0f ;
mri_play_sound_rate_fac(float fff)156 void mri_play_sound_rate_fac( float fff ){
157   if( fff > 0.1f && fff <= 10.0f ) play_rate_fac = fff ;
158 }
159 
160 /*---------------------------------------------------------------------------*/
161 /* Play sound from a 1D image (up to 4 columns) */
162 
mri_play_sound(MRI_IMAGE * imin,int ignore)163 void mri_play_sound( MRI_IMAGE *imin , int ignore )
164 {
165    MRI_IMAGE *qim ;
166    char *pre , fname[256] , cmd[2048] , extras[1024] ;
167    int ii , nsper ; float dt ;
168 
169    (void)get_sound_player() ;
170    if( imin == NULL || imin->nx < 2 || pprog == NULL ) return ;
171 
172    kill_sound_players() ;
173 
174    if( !psk_set ){ atexit(kill_sound_players) ; psk_set = 1 ; }
175 
176    ii = (int)fork() ;
177    if( ii != 0 ){  /*-- return to parent process --*/
178 #if 0
179      int jj = getpgid(ii) ;
180      if( nfork_pg == 0 || (nfork_pg > 0 && jj != forklist_pg[nfork_pg-1]) ){
181        forklist_pg[nfork_pg] = getpgid(ii) ;
182        nfork_pg              = (nfork_pg+1)%NFORKLIST ;
183      }
184 #endif
185 #if 0
186      jj = ii ;
187      if( nfork_id == 0 || (nfork_id > 0 && jj != forklist_id[nfork_id-1]) ){
188        forklist_id[nfork_id] = jj ;
189        nfork_id              = (nfork_id+1)%NFORKLIST ;
190      }
191 #endif
192      return ;
193    }
194 
195    dt = (imin->nx <= 100) ? 0.20f : 0.14f + 6.0f/(float)imin->nx ;
196    dt *= play_rate_fac ;
197    nsper = (int)rintf(DEFAULT_SRATE*dt) ;
198 
199    qim = mri_sound_1D_to_notes( imin , DEFAULT_SRATE , nsper , 4 , ignore , 0 ) ;
200    if( qim == NULL ) _exit(0) ;
201 
202    pre = UNIQ_idcode_11() ;  /* make up name for sound file */
203    sprintf(fname,"AFNI_SOUND_TEMP.%s.au",pre) ;
204    unlink(fname) ;           /* remove sound file, in case it already exists */
205    if( DEBUG ) ININFO_message("  temp sound filename = %s",fname) ;
206    if( play_notify )
207      ININFO_message("  writing temp sound file: %s",fname) ;
208    sound_write_au_16PCM( fname, qim->nx, MRI_FLOAT_PTR(qim), DEFAULT_SRATE, 0.1f ) ;
209    extras[0] = '\0' ;
210    if( strcmp(pprog_name,"play") == 0 ){
211      strcat(extras," reverb 44 ") ;
212      if( play_append != NULL ) strcat(extras,play_append) ;
213    }
214    sprintf(cmd,"tcsh -c '%s %s %s >& /dev/null'",pprog,fname,extras) ;
215    if( DEBUG ) ININFO_message("%s",cmd) ;
216    if( play_notify )
217      ININFO_message("  starting sound player: %s",cmd) ;
218    system(cmd) ;
219    sleep(1);
220    unlink(fname) ;
221    _exit(0) ;
222 }
223 
224 /*---------------------------------------------------------------------------*/
225 /*-------- convert value in range -1..1 into 8 bit code via 'mu-law' --------*/
226 
mulaw(float x)227 static INLINE byte mulaw( float x )
228 {
229    short sx ; byte bx ;
230    int   sr , im ;
231    short is , imag, iesp, ofst, ofst1 , sp ;
232 
233         if( x < -1.0f ) x = -1.0f ;
234    else if( x >  1.0f ) x =  1.0f ;
235 
236    sx = (short)rintf(8158.0f * x) ;
237 
238    is = sx >> 15 ;
239    sr = (sx & 65535) ;
240    im = (is==0) ? sr : (65536-sr)&32767 ;
241 
242    imag = im ; if( imag > 8158 ) imag = 8158 ;
243    ++imag;
244    iesp = 0;
245    ofst = 31;
246 
247    if( imag > ofst ){
248      for( iesp = 1 ; iesp <= 8 ; ++iesp){
249        ofst1 = ofst ;
250        ofst += (1 << (iesp + 5)) ;
251        if (imag <= ofst) break ;
252      }
253      imag -= ofst1 + 1 ;
254    }
255 
256    imag /= (1 << (iesp + 1)) ;
257 
258    sp = (is == 0) ? (imag + (iesp << 4)) : (imag + (iesp << 4) + 128) ;
259 
260    sp ^= 128 ; sp ^= 127 ;
261 
262    bx = (byte)sp ; return bx ;
263 }
264 
265 /*---------------------------------------------------------------------------*/
266 
267 static int little_endian = -66 ;
268 
set_little_endian(void)269 static INLINE void set_little_endian(void)
270 {
271    union { unsigned char bb[2] ;
272            short         ss    ; } fred ;
273 
274    if( little_endian < 0 ){
275      fred.bb[0] = 1 ; fred.bb[1] = 0 ;
276      little_endian = (fred.ss == 1) ;
277    }
278    return ;
279 }
280 
281 /*---------------------------------------------------------------------------*/
282 
283 typedef struct { unsigned char a,b,c,d ; } fourby ;
284 
swap_fourby(uint32_t ii)285 static uint32_t INLINE swap_fourby( uint32_t ii )
286 {
287    union { uint32_t qq ; fourby ff ; } qf ;
288    unsigned char tt ;
289 
290    qf.qq   = ii ;
291    tt      = qf.ff.a ;
292    qf.ff.a = qf.ff.d ;
293    qf.ff.d = tt ;
294    tt      = qf.ff.b ;
295    qf.ff.b = qf.ff.c ;
296    qf.ff.c = tt ;
297    return qf.qq ;
298 }
299 
300 typedef struct { unsigned char a,b ; } twoby ;
301 
swap_twobyar(int n,void * ar)302 static void swap_twobyar( int n , void *ar )
303 {
304    int ii ;
305    twoby *tb = (twoby *)ar ;
306    unsigned char tt ;
307 
308    for( ii=0 ; ii < n ; ii++ ){
309      tt       = tb[ii].a ;
310      tb[ii].a = tb[ii].b ;
311      tb[ii].b = tt ;
312    }
313    return ;
314 }
315 
316 /*---------------------------------------------------------------------------*/
317 
sound_write_au_header(FILE * fp,int nn,int srate,int code)318 void sound_write_au_header( FILE *fp , int nn , int srate , int code )
319 {
320    uint32_t ival ;
321 
322    set_little_endian() ;  /* do we need to swap bytes in header output? */
323 
324    fwrite( ".snd" , 1 , 4, fp ) ;                 /*----- magic 'number' -----*/
325 
326    ival = 32    ; if( little_endian ) ival = swap_fourby(ival) ;
327    fwrite( &ival  , 1 , 4 , fp ) ;                /*----- offset to data -----*/
328 
329    ival = nn    ; if( little_endian ) ival = swap_fourby(ival) ;
330    fwrite( &ival  , 1 , 4 , fp ) ;          /*----- number of data bytes -----*/
331 
332    ival =  code ; if( little_endian ) ival = swap_fourby(ival) ;
333    fwrite( &ival  , 1 , 4 , fp ) ;                      /*----- encoding -----*/
334 
335    ival = srate ; if( little_endian ) ival = swap_fourby(ival) ;
336    fwrite( &ival  , 1 , 4 , fp ) ;            /*----- samples per second -----*/
337 
338    ival =  1    ; if( little_endian ) ival = swap_fourby(ival) ;
339    fwrite( &ival  , 1 , 4 , fp ) ;            /*----- number of channels -----*/
340 
341    fwrite( "AFNI.au"  , 1 , 8 , fp ) ;     /*----- 8 bytes of annotation -----*/
342 
343    return ;
344 }
345 
346 /*---------------------------------------------------------------------------*/
347 /* samples in aa[] are between -1 and 1.
348    sample rate (per second) is in srate.
349    scl is a scale down factor (0 < scl <= 1).
350 *//*-------------------------------------------------------------------------*/
351 
sound_write_au_ulaw(char * fname,int nn,float * aa,int srate,float scl)352 void sound_write_au_ulaw( char *fname, int nn, float *aa, int srate, float scl )
353 {
354    FILE *fp ;
355    uint32_t ival , jval ;
356    byte *bb ;
357    int ii ;
358 
359    /* check inputs */
360 
361    if( fname == NULL || nn < 2 || aa == NULL ){
362      ERROR_message("Illegal inputs to sound_write_au :(") ;
363      return ;
364    }
365 
366    if( srate < 8000 ) srate = DEFAULT_SRATE ;
367    if( scl   < 0.0f || scl > 1.0f ) scl = 1.0f ;
368 
369    /* open output file */
370 
371    fp = fopen( fname , "w" ) ;
372    if( fp == NULL ){
373      ERROR_message("Can't open audio output file '%s'",fname) ;
374      return ;
375    }
376 
377    /* write .au file header */
378 
379    sound_write_au_header( fp , nn , srate , 1 ) ;
380 
381    /* convert and write data */
382 
383    bb = (byte *)malloc(sizeof(byte)*nn) ;
384    for( ii=0 ; ii < nn ; ii++ ) bb[ii] = mulaw(scl*aa[ii]) ;
385    fwrite( bb , 1 , nn , fp ) ;
386 
387    /* done done done */
388 
389    fclose(fp) ;
390    free(bb) ;
391    return ;
392 }
393 
394 /*---------------------------------------------------------------------------*/
395 /* samples in aa[] are between -1 and 1.
396    sample rate (per second) is in srate.
397    scl is a scale down factor (0 < scl <= 1).
398 *//*-------------------------------------------------------------------------*/
399 
sound_write_au_8PCM(char * fname,int nn,float * aa,int srate,float scl)400 void sound_write_au_8PCM( char *fname, int nn, float *aa, int srate, float scl )
401 {
402    FILE *fp ;
403    uint32_t ival , jval ;
404    int8_t *bb ;
405    int ii ; float fac , val ;
406 
407    /* check inputs */
408 
409    if( fname == NULL || nn < 2 || aa == NULL ){
410      ERROR_message("Illegal inputs to sound_write_au :(") ;
411      return ;
412    }
413 
414    if( srate < 8000 ) srate = DEFAULT_SRATE ;
415    if( scl   < 0.0f || scl > 1.0f ) scl = 1.0f ;
416 
417    /* open output file */
418 
419    fp = fopen( fname , "w" ) ;
420    if( fp == NULL ){
421      ERROR_message("Can't open audio output file '%s'",fname) ;
422      return ;
423    }
424 
425    /* write .au file header */
426 
427    sound_write_au_header( fp , nn , srate , 2 ) ;
428 
429    /* convert and write data */
430 
431    bb  = (int8_t *)malloc(sizeof(int8_t)*nn) ;
432    fac = 127.444f * scl ;
433    for( ii=0 ; ii < nn ; ii++ ){
434      val = fac*aa[ii] ;
435      bb[ii] = ( val < -127.0f ) ? -127 :
436               ( val >  127.0f ) ?  127 : (int8_t)rintf(val) ;
437    }
438    fwrite( bb , 1 , nn , fp ) ;
439 
440    /* done done done */
441 
442    fclose(fp) ;
443    free(bb) ;
444    return ;
445 }
446 
447 /*---------------------------------------------------------------------------*/
448 /* samples in aa[] are between -1 and 1.
449    sample rate (per second) is in srate.
450    scl is a scale down factor (0 < scl <= 1).
451 *//*-------------------------------------------------------------------------*/
452 
sound_write_au_16PCM(char * fname,int nn,float * aa,int srate,float scl)453 void sound_write_au_16PCM( char *fname, int nn, float *aa, int srate, float scl )
454 {
455    FILE *fp ;
456    uint32_t ival , jval ;
457    int16_t *bb ;
458    int ii ; float fac , val ;
459 
460    /* check inputs */
461 
462    if( fname == NULL || nn < 2 || aa == NULL ){
463      ERROR_message("Illegal inputs to sound_write_au :(") ;
464      return ;
465    }
466 
467    if( srate < 8000 ) srate = DEFAULT_SRATE ;
468    if( scl   < 0.0f || scl > 1.0f ) scl = 1.0f ;
469 
470    /* open output file */
471 
472    fp = fopen( fname , "w" ) ;
473    if( fp == NULL ){
474      ERROR_message("Can't open audio output file '%s'",fname) ;
475      return ;
476    }
477 
478    /* write .au file header */
479 
480    sound_write_au_header( fp , 2*nn , srate , 3 ) ;
481 
482    /* convert and write data */
483 
484    bb  = (int16_t *)malloc(sizeof(int16_t)*nn) ;
485    fac = 32767.444f * scl ;
486    for( ii=0 ; ii < nn ; ii++ ){
487      val = fac*aa[ii] ;
488      bb[ii] = ( val < -32767.0f ) ? -32767 :
489               ( val >  32767.0f ) ?  32767 : (int16_t)rintf(val) ;
490    }
491    if( little_endian ) swap_twobyar( nn , bb ) ;
492 
493    fwrite( bb , 2 , nn , fp ) ;
494 
495    /* done done done */
496 
497    fclose(fp) ;
498    free(bb) ;
499    return ;
500 }
501 
502 /*---------------------------------------------------------------------------*/
503 
504 #undef  A4
505 #define A4 440.0  /* Hz */
506 
mri_sound_1D_to_FM(MRI_IMAGE * imin,float fbot,float ftop,int srate,int nsper)507 MRI_IMAGE * mri_sound_1D_to_FM( MRI_IMAGE *imin ,
508                                 float fbot , float ftop ,
509                                 int srate , int nsper    )
510 {
511    float *aa,*bb ;
512    float abot,atop , lfbot,lftop,dlf,dfac,ai,ap,di,dp ;
513    float afac,dph,ph , val ;
514    int nout , ii,jj,kk,ip , nn ;
515    MRI_IMAGE *imout , *qim ;
516 
517    if( imin == NULL ) return NULL ;
518 
519    nn = imin->nx ;
520    if( nn < 2 ){
521      ERROR_message("mri_sound_1D_to_FM: nn = %d",nn) ;
522      return NULL ;
523    }
524 
525    if( imin->kind != MRI_float ){
526      qim = mri_to_float(imin) ;
527    } else {
528      qim = imin ;
529    }
530    aa = MRI_FLOAT_PTR(qim) ;
531 
532    if( fbot <= 0.0f || fbot >= ftop ){
533      fbot = 0.25f * A4 ; ftop = 4.0f * A4 ;
534    }
535    if( ftop > 10000.0f ) ftop = 10000.0f ;
536    if( fbot <    30.0f ) fbot =    30.0f ;
537 
538    if( srate < 8000 ) srate = DEFAULT_SRATE ;
539    if( nsper <= 0   ) nsper = 1 ;
540 
541    /* will scale so abot..atop = log(fbot)..log(ftop) */
542 
543    abot = atop = aa[0] ;
544    for( ii=1 ; ii < nn ; ii++ ){
545            if( aa[ii] < abot ) abot = aa[ii] ;
546       else if( aa[ii] > atop ) atop = aa[ii] ;
547    }
548 
549    nout  = nsper * nn ;
550    imout = mri_new( nout , 1 , MRI_float ) ;
551    bb    = MRI_FLOAT_PTR(imout) ;
552 
553    if( abot >= atop ){
554      float fmid = sqrtf(fbot*ftop) ;
555      INFO_message("mri_sound_1D_to_FM: only 1 value == sine wave output f=%.1g",fmid) ;
556      ph  = 0.0f ;
557      dph = 2.0f * PI * fmid / srate ;
558      for( ii=0 ; ii < nout ; ii++ ){
559        bb[ii] = sin(ph) ; ph += dph ;
560      }
561      if( qim != imin ) mri_free(qim) ;
562      return imout ;
563    }
564 
565    lfbot = log2(fbot) ; lftop = log2(ftop) ; dlf = lftop-lfbot ;
566 
567    dfac = 1.0f / nsper ;
568    afac = dlf  / (atop-abot) ;
569 
570 #undef  FRMOD
571 #define FRMOD(x) exp2f( lfbot + afac*((x)-abot) )
572 
573    ph  = 0.0f ;
574    dph = 2.0f * PI / srate ;
575    for( jj=ii=0 ; ii < nn ; ii++ ){
576      ph += FRMOD(aa[ii]) * dph ; bb[jj++] = sin(ph) ;
577 #if 0
578 val = FRMOD(aa[ii]) ;
579 ININFO_message(" %g  %g",val,bb[jj-1]) ;
580 #endif
581      if( nsper > 1 ){
582        ip = ii+1 ; if( ip >= nn ) ip = nn-1 ;
583        ai = aa[ii] ; ap = aa[ip] ;
584        di = 1.0f   ; dp = 0.0f   ;
585        for( kk=1 ; kk < nsper ; kk++ ){
586          di -= dfac ; dp += dfac ;
587          ph += FRMOD( di*ai+dp*ap ) * dph ; bb[jj++] = sin(ph) ;
588 #if 0
589 val = FRMOD( di*ai+dp*ap ) ;
590 ININFO_message(" %g  %g",val,bb[jj-1]) ;
591 #endif
592        }
593      }
594    }
595 
596 #undef FRMOD
597 
598    if( qim != imin ) mri_free(qim) ;
599    return imout ;
600 }
601 
602 #undef A4
603 
604 /*---------------------------------------------------------------------------*/
605 
606 #define PA 54.0f  /* 5 base notes (Hz) */
607 #define PC 64.0f
608 #define PD 72.0f
609 #define PE 81.0f
610 #define PG 96.0f
611 
612 #define POCTA 4   /* number of octaves */
613 
614 static int   npenta = 0 ;     /* will be 5*POCTA+1 */
615 static float *penta = NULL ;  /* will hold all the notes */
616 
sound_setup_penta(int octstart)617 void sound_setup_penta( int octstart )
618 {
619    int ii , jj ; float fac ;
620 
621    if( npenta > 0 ) return ;
622    if( octstart < 0 || octstart >= POCTA ) octstart = 0 ;
623 
624    npenta = 5*POCTA+1 ;
625     penta = (float *)malloc(sizeof(float)*npenta) ;
626    fac    = 1.0f ;
627 
628    for( jj=ii=0 ; ii < POCTA ; ii++ ){
629      if( ii >= octstart ){
630        penta[jj++] = fac * PA ;
631        penta[jj++] = fac * PC ;
632        penta[jj++] = fac * PD ;
633        penta[jj++] = fac * PE ;
634        penta[jj++] = fac * PG ;
635      }
636      fac *= 2.0f ;
637    }
638    penta[jj++] = fac * PA ; /* complete last octave */
639    npenta      = jj ;
640 
641    return ;
642 }
643 
644 /*---------------------------------------------------------------------------*/
645 
646 static int note_waveform = SOUND_WAVEFORM_TRIANGLE ;
647 
sound_set_note_waveform(int nn)648 void sound_set_note_waveform( int nn ){ note_waveform = nn; }
649 
650 #undef  twoPI
651 #define twoPI   6.283185f
652 #undef  fourPI
653 #define fourPI 12.566371f
654 #undef  sixPI
655 #define sixPI  18.849556f
656 
657 /* wav_xxx functions have period 1, amplitude 1, and assume t > 0 */
658 
wav_sine(float t)659 static INLINE float wav_sine(float t){ return ( 0.999f*sinf(twoPI*t) ) ; }
660 
wav_h2sine(float t)661 static INLINE float wav_h2sine(float t){
662   return ( 0.953f*sinf(twoPI*t)+0.3f*cosf(fourPI*t) ) ;
663 }
664 
wav_sqsine(float t)665 static INLINE float wav_sqsine(float t){
666   float val = sinf(twoPI*t) , aval ;
667 #if 1
668   aval = sqrtf(fabsf(val)) ;
669 #else
670   aval = powf( fabsf(val) , 0.6f ) ;
671 #endif
672   return ( (val >= 0.0f ) ?  aval : -aval ) ;
673 }
674 
wav_square(float t)675 static INLINE float wav_square(float t){
676   float dt = fmodf(t,1.0f) ;
677   return ( (dt < 0.45f) ? 0.999f
678           :(dt < 0.55f) ? 0.999f-19.98f*(dt-0.45f)
679           : -0.999f ) ;
680 }
681 
682 #undef  TW
683 #define TW(x) (0.999f-3.996f*fabsf(x))
684 
wav_triangle(float t)685 static INLINE float wav_triangle(float t){
686   float dt = fmodf(t,1.0f) ;
687   return ( (dt < 0.5f) ? TW(dt-0.25f) : -TW(dt-0.75f) ) ;
688 }
689 
690 #undef  envA
691 #undef  envD
692 #undef  envS
693 #define envA 0.0666f
694 #define envD 0.1666f
695 #define envS 0.9333f
696 
697 /* Envelope for note, with 0 <= t <= 1 */
698 
ADSR_env(float t)699 static INLINE float ADSR_env(float t){
700        if( t <= envA ) return (0.07f+0.93f*t/envA) ;
701   else if( t <= envD ) return (1.0f-0.1f*(t-envD)/(envD-envA)) ;
702   else if( t <= envS ) return (0.9f) ;
703                        return (0.9f-0.83f*(t-envS)/(1.0f-envS)) ;
704 }
705 
706 static int use_ADSR = 1 ;
707 
sound_set_note_ADSR(int qq)708 void sound_set_note_ADSR(int qq){ use_ADSR = qq ; }
709 
710 /*---------------------------------------------------------------------------*/
711 /* Note that if frq >= 0.5*srate, bad things will happen due to Mr Nyquist!! */
712 /*---------------------------------------------------------------------------*/
713 
714 static float ttn = 0.0f ;  /* continuous time between notes */
715 
reset_note_ttn(void)716 static void reset_note_ttn(void){ ttn = 0.0f ; }
717 
sound_make_note(float frq,int waveform,int srate,int nsam,float * sam)718 void sound_make_note( float frq, int waveform, int srate, int nsam, float *sam )
719 {
720    int ii ; float dt,tt ;
721 
722    if( frq <= 0.0f || nsam < 9 || sam == NULL ) return ;
723 
724    if( srate < 8000 ) srate = DEFAULT_SRATE ;
725 
726    dt = frq / srate ; tt = ttn ;
727 
728    /* form periodic waveform */
729 
730    switch( waveform ){
731 
732      default:
733      case SOUND_WAVEFORM_SINE:
734        for( ii=0 ; ii < nsam ; ii++ ){ sam[ii] = wav_sine(tt); tt += dt; }
735      break ;
736 
737      case SOUND_WAVEFORM_SQUARE:
738        for( ii=0 ; ii < nsam ; ii++ ){ sam[ii] = wav_square(tt); tt += dt; }
739      break ;
740 
741      case SOUND_WAVEFORM_TRIANGLE:
742        for( ii=0 ; ii < nsam ; ii++ ){ sam[ii] = wav_triangle(tt); tt += dt; }
743      break ;
744 
745      case SOUND_WAVEFORM_H2SINE:
746        for( ii=0 ; ii < nsam ; ii++ ){ sam[ii] = wav_h2sine(tt); tt += dt; }
747      break ;
748 
749      case SOUND_WAVEFORM_SQSINE:
750        for( ii=0 ; ii < nsam ; ii++ ){ sam[ii] = wav_sqsine(tt); tt += dt; }
751      break ;
752 
753    }
754 
755    ttn = tt ;  /* continuous time between notes */
756 
757    /* apply envelope (if note has enough samples) */
758 
759    if( nsam > 127 && use_ADSR ){
760      dt = 1.0f/nsam ; tt= 0.0f ;
761      for( ii=0 ; ii < nsam ; ii++ ){ sam[ii] *= ADSR_env(tt); tt += dt; }
762    } else if( nsam > 24 ){
763 #if 0
764      float fac ;
765      for( ii=0 ; ii < 9 ; ii++ ){
766        fac = (ii+1)*0.1f ; sam[ii] *= fac ; sam[nsam-1-ii] *= fac ;
767      }
768 #endif
769    }
770 
771    return ;
772 }
773 
774 /*---------------------------------------------------------------------------*/
775 
776 #define VAL_TO_CODE(v) ((int)rintf((v)-SOUND_WAVECODE_BASE))
777 
mri_sound_1D_to_notes(MRI_IMAGE * imin,int srate,int nsper,int ny,int ignore,int use_wavecodes)778 MRI_IMAGE * mri_sound_1D_to_notes( MRI_IMAGE *imin, int srate, int nsper,
779                                    int ny, int ignore, int use_wavecodes )
780 {
781    float *aa,*bb,*qa ;
782    float abot,atop , fac , *valn ;
783    int nout , ii,jj , nn , qq ;
784    MRI_IMAGE *imout , *qim ;
785    int max_wavecode=0 ;
786    int ncode=0 , nsamcode=0 ;
787 
788    /*--- deal with inputs ---*/
789 
790    if( imin == NULL ) return NULL ;
791 
792    nn = imin->nx ;
793    if( nn < 2 ){
794      ERROR_message("mri_sound_1D_to_notes: nn = %d",nn) ;
795      return NULL ;
796    }
797 
798    if( ignore < 0 || nn-ignore < 2 ) ignore = 0 ;
799 
800    if( imin->kind != MRI_float ){
801      qim = mri_to_float(imin) ;
802    } else {
803      qim = imin ;
804    }
805    aa = MRI_FLOAT_PTR(qim) ;
806 
807         if( ny <= 0       ) ny = 1 ;
808    else if( ny >  qim->ny ) ny = qim->ny ;
809 
810    if( srate < 8000 ) srate = DEFAULT_SRATE ;
811    if( nsper <= 9   ) nsper = srate/2 ;
812 
813    /*-- check for wavecodes embedded in the data --*/
814 
815    if( use_wavecodes ){
816      max_wavecode  = get_num_sound_waveforms() ;
817      use_wavecodes = max_wavecode > 0 ;
818    }
819 
820    if( use_wavecodes ){
821    }
822 
823    /*-- create output ---*/
824 
825    nout  = nsper * (nn-ignore) ;
826    imout = mri_new( nout , 1 , MRI_float ) ;
827    bb    = MRI_FLOAT_PTR(imout) ;  /* is full of zeros */
828 
829    sound_setup_penta(1) ; /* skip octave 0 -- it's too low */
830 
831    valn = (float *)malloc(sizeof(float)*nsper) ; /* notes */
832 
833    for( qq=0 ; qq < ny ; qq++ ){  /* process first ny columns */
834      qa = aa + (nn*qq) ;          /* add their sounds all up */
835      abot = atop = qa[ignore] ;
836      reset_note_ttn() ;           /* re-start time at 0 */
837      for( ii=ignore+1 ; ii < nn ; ii++ ){
838              if( qa[ii] < abot ) abot = qa[ii] ;
839         else if( qa[ii] > atop ) atop = qa[ii] ;
840      }
841 
842      if( abot < atop ){ /* some range to the numbers */
843        fac = (npenta-1.0f) / (atop-abot) ;
844        for( ii=ignore ; ii < nn ; ii++ ){
845          jj = rintf( fac*(qa[ii]-abot) ) ;
846          sound_make_note( penta[jj], note_waveform, srate, nsper, valn ) ;
847          for( jj=0 ; jj < nsper ; jj++ ) bb[((ii-ignore)*nsper)+jj] += valn[jj];
848        }
849      }
850    }
851 
852    abot = mri_maxabs(imout) ;
853    if( abot == 0.0f ){  /* nothing computed? do something random! */
854      for( ii=ignore ; ii < nn ; ii++ ){
855        jj = lrand48() % npenta ;
856        sound_make_note( penta[jj], note_waveform,
857                         srate, nsper, bb+((ii-ignore)*nsper) ) ;
858      }
859    }
860 
861    THD_normmax( nout , bb ) ;  /* max abs value = 1 */
862 
863    free(valn) ;
864    if( qim != imin ) mri_free(qim) ;
865 
866    return imout ;
867 }
868