Update Andrew Plotkin's unit tests
[projects/chimara/chimara.git] / interpreters / frotz / sound.c
1 /* sound.c - Sound effect function
2  *      Copyright (c) 1995-1997 Stefan Jokisch
3  *
4  * This file is part of Frotz.
5  *
6  * Frotz is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Frotz is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "frotz.h"
22
23 #ifdef DJGPP
24 #include "djfrotz.h"
25 #endif
26
27 #define EFFECT_PREPARE 1
28 #define EFFECT_PLAY 2
29 #define EFFECT_STOP 3
30 #define EFFECT_FINISH_WITH 4
31
32 extern int direct_call (zword);
33
34 static int next_sample = 0;
35 static int next_volume = 0;
36
37 static bool locked = FALSE;
38 static bool playing = FALSE;
39
40 /*
41  * init_sound
42  *
43  * Initialize sound variables.
44  *
45  */
46
47 void init_sound (void)
48 {
49     locked = FALSE;
50     playing = FALSE;
51 } /* init_sound */
52
53
54 /*
55  * start_sample
56  *
57  * Call the IO interface to play a sample.
58  *
59  */
60
61 static void start_sample (int number, int volume, int repeats, zword eos)
62 {
63
64     static zbyte lh_repeats[] = {
65         0x00, 0x00, 0x00, 0x01, 0xff,
66         0x00, 0x01, 0x01, 0x01, 0x01,
67         0xff, 0x01, 0x01, 0xff, 0x00,
68         0xff, 0xff, 0xff, 0xff, 0xff
69     };
70
71     if (story_id == LURKING_HORROR)
72         repeats = lh_repeats[number];
73
74     os_start_sample (number, volume, repeats, eos);
75
76     playing = TRUE;
77
78 }/* start_sample */
79
80 /*
81  * start_next_sample
82  *
83  * Play a sample that has been delayed until the previous sound effect has
84  * finished.  This is necessary for two samples in The Lurking Horror that
85  * immediately follow other samples.
86  *
87  */
88
89 static void start_next_sample (void)
90 {
91
92     if (next_sample != 0)
93         start_sample (next_sample, next_volume, 0, 0);
94
95     next_sample = 0;
96     next_volume = 0;
97
98 }/* start_next_sample */
99
100 /*
101  * end_of_sound
102  *
103  * Call the Z-code routine which was given as the last parameter of
104  * a sound_effect call. This function may be called from a hardware
105  * interrupt (which requires extremely careful programming).
106  *
107  */
108
109 void end_of_sound (zword routine)
110 {
111
112 #if defined(DJGPP) && defined(SOUND_SUPPORT)
113     end_of_sound_flag = 0;
114 #endif
115
116     playing = FALSE;
117
118     if (!locked) {
119
120         if (story_id == LURKING_HORROR)
121             start_next_sample ();
122
123         direct_call (routine);
124
125     }
126
127 }/* end_of_sound */
128
129 /*
130  * z_sound_effect, load / play / stop / discard a sound effect.
131  *
132  *      zargs[0] = number of bleep (1 or 2) or sample
133  *      zargs[1] = operation to perform (samples only)
134  *      zargs[2] = repeats and volume (play sample only)
135  *      zargs[3] = end-of-sound routine (play sample only, optional)
136  *
137  * Note: Volumes range from 1 to 8, volume 255 is the default volume.
138  *       Repeats are stored in the high byte, 255 is infinite loop.
139  *
140  */
141
142 void z_sound_effect (void)
143 {
144     zword number = zargs[0];
145     zword effect = zargs[1];
146     zword volume = zargs[2];
147
148     if (zargc < 1)
149         number = 0;
150     if (zargc < 2)
151         effect = EFFECT_PLAY;
152     if (zargc < 3)
153         volume = 8;
154
155     if (number >= 3 || number == 0) {
156
157         locked = TRUE;
158
159         if (story_id == LURKING_HORROR && (number == 9 || number == 16)) {
160
161             if (effect == EFFECT_PLAY) {
162
163                 next_sample = number;
164                 next_volume = volume;
165
166                 locked = FALSE;
167
168                 if (!playing)
169                     start_next_sample ();
170
171             } else locked = FALSE;
172
173             return;
174
175         }
176
177         playing = FALSE;
178
179         switch (effect) {
180
181         case EFFECT_PREPARE:
182             os_prepare_sample (number);
183             break;
184         case EFFECT_PLAY:
185             start_sample (number, lo (volume), hi (volume), (zargc == 4) ? zargs[3] : 0);
186             break;
187         case EFFECT_STOP:
188             os_stop_sample (number);
189             break;
190         case EFFECT_FINISH_WITH:
191             os_finish_with_sample (number);
192             break;
193
194         }
195
196         locked = FALSE;
197
198     } else os_beep (number);
199
200 }/* z_sound_effect */