#!../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.

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

   if(!fallow("/dev/dsp"))
      exit(nl(.(" tsnd1: sound device not found, test skipped")));

   catmsg(no);

   function (B) = vmax8(A) { // scale A to max 8-bit sound level
      { AMP = 255; } // amplitude max for 8-bit sound
      (Amin, r, c) = minfetch(A);
      (Bmax, r, c) = maxfetch((B = (A + abs(Amin))));
      B = B*(AMP/Bmax);
   }

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

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

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

   open("/dev/dsp", old, binary, "DSP"); // standard sound device

/*
   .(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];

/* Some background: */
   open(usrpath + "voice/endoftheworld", old, binary, "BG");
   Background = uimport1(fget(BG, INF))[110000:=42000]; 
   close(BG);
   
   .(nl, sp, "Mike and Crystal talking at the same time...");
   fput(export1(vmax8(Crystal + Mike + Background/2)), 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;
<<
\  This postfix function gives the same result as the newer infix 
\  function above:
   inline: vmax8 (hA --- hB) \ scale A to max 8-bit sound level
\     A and B are MATs.
      [ 255 "AMP" book ] \ amplitude max for 8-bit sound
      (hA) dup minfetch 2drop abs + \ make A unsigned
      (hA) AMP over maxfetch 2drop / * (hB)
   end
>>
/* 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);

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