OS2World OLD-STATIC-BACKUP Forum

OS/2 - SIGs => Rexx => Topic started by: jep on 2008.08.27, 21:11:54

Title: Anatomy of a rexx script, and how to add sound
Post by: jep on 2008.08.27, 21:11:54
Marked as: Normal
Hello,

I've earlier posted some scripts that may be a bit advanced for all to grasp right away. This script has at least two purposes. The first is to show you how to build a rexx script that use logic that can be reused in several situations, and second, a simplified version of play.cmd to play e.g. wav-files.

This simple script use a simple yet efficient configuration file to store information about the file previously played, the default is to play the same file again.

Save the code as anatomy.cmd, open a command line window and type:
set rxtrace=on
to enter rexx debug mode whenever you run a rexx script in that command line window, type:
set rxtrace=off
if you just want to run it and not study it.

Type: anatomy to try it out.

You may also state parameters, see code below and what the script display for more info.

//Jan-Erik

/* Basic structure/anatomy of a rexx script */
/* 1. Place a comment with a good description on the first line of the script such as above */

/* 2. Load libraries you need to perform the task */
/*   a) Either as a single function */
Call RxFuncAdd 'SysCls', 'RexxUtil', 'SysCls'
/*   b) And/or the whole library with all the functions within */
Call RXFUNCADD "mciRxInit", "MCIAPI", "mciRxInit"
Call mciRxInit

/* 3. Prepare constant values to fall back on, as "defaults" */
cfg.path = "C:\MyApps"
cfg.file = "myexample.cfg"
cfg.soundfile = "C:\MMOS2\SOUNDS\applause.wav"
cfg.device = 'WAVEAUDIO'
retval = 1

/* 4. Check system variables, overwrite/override constants depending on how the system look like */
/*   a) If C:\MyApps doesn't exist, try HOME, usually C:\HOME\DEFAULT */
If Directory( cfg.path ) = '' Then
   cfg.path = VALUE( "HOME",, "ENVIRONMENT" )
/*   b) If HOME doesn't exist, try ETC, usually C:\MPTN\ETC */
If Directory( cfg.path ) = '' Then
   cfg.path = VALUE( "ETC",, "ENVIRONMENT" )
/*   c) If ETC doesn't exist, try TEMP, usually C:\var\temp */
If Directory( cfg.path ) = '' Then
   cfg.path = VALUE( "TEMP",, "ENVIRONMENT" )

/* 5. Read from configuration file(s) ( check and validation omitted here ) */
/*    overwrite/override variables, remember settings from previous run */
/*  a) Read, interpret and close file afterward */
Do While Lines( cfg.path||'\'||cfg.file ) > 0
   Interpret LineIn( cfg.path||'\'||cfg.file )
End
Call Stream cfg.path||'\'||cfg.file, "C", "CLOSE"
/*  b) Alternative is to read the EA's or as SysIni, see other examples */


/* 6. Check command line parameters to override varaibles */
/* Check if any parameters are available and optionally show how to use the script */
/* If ARG() = 0 then Return Usage() */
/* The return statement above mean that we leave the current "function" (main) after we've shown Usage */

If ARG() = 0 Then
   Call Usage
Else
Do
   /* This code should run otherwise... */
   Parse Value Translate( ARG(1) ) WITH .'/CFG'temp'/'.
   If Length( temp ) > 0 Then
   Do
      cfg.path = Filespec( 'D', temp )||Filespec( 'P', temp )
      cfg.file = Filespec( 'N', temp )
   End
   Parse Value Translate( ARG(1) ) WITH .'/SND'temp'/'.
   If Length( temp ) > 0 Then
      cfg.soundfile = temp
   Parse Value Translate( ARG(1) ) WITH .'/DEV'temp'/'.
   If Length( temp ) > 0 Then
      cfg.device = temp
End
/* 7. Output information */
Call SysCls
Say 'Ready to play: '||filespec( 'N', cfg.soundfile )

/* 8. Ask for input */
Say 'Press Y to play the file or N to leave, followed by Enter...'
Parse Pull answer

/* 9. Process input */
If Translate( answer ) = 'Y' Then
Do
   retval = mciRxSendString( "open" cfg.soundfile "type" cfg.device "alias rexxalias wait", mciretval, '0', '0' )
   If retval <> 0 Then
      retval = mciRxSendString( "capability rexxalias device type wait", mciretval, '0', '0' )
   else mciretval = cfg.device
   if Translate( mciretval ) = 'WAVEAUDIO' Then
      retval = mciRxSendString( "status rexxalias length wait", mciretval, '0', '0' )      /* If length is 0 no file exists */
   if retval <> 0 then
      retval = mciRxSendString( "close rexxalias wait", mciretval, '0', '0' )
   DeviceID = mciRxGetDeviceID(""rexxalias"")
   retval = mciRxSendString( "play rexxalias wait", mciretval, '0', '0' )
   retval = mciRxSendString( "close rexxalias wait", mciretval, '0', '0' )
End

/* 10. Write configuration file */
Call Stream cfg.path||'\'||cfg.file, "C", "OPEN WRITE"
Call Lineout cfg.path||'\'||cfg.file, "cfg.path='"||cfg.path||"'"
Call Lineout cfg.path||'\'||cfg.file, "cfg.file='"||cfg.file||"'"
Call Lineout cfg.path||'\'||cfg.file, "cfg.soundfile='"||cfg.soundfile||"'"
Call Lineout cfg.path||'\'||cfg.file, "cfg.device='"||cfg.device||"'"
Call Stream cfg.path||'\'||cfg.file, "C", "CLOSE"

/* 11. Return value that indicate if the script succeded or not */
Return retval
/* This is the point where the code exit */

/* 12. Place functions below here that can perform tasks that simplify the coding for you */
Usage:
   Parse Source . . prog'.'.
   Say "Usage: "||Filespec( 'N', prog )||" optional_options"
   Say ""
   Say "Example: "||Filespec( 'N', prog )||" </cfg path_cfg> </snd path_sound> </DEV device_type>"
   Say ""
   Say "Note: All parameters are optional in this specific script!"
Return 1
Title: Re: Anatomy of a rexx script, and how to add sound
Post by: ddan on 2008.08.29, 20:01:05
More excellence from jep. Wish more here would catch on that REXX is fun, besides allows control of your system.

Here's a simpler way (snagged somewhere) to make sounds, which also illustrates calling another script (one that should exist in every OS/2 installation):

/* */
call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs';
call SysLoadFuncs; /* Die notwendige Systemfunktionen */

/* note: original specified "BOING.WAV", which isn't on my English system */
CMDBefehl = "call C:\MMOS2\PLAY.CMD FILE=C:\MMOS2\SOUNDS\BELLS.WAV"

/* OR if you have Dink's Z MP3 player or PM123 specify them: */
/* CMDBefehl = "C:\Z28\Z.EXE C:\MMOS2\SOUNDS\BELLS.WAV" */

CMDBefehl
/* ^^^ this is also a handy way to in essence use it as a named procedure */

exit;
Title: Re: Anatomy of a rexx script, and how to add sound
Post by: RobertM on 2008.08.30, 00:04:57
And for those of you who really want to play, and expanding on ddan's example, you can find the play.cmd script (which is pretty well documented if memory serves) and actually load it into your REXX program and turn it into a "function" in it (which saves on a disk read).

Rob
Title: Re: Anatomy of a rexx script, and how to add sound
Post by: ddan on 2008.08.30, 05:06:30
If not clear, yes I know jep's program is for education; if you JUST want to make sounds, the calls I give are much simpler.

Can't recommend PLAY.CMD for learning, though, unless you wish to become a true weenie. The code uses an alias ("rexxalias") to refer to the wavaudio device, which is unnecessary and confusing. Five years ago, I spent QUITE a while struggling to use bits of it as jep extracted above in my own code, and while I got it to work, it's just simpler to use literals, IF you knew what you were doing and wrote it from scratch.

Related points that may be of interest:
.wav files can be played back with more or less arbitrary rates, allowing time compression. Becomes a bit like a chipmunk if speeded up over 10%, so I never used it except for experiment.

When skipping forward or backward, you need to round the times to nearest second, otherwise it loses synchronization and makes horrible noises.

22KHz stereo .wavs are somewhat limited to 20 mins duration (around 105M file size); longer ones will play, but won't be able to skip around in correctly.

Spooling those files to a RAM drive turns out to require twice the file size of RAM, because the subsystems insists on first making a copy of it before copying to HD.

I still have the horrendous REXX code from that era if anyone is REALLY interested in recording (either manually started or on a timed schedule) and playing .wavs.