#!/usr/local/bin/tops -s /usr/local/tops/sys -u /opt/mytops/usr/
{
   File tops_snd
   March 2008

   A server to queue and play sound files

   Copyright (C) 2008  Dale R. Williamson

   This script starts a daemon server for playing wave sound files,
   running on SNDSERVER port.  

   When a process plays a sound file while another is playing, this
   message is obtained:
      sox: Can't open output file '/dev/dsp': Device or resource busy
   and the file is simply not played.

   A process can instead submit its sound file to this sound file server
   and it will be queued with others and played when its turn comes.

   Clients obtain the number of SNDSERVER port from message SNDSERVER 
   on the interprocess message file as shown below.  Once connected, 
   say on socket S, rather than running 

      (qFile) wavPlayb,

   to play a file named File, a client submits name File to the sound 
   file server over socket S by running the phrase

      (qFile) " wavque_add" + S remoterun

   The file will be queued and played when its turn comes.

   This shows the interprocess message file with message SNDSERVER 
   among its messages and showing port 9886:
 
      [dale@plunger] /home/dale > cat msgcomm
      RTSERVER 9878
      SNDSERVER 9886
      eCOLLECT SF Sun Mar 30 18:41:01 PDT 2008 1206927661 9415
      eCOLLECT SM Sun Mar 30 18:40:51 PDT 2008 1206927651 9411
      eCOLLECT CL Sun Mar 30 18:41:10 PDT 2008 1206927670 9421
      HIST_ADD BO Sun Mar 30 18:41:21 PDT 2008 1206927681 9425
      HIST_ADD TN Sun Mar 30 18:41:30 PDT 2008 1206927690 9442

   A local client fetches the port from msgcomm using msgPeek (not
   msgGet, which would remove the message):

      "SNDSERVER" msgPeek (qPORT) number drop (nPORT) "PORT" book 

   Word number turns the text into a port number required by word 
   CLIENT.

   The client then connects to the local sound file server PORT using 
   the phrase:

      IPloop PORT CLIENT (nS) "S" book

   and receives socket number S.  

   The client is now ready to send remoterun commands like the follow-
   ing any time it has a wave file to play:

      (qFile) " wavque_add" + S remoterun
}
   ontheweb IF exit THEN \ not for servers on the web

\-----------------------------------------------------------------------

\  Words.

   CATMSG push no catmsg

   "msgPut" missing IF "dog.v" source THEN

   "wavque_play" missing
   IF "snd.v" source
      4 "wavque_play" "NSEC" bank \ override default 2 sec
      1 5 / "wavque_play" "qRATE" bank \ faster rate
      MC1 \ load morse code, not shrill (MC2 is shrill)
   THEN

   inline: CLOSE ( --- ) \ close this daemon
\     This word, run remotely, will close this sound file server daemon.

      "SNDSERVER" msgGet drop \ remove port number from msgcomm
      wavque_clr \ delete queued and played files

      " CLOSE: program will exit in 5 seconds" . nl
      5 idle
      sockets rows 1st DO sockets I pry sclose LOOP \ close all clients
      1 "exit" ALARM
   end

   inline: LOG_SND ( --- qFile) \ name of sound file server log file
      [ "HOME" env "SND.LOG" catpath "log" book ] log
   end

   pull catmsg

\-----------------------------------------------------------------------

   "SNDSERVER" msgGet drop        \ remove old port number

   servershutdown
   def_port nextport "PORT" book 

   PORT intstr "SNDSERVER" msgPut \ put new port number
   wavque_start                   \ start wave file queuing

   keys? 
   IF "*" PORT SERVER halt THEN \ interactive testing halts here

\  SYSOUT must be defined for daemon output.  The following sets SYSOUT
\  to file LOG_SND:
   LOG_SND set_sysout \ log file receives output

\  Write the first lines in LOG_SND:
   "-" 72 cats nl dot nl
   "PID " getpid intstr + spaced date + dot nl

\-----------------------------------------------------------------------

\  Start a daemon server, running forever.
   "*" PORT DSERVER

\-----------------------------------------------------------------------

Using remoteprompt to check on the sound file server.  

The interactive record below shows getting the sound file server port 
number and then connecting to it on an interactive prompt using word 
remoteprompt.

Commands are keyed directly to the sound file server at the tops@socket3
prompt. 

Word clients shows twenty two clients are connected (the 23rd is us at 
socket 26 connected for this interactive remoteprompt session).

Running memcat shows about 3.5 Mb of catalog memory.  Most of this is 
due to Morse Code words from snd.v, which these clients want to run.

Prevously, each client needed to source snd.v, and catalog memory was
about 4.0 Mb.

By using the sound file server, these clients do not need snd.v, and 
their catalog size has dropped to 0.72 Mb.  With 22 clients, memory 
usage has dropped from 88 Mb to 15.8 Mb, a significant saving on this
machine with 128 Mb of ram. 

[tops@plunger] ready > IPloop "SNDSERVER" msgPeek number drop CLIENT

 stack elements:
       0 number: 3
 [1] ok!
[tops@plunger] ready > remoteprompt
tops@socket3 > clients
 Server local is listening on port 9886
 Clients:
  socket 2, port  3295, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 3, port  3264, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 4, port  3275, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 7, port  3300, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 8, port  3305, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 9, port  3307, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 10, port  3312, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 11, port  3314, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 12, port  3316, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 13, port  3321, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 14, port  3334, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 15, port  3348, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 16, port  3350, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 17, port  3352, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 18, port  3354, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 19, port  3356, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 20, port  3362, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 21, port  3367, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 22, port  3373, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 23, port  3375, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 24, port  3380, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 25, port  3382, conn S<C, 127.0.0.1 LOGIN dale plunger
  socket 26, port  3447, conn S<C, 127.0.0.1 LOGIN dale plunger
tops@socket3 > memcat .
 3.4580E+00
tops@socket3 > tasks
 Multitasker tasks:
  wavque_play,0:CODE__ task running at 0.1 Hz; tics remaining 7
tops@socket3 > 
