1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 // Music class
24 
25 #ifndef TINSEL_MUSIC_H
26 #define TINSEL_MUSIC_H
27 
28 #include "audio/midiplayer.h"
29 #include "audio/audiostream.h"
30 #include "audio/mixer.h"
31 #include "common/mutex.h"
32 
33 class MidiParser;
34 
35 namespace Tinsel {
36 
37 class Music {
38 public:
Music()39 	Music() : _currentMidi(0), _currentLoop(false) {
40 		_midiBuffer.pDat = nullptr;
41 		_midiBuffer.size = 0;
42 	}
43 
44 	bool PlayMidiSequence(		// Plays the specified MIDI sequence through the sound driver
45 		uint32 dwFileOffset,		// handle of MIDI sequence data
46 		bool bLoop);			// Whether to loop the sequence
47 
48 	bool MidiPlaying();		// Returns TRUE if a Midi tune is currently playing
49 
50 	bool StopMidi();		// Stops any currently playing midi
51 
52 	void SetMidiVolume(		// Sets the volume of the MIDI music. Returns the old volume
53 		int vol);		// new volume - 0..MAXMIDIVOL
54 
55 	int GetMidiVolume();
56 
57 	void OpenMidiFiles();
58 	void DeleteMidiBuffer();
59 
60 	void CurrentMidiFacts(SCNHANDLE	*pMidi, bool *pLoop);
61 	void RestoreMidiFacts(SCNHANDLE	Midi, bool Loop);
62 
63 	int GetTrackNumber(SCNHANDLE hMidi);
64 	SCNHANDLE GetTrackOffset(int trackNumber);
65 
GetMidiBuffer()66 	uint8 *GetMidiBuffer() { return _midiBuffer.pDat; }
67 
ResizeMidiBuffer(uint32 newSize)68 	uint8* ResizeMidiBuffer(uint32 newSize) {
69 		if (_midiBuffer.size < newSize) {
70 			_midiBuffer.pDat = (byte*)realloc(_midiBuffer.pDat, newSize);
71 			assert(_midiBuffer.pDat);
72 		}
73 
74 		return _midiBuffer.pDat;
75 	}
76 
77 	void dumpMusic();
78 
79 private:
80 	// sound buffer structure used for MIDI data and samples
81 	struct SOUND_BUFFER {
82 		uint8 *pDat;		// pointer to actual buffer
83 		uint32 size;		// size of the buffer
84 	};
85 
86 	// MIDI buffer
87 	SOUND_BUFFER _midiBuffer;
88 
89 	SCNHANDLE	_currentMidi;
90 	bool		_currentLoop;
91 
92 	// We allocate 155 entries because that's the maximum, used in the SCN version
93 	SCNHANDLE _midiOffsets[155];
94 };
95 
96 class MidiMusicPlayer : public Audio::MidiPlayer {
97 public:
98 	MidiMusicPlayer(TinselEngine *vm);
99 
100 	void setVolume(int volume) override;
101 
102 	void playMIDI(uint32 size, bool loop);
103 
104 //	void stop();
105 	void pause() override;
106 	void resume() override;
107 
108 	// MidiDriver_BASE interface implementation
109 	void send(uint32 b) override;
110 
111 	// The original sets the "sequence timing" to 109 Hz, whatever that
112 	// means. The default is 120.
getBaseTempo()113 	uint32 getBaseTempo()	{ return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; }
114 
115 	bool _milesAudioMode;
116 
117 private:
118 	void playXMIDI(uint32 size, bool loop);
119 	void playSEQ(uint32 size, bool loop);
120 };
121 
122 class PCMMusicPlayer : public Audio::AudioStream {
123 public:
124 	PCMMusicPlayer();
125 	~PCMMusicPlayer() override;
126 
127 	bool isPlaying() const;
128 
129 	bool isDimmed() const;
130 
131 	void getTunePlaying(void *voidPtr, int length);
132 	void restoreThatTune(void *voidPtr);
133 
134 	void setMusicSceneDetails(SCNHANDLE hScript, SCNHANDLE hSegment, const char *fileName);
135 
136 	void setVolume(int volume);
137 
138 	void startPlay(int id);
139 	void stopPlay();
140 
141 	bool getMusicTinselDimmed() const;
142 	void dim(bool bTinselDim);
143 	void unDim(bool bTinselUnDim);
144 	void dimIteration();
145 
146 	void startFadeOut(int ticks);
147 	void fadeOutIteration();
148 
149 	int readBuffer(int16 *buffer, const int numSamples) override;
150 	bool isStereo() const override;
endOfData()151 	bool endOfData() const override { return _end; }
endOfStream()152 	bool endOfStream() const override { return false; }
153 	int getRate() const override;
154 
155 protected:
156 	enum State {
157 		S_IDLE,
158 		S_NEW,
159 		S_MID,
160 		S_END1,
161 		S_END2,
162 		S_END3,
163 		S_NEXT,
164 		S_STOP
165 	};
166 
167 	Audio::SoundHandle _handle;
168 	Audio::AudioStream *_curChunk;
169 	Common::Mutex _mutex;
170 
171 	bool _end;
172 
173 	int _silenceSamples;
174 
175 	State _state, _mState;
176 	bool _forcePlay;
177 	int32 _scriptNum;
178 	int32 _scriptIndex;
179 	SCNHANDLE _hScript;
180 	SCNHANDLE _hSegment;
181 	Common::String _filename;
182 
183 	uint8 _volume;
184 
185 	bool _dimmed;
186 	bool _dimmedTinsel;
187 	uint8 _dimmedVolume;
188 	int _dimIteration;
189 	int _dimPosition;
190 
191 	uint8 _fadeOutVolume;
192 	int _fadeOutIteration;
193 
194 	void play();
195 	void stop();
196 	void setVol(uint8 volume);
197 
198 	bool getNextChunk();
199 
200 	void loadMusicFromSegment(int segmentNum);
201 	void loadADPCMMusicFromSegment(int segmentNum);
202 	void loadMP3MusicFromSegment(int segmentNum);
203 };
204 
205 } // End of namespace Tinsel
206 
207 #endif
208