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