/
i_musicinterns.h
387 lines (318 loc) · 10.1 KB
/
i_musicinterns.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
#include <mutex>
#include "oplsynth/opl_mus_player.h"
#include "c_cvars.h"
#include "mus2midi.h"
#include "i_sound.h"
#include "i_music.h"
#include "s_sound.h"
#include "files.h"
#include "wildmidi/wildmidi_lib.h"
#include "midisources/midisource.h"
void I_InitMusicWin32 ();
extern float relative_volume;
class MIDISource;
// A device that provides a WinMM-like MIDI streaming interface -------------
struct MidiHeader
{
uint8_t *lpData;
uint32_t dwBufferLength;
uint32_t dwBytesRecorded;
MidiHeader *lpNext;
};
// These constants must match the corresponding values of the Windows headers
// to avoid readjustment in the native Windows device's playback functions
// and should not be changed.
enum
{
MIDIDEV_MIDIPORT = 1,
MIDIDEV_SYNTH,
MIDIDEV_SQSYNTH,
MIDIDEV_FMSYNTH,
MIDIDEV_MAPPER,
MIDIDEV_WAVETABLE,
MIDIDEV_SWSYNTH
};
enum : uint8_t
{
MEVENT_TEMPO = 1,
MEVENT_NOP = 2,
MEVENT_LONGMSG = 128,
};
#define MEVENT_EVENTTYPE(x) ((uint8_t)((x) >> 24))
#define MEVENT_EVENTPARM(x) ((x) & 0xffffff)
class MIDIStreamer;
typedef void(*MidiCallback)(void *);
class MIDIDevice
{
public:
MIDIDevice();
virtual ~MIDIDevice();
virtual int Open(MidiCallback, void *userdata) = 0;
virtual void Close() = 0;
virtual bool IsOpen() const = 0;
virtual int GetTechnology() const = 0;
virtual int SetTempo(int tempo) = 0;
virtual int SetTimeDiv(int timediv) = 0;
virtual int StreamOut(MidiHeader *data) = 0;
virtual int StreamOutSync(MidiHeader *data) = 0;
virtual int Resume() = 0;
virtual void Stop() = 0;
virtual int PrepareHeader(MidiHeader *data);
virtual int UnprepareHeader(MidiHeader *data);
virtual bool FakeVolume();
virtual bool Pause(bool paused) = 0;
virtual void InitPlayback();
virtual bool Update();
virtual void PrecacheInstruments(const uint16_t *instruments, int count);
virtual void FluidSettingInt(const char *setting, int value);
virtual void FluidSettingNum(const char *setting, double value);
virtual void FluidSettingStr(const char *setting, const char *value);
virtual void WildMidiSetOption(int opt, int set);
virtual bool Preprocess(MIDIStreamer *song, bool looping);
virtual FString GetStats();
virtual int GetDeviceType() const { return MDEV_DEFAULT; }
virtual bool CanHandleSysex() const { return true; }
};
void TimidityPP_Shutdown();
// Base class for software synthesizer MIDI output devices ------------------
class SoftSynthMIDIDevice : public MIDIDevice
{
friend class MIDIWaveWriter;
public:
SoftSynthMIDIDevice(int samplerate, int minrate = 1, int maxrate = 1000000 /* something higher than any valid value */);
~SoftSynthMIDIDevice();
void Close();
bool IsOpen() const;
int GetTechnology() const;
int SetTempo(int tempo);
int SetTimeDiv(int timediv);
int StreamOut(MidiHeader *data);
int StreamOutSync(MidiHeader *data);
int Resume();
void Stop();
bool Pause(bool paused);
protected:
std::mutex CritSec;
SoundStream *Stream;
double Tempo;
double Division;
double SamplesPerTick;
double NextTickIn;
MidiHeader *Events;
bool Started;
uint32_t Position;
int SampleRate;
MidiCallback Callback;
void *CallbackData;
virtual void CalcTickRate();
int PlayTick();
int OpenStream(int chunks, int flags, MidiCallback, void *userdata);
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
virtual bool ServiceStream (void *buff, int numbytes);
int GetSampleRate() const { return SampleRate; }
virtual void HandleEvent(int status, int parm1, int parm2) = 0;
virtual void HandleLongEvent(const uint8_t *data, int len) = 0;
virtual void ComputeOutput(float *buffer, int len) = 0;
};
// OPL implementation of a MIDI output device -------------------------------
class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
{
public:
OPLMIDIDevice(const char *args);
int Open(MidiCallback, void *userdata);
void Close();
int GetTechnology() const;
FString GetStats();
protected:
void CalcTickRate();
int PlayTick();
void HandleEvent(int status, int parm1, int parm2);
void HandleLongEvent(const uint8_t *data, int len);
void ComputeOutput(float *buffer, int len);
bool ServiceStream(void *buff, int numbytes);
int GetDeviceType() const override { return MDEV_OPL; }
};
// OPL dumper implementation of a MIDI output device ------------------------
class OPLDumperMIDIDevice : public OPLMIDIDevice
{
public:
OPLDumperMIDIDevice(const char *filename);
~OPLDumperMIDIDevice();
int Resume();
void Stop();
};
// Internal disk writing version of a MIDI device ------------------
class MIDIWaveWriter : public SoftSynthMIDIDevice
{
public:
MIDIWaveWriter(const char *filename, SoftSynthMIDIDevice *devtouse);
~MIDIWaveWriter();
int Resume();
int Open(MidiCallback cb, void *userdata)
{
return playDevice->Open(cb, userdata);
}
void Stop();
void HandleEvent(int status, int parm1, int parm2) { playDevice->HandleEvent(status, parm1, parm2); }
void HandleLongEvent(const uint8_t *data, int len) { playDevice->HandleLongEvent(data, len); }
void ComputeOutput(float *buffer, int len) { playDevice->ComputeOutput(buffer, len); }
int StreamOutSync(MidiHeader *data) { return playDevice->StreamOutSync(data); }
int StreamOut(MidiHeader *data) { return playDevice->StreamOut(data); }
int GetDeviceType() const override { return playDevice->GetDeviceType(); }
bool ServiceStream (void *buff, int numbytes) { return playDevice->ServiceStream(buff, numbytes); }
int GetTechnology() const { return playDevice->GetTechnology(); }
int SetTempo(int tempo) { return playDevice->SetTempo(tempo); }
int SetTimeDiv(int timediv) { return playDevice->SetTimeDiv(timediv); }
bool IsOpen() const { return playDevice->IsOpen(); }
void CalcTickRate() { playDevice->CalcTickRate(); }
protected:
FileWriter *File;
SoftSynthMIDIDevice *playDevice;
};
// Base class for streaming MUS and MIDI files ------------------------------
enum
{
MAX_MIDI_EVENTS = 128
};
class MIDIStreamer : public MusInfo
{
public:
MIDIStreamer(EMidiDevice type, const char *args);
~MIDIStreamer();
void MusicVolumeChanged() override;
void Play(bool looping, int subsong) override;
void Pause() override;
void Resume() override;
void Stop() override;
bool IsPlaying() override;
bool IsMIDI() const override;
bool IsValid() const override;
bool SetSubsong(int subsong) override;
void Update() override;
FString GetStats() override;
void FluidSettingInt(const char *setting, int value) override;
void FluidSettingNum(const char *setting, double value) override;
void FluidSettingStr(const char *setting, const char *value) override;
void WildMidiSetOption(int opt, int set) override;
int ServiceEvent();
void SetMIDISource(MIDISource *_source);
int GetDeviceType() const override
{
return nullptr == MIDI
? MusInfo::GetDeviceType()
: MIDI->GetDeviceType();
}
bool DumpWave(const char *filename, int subsong, int samplerate);
bool DumpOPL(const char *filename, int subsong);
protected:
MIDIStreamer(const char *dumpname, EMidiDevice type);
void OutputVolume (uint32_t volume);
int FillBuffer(int buffer_num, int max_events, uint32_t max_time);
int FillStopBuffer(int buffer_num);
uint32_t *WriteStopNotes(uint32_t *events);
int VolumeControllerChange(int channel, int volume);
void SetTempo(int new_tempo);
void Precache();
void StartPlayback();
bool InitPlayback();
//void SetMidiSynth(MIDIDevice *synth);
static EMidiDevice SelectMIDIDevice(EMidiDevice devtype);
MIDIDevice *CreateMIDIDevice(EMidiDevice devtype, int samplerate);
static void Callback(void *userdata);
enum
{
SONG_MORE,
SONG_DONE,
SONG_ERROR
};
MIDIDevice *MIDI;
uint32_t Events[2][MAX_MIDI_EVENTS*3];
MidiHeader Buffer[2];
int BufferNum;
int EndQueued;
bool VolumeChanged;
bool Restarting;
bool InitialPlayback;
uint32_t NewVolume;
uint32_t Volume;
EMidiDevice DeviceType;
bool CallbackIsThreaded;
int LoopLimit;
FString Args;
MIDISource *source;
};
// Anything supported by the sound system out of the box --------------------
class StreamSong : public MusInfo
{
public:
StreamSong (FileReader &reader);
~StreamSong ();
void Play (bool looping, int subsong);
void Pause ();
void Resume ();
void Stop ();
bool IsPlaying ();
bool IsValid () const { return m_Stream != NULL; }
bool SetPosition (unsigned int pos);
bool SetSubsong (int subsong);
FString GetStats();
protected:
StreamSong () : m_Stream(NULL) {}
SoundStream *m_Stream;
};
// MUS file played by a software OPL2 synth and streamed through the sound system
class OPLMUSSong : public StreamSong
{
public:
OPLMUSSong (FileReader &reader, const char *args);
~OPLMUSSong ();
void Play (bool looping, int subsong);
bool IsPlaying ();
bool IsValid () const;
void ResetChips ();
MusInfo *GetOPLDumper(const char *filename);
protected:
OPLMUSSong(const OPLMUSSong *original, const char *filename); // OPL dump constructor
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
OPLmusicFile *Music;
};
class OPLMUSDumper : public OPLMUSSong
{
public:
OPLMUSDumper(const OPLMUSSong *original, const char *filename);
void Play(bool looping, int);
};
// CD track/disk played through the multimedia system -----------------------
class CDSong : public MusInfo
{
public:
CDSong (int track, int id);
~CDSong ();
void Play (bool looping, int subsong);
void Pause ();
void Resume ();
void Stop ();
bool IsPlaying ();
bool IsValid () const { return m_Inited; }
protected:
CDSong () : m_Inited(false) {}
int m_Track;
bool m_Inited;
};
// CD track on a specific disk played through the multimedia system ---------
class CDDAFile : public CDSong
{
public:
CDDAFile (FileReader &reader);
};
// Module played via foo_dumb -----------------------------------------------
MusInfo *MOD_OpenSong(FileReader &reader);
// Music played via Game Music Emu ------------------------------------------
const char *GME_CheckFormat(uint32_t header);
MusInfo *GME_OpenSong(FileReader &reader, const char *fmt);
MusInfo *SndFile_OpenSong(FileReader &fr);
// --------------------------------------------------------------------------
extern MusInfo *currSong;
void MIDIDeviceChanged(int newdev, bool force = false);
EXTERN_CVAR (Float, snd_mastervolume)
EXTERN_CVAR (Float, snd_musicvolume)