!----------------------------------------------------------------------------
!   Sound               An Inform 6 library by L. Ross Raszewski to handle
!                       Inform's sound capabilities. Requires sound card.
!                       CAUTION: MAY BEHAVE UNPREDICTABLY ON SOME INTERPRETERS
!
! Most notably, the "Sequencer" option intermittenly crashes Frotz on my
! system rather dramatically.  I'm not sure if it's my interpreter or my
! computer.  At any rate, be careful.  I've had no trouble with the other
! operations, but that's no guarantee.
!
! This system consumes three global variables and one array:
! play_sounds -  If play_sounds=1, sounds will be played, if 0, they will not.
! sound_vol -  a number from 1 to 8, setting the volume
! playing -  A bit array holding three bites used internally. ->0 indicates
!               whether or not PlaySound has been called yet.
!               ->1 indicates the currenly playing sound effect number
!               ->2 is used by internal operations
!
!  This library plays sound effects of the formats described in Stefan
! Jokisch's treatise on Infocom sound formats.  The actual conventions of the
! format are handled by the interpreter, but, and there's a lot more on this in
! the Specification of the Z-Machine, sound_effects 1 and 2 are beeps, and 3
! and up are sound files in an arcane and proprietary format. (There's a beta
! version of SOX that an write to them, however.) Once you have the files where
! your interpreter wants them (usually the "sound" subdirectory), the
! @sound_effect opcode plays these sounds.  However, the nature of
! @sound_effect is such that its use isn't intuative.  Indeed, there's three
! lines of assembly I had to stick in to make it work (liberally stolen from
! Sherlock)  This library makes this useable.
!
! Usage:
! To play a sound:
! PlaySound(sound_number);
! Options:
! PlaySound(sound_number,reps);
!               - plays a sound effect a set number of times
! PlaySound(sound_number,Routine,[option]);
!               - Plays a sound effect, and runs Routine when the effect
!                 has finished.  The third argument is stored in the global
!                 variable sequence.
! Features:
!       If you're using my footnote library, a footnote will be called
!       the first time PlaySound is used.  The number of that footnote
!       should be stored in a constant "SoundNote".  Such a footnote
!       could say something like "Type "SOUND OFF" to disable sounds"
!
!  Routines included:
!       Sequencer:  Call PlaySound(Sequencer,array);.  This will cause
!               each sound effect in the array to be played in order.
!               array->0 MUST be the number of sounds to play, however.
!               Note: This only works about one time in five on my system
!               if anyone could explain why, I'd be much obliged.
!       Repeat and Fade: Call PlaySound(sound_number,RepAndFade); to
!               cause a sound effect to repeat and fade out.
!       Fade In: Call PlaySound(sound_number, FadeIn); and the sound effect
!               will repeat while fading in.
!
!  End-User Functions:
!      Sound    -       Toggles sound on and off
!      Sound On -       Turns sound on
!      Sound Off-       Turns sound off
!      Sound Up -       Turns volume up
!      Sound Down-      Turns volume down
!      Sound (number)-  Sets volume
!
! Debugging Suite:
!       Audio (number)- Plays the corresponding sound effect
!       Audio (2 numbers) Plays the corresponding effect a number of times
!       Audio FIN #  -  Fades in the sound effect
!       Audio RF #   -  Repeats and fades sound effect
!



global play_sounds=1;
global sound_vol=5;
global sequence;
array playing -> 3;
[ PlaySound i Rout k j l;
        if (play_sounds==0) rtrue;
        #IFDEF SoundNote;
        if (playing->0==0) print "^", (Note) SoundNote, "^";
        playing->0=1;
        #ENDIF;
        if (i ofclass Routine) {sequence=Rout; indirect(i); rtrue;};
        if (~~(Rout ofclass Routine)){j=Rout; Rout=0;};
        if (j==0) j=1;
        if (Rout==0) Rout=StopSound;
        l=sound_vol;
        if (Rout==FadeIn) l=1;
        playing->1=i;
        sequence=k;
        @log_shift j 8 sp;
        @or sp l sp;
        @sound_effect i 2 sp Rout;
];
[ StopSound i;
        i=playing->1;
        @sound_effect i 4;
];
[ FadeIn;
        playing->2=1;
        FIner();
];
[ FIner i j;
        playing->2=playing->2+1;
        i=playing->1;
        j=playing->2;
        @log_shift 1 8 sp;
        @or sp j sp;
        if (j<=sound_vol)
                @sound_effect i 2 sp FIner;
];

[ RepAndFade;
        playing->2=sound_vol;
        RnF();
];
[ RnF j i;
        playing->2=playing->2-1;
        i=playing->1;
        j=playing->2;
        @log_shift 1 8 sp;
        @or sp j sp;
        if (j>=1)
                @sound_effect i 2 sp RnF;
];
[ Sequencer;
        playing->2=0;
        SeqNext();
];
[ SeqNext j i k;
        playing->2=playing->2+1;
        j=playing->2;
        if (j>sequence->0) rtrue;
        i=sequence->j;
        @log_shift 1 8 k;
        @or k sound_vol k;
        @sound_effect i 2 k SeqNext;
];

[ SoundToggleSub;
        if (play_sounds==1) <<SoundsOff>>;
        if (play_sounds==0) <<SoundsOn>>;
];
[ SoundVolSub;
        if (noun>8 || noun <=0) "Please specify a volume level between 1 and 8.";
        sound_vol=noun;
        "Sound volume set to ", sound_vol, ".";
];
[ SoundUpSub;
        if (sound_vol==8) "Maximum volume";
        sound_vol++;
        "Sound volume set to ", sound_vol, ".";
];
[ SoundDownSub;
        if (sound_vol==1) "Minimum volume";
        sound_vol--;
        "Sound volume set to ", sound_vol, ".";
];
[ SoundsOnSub;
        play_sounds=1;
        "Sound on.";
];
[ SoundsOffSub;
        play_sounds=0;
        "Sound off.";
];
verb "sound" "sounds" "volume" *                       -> SoundToggle
             * "on"                                    -> SoundsOn
             * "off"                                   -> SoundsOff
             * "up"                                    -> SoundUp
             * "down"                                  -> SoundDown
             * number                                  -> SoundVol;

#IfDef DEBUG;
[ AudioSub;
PlaySound(noun);
];
[ AudioRSub;
PlaySound(noun,RepAndFade);
];
[ AudioFINSub;
PlaySound(noun,FadeIn);
];
[ AudioXRSub;
PlaySound(noun,second);
];

verb "audio" * number                                   ->Audio
             * number number                            ->AudioXR
             * "Fin" number                             ->AudioFIN
             * "RF" number                              ->AudioR;
#ENDIF;
!---------------------------------------------------------------------------
