#!../src/tops  -i -s ../sys  -u ../usr
/*
Program Tops - a stack-based computing environment
Copyright (C) 1999-2008  Dale R. Williamson

Author: Dale R. Williamson <dale.williamson@prodigy.net>

File test/tsnd1  April 2008

References:
   http://www.naturalvoices.att.com/

   The voices for this test were created at this ATT demo site: 
      http://www.research.att.com/~ttsweb/tts/demo.php
      (note: tts = text-to-speech)

Each 16 kHz, 16-bit voice from the demo site was resampled at 8 kHz and
saved as 8-bit data (see below), so the raw bytes drive the sound device
directly just by writing to it as if it were a file.

----------------------------------------------------------------------*/

   catmsg(no);
   if(missing("vmax8")) source("snd.v");

   if(!dsp_ready)
      exit(nl(.(" tsnd1: sound device not found, test skipped")));
<<
   inline: add8 (hA hB --- hC) \ add 8-bit sound A and B to make C
    \ Sat Nov  7 12:20:48 PST 2009

    \ Incoming A and B are type MAT, suitable for math operations.
    \ Returned C is also type MAT.

    \ The range of 8-bit sound values in A and B is from 0 to 255,  
    \ with 128 corresponding to silence.

    \ Make the incoming unsigned values of A and B signed with respect
    \ to zero sound (128), then add them, and then make C unsigned:
    \    C = (A - 128) + (B - 128) + 128 = A + B - 128

    \ It may be necessary to fit C into the range of allowable 8-bit 
    \ sound data (0 to 255); see word vmax8.

      (hA hB) + 128 - (hC)
   end
>>
   file(dsp_ready.DSP, old, binary, "DSP"); // standard sound device
   if(!rows(DSP)) exit(nl(dot("tsnd: error opening " + dsp_ready.DSP)));

   .("tsnd1: is the speaker on?");
   nl();
   .("tsnd1: writing voice bytes to the sound device");

   file(usrpath + "voice/mike", old, binary, "MIKE");
   Mike = uimport1(fget(MIKE, 42000)); // assumes file ge 42000
   close(MIKE);

   file(usrpath + "voice/crystal", old, binary, "CRYSTAL");
   Crystal = uimport1(fget(CRYSTAL, 39000)); // assumes file ge 39000
   close(CRYSTAL);

   .(nl, sp, "Mike talking...");
   fput(export1(Mike), DSP);
   idle(0.25 + rows(Mike)/8000);

   .(nl, sp, "Crystal talking...");
   fput(export1(Crystal), DSP);
   idle(0.25 + rows(Crystal)/8000);

/* Time delay Crystal by about 3/8 second (3000 rows): */
   Crystal = [fill(@Crystal[1], 3000, 1) ; Crystal];

   .(nl, sp, "Mike and Crystal talking at the same time...");
   fput(export1(vmax8(add8(Crystal, Mike))), DSP);
   idle(0.25 + rows(Mike)/8000);

   close(DSP);

   .(nl, "tsnd1: voice test complete");

   nl; nl; nl;

/*----------------------------------------------------------------------

/* This shows resampling two ATT 16 kHz .wav data files to 8 kHz, and
   saving the two files of 8-bit data used in this test: */

   if(missing("wavData")) source("snd.v");
   if(missing("resample")) source("signal.v");
   resample.RMS_SCALE = yes;

/* Load ATT voice mike.wav: */
   (M, H) = wavData("/usr/local/sound/voices/mike.wav");
   if(@H[8] != 16000) HALT(.(" Data is not 16kHz"));
   if(@H[11] != 16) HALT(.(" Data is not 16 bits/sample"));

/* Load ATT voice crystal.wav: */
   (C, H) = wavData("/usr/local/sound/voices/crystal.wav");
   if(@H[8] != 16000) HALT(.(" Data is not 16kHz"));
   if(@H[11] != 16) HALT(.(" Data is not 16 bits/sample"));

/* Resample and save voice mike: */
   A = import2(M, LITTLE_ENDIAN); // import 2-byte data
   A = [A ; fill(@A[rows(A)], 16000, 1)]; // append one second
   R = export1(vmax8(resample(A, 16000, 8000))); // export 1-byte data
   file("/opt/tops/tops/usr/voice/mike", new, binary, "MIKE");
   fclose(fput(R, MIKE), MIKE);

/* Resample and save voice crystal: */
   A = import2(C, LITTLE_ENDIAN); // import 2-byte data
   A = [A ; fill(@A[rows(A)], 16000, 1)]; // append one second
   R = export1(vmax8(resample(A, 16000, 8000))); // export 1-byte data
   file("/opt/tops/tops/usr/voice/crystal", new, binary, "CRYSTAL");
   fclose(fput(R, CRYSTAL), CRYSTAL);

----------------------------------------------------------------------*/
