1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: snd_allegromusic.cpp 3866 2008-11-17 18:58:49Z dj_jl $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include <allegro.h>
29 #include "gamedefs.h"
30 #include "snd_local.h"
31
32 // MACROS ------------------------------------------------------------------
33
34 // TYPES -------------------------------------------------------------------
35
36 class VAllegroMidiDevice : public VMidiDevice
37 {
38 public:
39 bool DidInitAllegro;
40 MIDI mididata;
41 bool midi_locked;
42
43 void* Mus_SndPtr;
44 bool MusicPaused;
45 float MusVolume;
46
47 VAllegroMidiDevice();
48 void Init();
49 void Shutdown();
50 void SetVolume(float);
51 void Tick(float);
52 void Play(void*, int, const char*, bool);
53 void Pause();
54 void Resume();
55 void Stop();
56 bool IsPlaying();
57
58 bool LoadMIDI();
59 };
60
61 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
62
63 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
64
65 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
66
67 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
68
69 extern bool allegro_sound_initialised;
70
71 // PUBLIC DATA DEFINITIONS -------------------------------------------------
72
73 IMPLEMENT_MIDI_DEVICE(VAllegroMidiDevice, MIDIDRV_Default, "Default",
74 "Allegro midi device", NULL);
75
76 // PRIVATE DATA DEFINITIONS ------------------------------------------------
77
78 // CODE --------------------------------------------------------------------
79
80 //==========================================================================
81 //
82 // VAllegroMidiDevice::VAllegroMidiDevice
83 //
84 //==========================================================================
85
VAllegroMidiDevice()86 VAllegroMidiDevice::VAllegroMidiDevice()
87 : DidInitAllegro(false)
88 , midi_locked(false)
89 , Mus_SndPtr(NULL)
90 , MusicPaused(false)
91 , MusVolume(-1)
92 {
93 memset(&mididata, 0, sizeof(mididata));
94 }
95
96 //==========================================================================
97 //
98 // VAllegroMidiDevice::Init
99 //
100 //==========================================================================
101
Init()102 void VAllegroMidiDevice::Init()
103 {
104 guard(VAllegroMidiDevice::Init);
105 if (!allegro_sound_initialised)
106 {
107 // Init sound device
108 if (install_sound(DIGI_NONE, MIDI_AUTODETECT, NULL) == -1)
109 {
110 GCon->Logf(NAME_Init, "ALLEGRO SOUND INIT ERROR!!!!\n%s\n", allegro_error);
111 return;
112 }
113 DidInitAllegro = true;
114 }
115 Initialised = true;
116 unguard;
117 }
118
119 //==========================================================================
120 //
121 // VAllegroMidiDevice::Shutdown
122 //
123 //==========================================================================
124
Shutdown()125 void VAllegroMidiDevice::Shutdown()
126 {
127 guard(VAllegroMidiDevice::Shutdown);
128 if (Initialised)
129 {
130 Stop();
131 if (DidInitAllegro)
132 {
133 remove_sound();
134 }
135 }
136 unguard;
137 }
138
139 //==========================================================================
140 //
141 // VAllegroMidiDevice::SetVolume
142 //
143 //==========================================================================
144
SetVolume(float Volume)145 void VAllegroMidiDevice::SetVolume(float Volume)
146 {
147 guard(VAllegroMidiDevice::SetVolume);
148 if (Volume != MusVolume)
149 {
150 MusVolume = Volume;
151 set_volume(-1, int(MusVolume * 255));
152 }
153 unguard;
154 }
155
156 //==========================================================================
157 //
158 // VAllegroMidiDevice::Tick
159 //
160 //==========================================================================
161
Tick(float)162 void VAllegroMidiDevice::Tick(float)
163 {
164 }
165
166 //==========================================================================
167 //
168 // VAllegroMidiDevice::Play
169 //
170 //==========================================================================
171
Play(void * Data,int len,const char * song,bool loop)172 void VAllegroMidiDevice::Play(void* Data, int len, const char* song, bool loop)
173 {
174 guard(VAllegroMidiDevice::Play);
175 bool res;
176
177 Mus_SndPtr = Data;
178 res = LoadMIDI();
179 if (!res)
180 {
181 Z_Free(Mus_SndPtr);
182 Mus_SndPtr = NULL;
183 return;
184 }
185
186 play_midi(&mididata, loop); // 'true' denotes endless looping.
187 if (!MusVolume || MusicPaused)
188 {
189 midi_pause();
190 }
191 CurrSong = VName(song, VName::AddLower8);
192 CurrLoop = loop;
193 unguard;
194 }
195
196 //==========================================================================
197 //
198 // VAllegroMidiDevice::LoadMIDI
199 //
200 // Convert an in-memory copy of a MIDI format 0 or 1 file to
201 // an Allegro MIDI structure
202 //
203 //==========================================================================
204
LoadMIDI()205 bool VAllegroMidiDevice::LoadMIDI()
206 {
207 guard(VAllegroMidiDevice::LoadMIDI);
208 int i;
209 int num_tracks;
210 byte *data;
211 MIDheader *hdr;
212
213 memset(&mididata, 0, sizeof(mididata));
214
215 hdr = (MIDheader*)Mus_SndPtr;
216
217 // MIDI file type
218 i = BigShort(hdr->type);
219 if ((i != 0) && (i != 1))
220 {
221 // only type 0 and 1 are suported
222 GCon->Log(NAME_Dev, "Unsuported MIDI type");
223 return false;
224 }
225
226 // number of tracks
227 num_tracks = BigShort(hdr->num_tracks);
228 if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
229 {
230 GCon->Log(NAME_Dev, "Invalid MIDI track count");
231 return false;
232 }
233
234 // beat divisions
235 mididata.divisions = BigShort(hdr->divisions);
236
237 // read each track
238 data = (byte*)hdr + sizeof(*hdr);
239 for (i = 0; i < num_tracks; i++)
240 {
241 if (memcmp(data, "MTrk", 4))
242 {
243 GCon->Logf(NAME_Dev, "Bad MIDI track %d header", i);
244 return false;
245 }
246 data += 4;
247
248 mididata.track[i].len = BigLong(*(int*)data);
249 data += 4;
250
251 mididata.track[i].data = data;
252 data += mididata.track[i].len;
253 }
254
255 lock_midi(&mididata);
256 midi_locked = true;
257 return true;
258 unguard;
259 }
260
261 //==========================================================================
262 //
263 // VAllegroMidiDevice::Pause
264 //
265 //==========================================================================
266
Pause()267 void VAllegroMidiDevice::Pause()
268 {
269 guard(VAllegroMidiDevice::Pause);
270 midi_pause();
271 MusicPaused = true;
272 unguard;
273 }
274
275 //==========================================================================
276 //
277 // VAllegroMidiDevice::Resume
278 //
279 //==========================================================================
280
Resume()281 void VAllegroMidiDevice::Resume()
282 {
283 guard(VAllegroMidiDevice::Resume);
284 if (MusVolume)
285 midi_resume();
286 MusicPaused = false;
287 unguard;
288 }
289
290 //==========================================================================
291 //
292 // VAllegroMidiDevice::Stop
293 //
294 //==========================================================================
295
Stop()296 void VAllegroMidiDevice::Stop()
297 {
298 guard(VAllegroMidiDevice::Stop);
299 stop_midi();
300 if (midi_locked)
301 {
302 for (int i = 0; i < MIDI_TRACKS; i++)
303 {
304 if (mididata.track[i].data)
305 {
306 UNLOCK_DATA(mididata.track[i].data, mididata.track[i].len);
307 }
308 }
309 UNLOCK_DATA(&mididata, sizeof(MIDI));
310 midi_locked = false;
311 }
312 if (Mus_SndPtr)
313 {
314 Z_Free(Mus_SndPtr);
315 Mus_SndPtr = NULL;
316 }
317 CurrSong = NAME_None;
318 unguard;
319 }
320
321 //==========================================================================
322 //
323 // VAllegroMidiDevice::IsPlaying
324 //
325 //==========================================================================
326
IsPlaying()327 bool VAllegroMidiDevice::IsPlaying()
328 {
329 guard(VAllegroMidiDevice::IsPlaying);
330 return midi_pos >= 0;
331 unguard;
332 }
333