/
native_midi_win32.c
319 lines (277 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
native_midi: Hardware Midi support for the SDL_mixer library
Copyright (C) 2000,2001 Florian 'Proff' Schulze
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Florian 'Proff' Schulze
florian.proff.schulze@gmx.net
*/
22
#include "SDL_config.h"
23
24
25
/* everything below is currently one very big bad hack ;) Proff */
26
#if __WIN32__
27
28
29
30
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
31
32
33
34
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "native_midi.h"
35
#include "native_midi_common.h"
36
37
38
39
40
41
struct _NativeMidiSong {
int MusicLoaded;
int MusicPlaying;
MIDIHDR MidiStreamHdr;
MIDIEVENT *NewEvents;
42
43
Uint16 ppqn;
int Size;
44
45
46
int NewPos;
};
47
48
49
50
51
52
53
54
55
56
57
58
static UINT MidiDevice=MIDI_MAPPER;
static HMIDISTRM hMidiStream;
static NativeMidiSong *currentsong;
static int BlockOut(NativeMidiSong *song)
{
MMRESULT err;
int BlockSize;
if ((song->MusicLoaded) && (song->NewEvents))
{
// proff 12/8/98: Added for savety
59
60
midiOutUnprepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
if (song->NewPos>=song->Size)
61
return 0;
62
BlockSize=(song->Size-song->NewPos);
63
64
65
66
if (BlockSize<=0)
return 0;
if (BlockSize>36000)
BlockSize=36000;
67
song->MidiStreamHdr.lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
68
69
70
71
song->NewPos+=BlockSize;
song->MidiStreamHdr.dwBufferLength=BlockSize;
song->MidiStreamHdr.dwBytesRecorded=BlockSize;
song->MidiStreamHdr.dwFlags=0;
72
err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
73
74
75
76
77
78
79
80
if (err!=MMSYSERR_NOERROR)
return 0;
err=midiStreamOut(hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
return 0;
}
return 1;
}
81
static void MIDItoStream(NativeMidiSong *song, MIDIEvent *evntlist)
82
{
83
84
85
86
87
88
89
int eventcount;
MIDIEvent *event;
MIDIEVENT *newevent;
eventcount=0;
event=evntlist;
while (event)
90
{
91
92
eventcount++;
event=event->next;
93
}
94
95
96
97
98
99
100
101
102
song->NewEvents=malloc(eventcount*3*sizeof(DWORD));
if (!song->NewEvents)
return;
memset(song->NewEvents,0,(eventcount*3*sizeof(DWORD)));
eventcount=0;
event=evntlist;
newevent=song->NewEvents;
while (event)
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
int status = (event->status&0xF0)>>4;
switch (status)
{
case MIDI_STATUS_NOTE_OFF:
case MIDI_STATUS_NOTE_ON:
case MIDI_STATUS_AFTERTOUCH:
case MIDI_STATUS_CONTROLLER:
case MIDI_STATUS_PROG_CHANGE:
case MIDI_STATUS_PRESSURE:
case MIDI_STATUS_PITCH_WHEEL:
newevent->dwDeltaTime=event->time;
newevent->dwEvent=(event->status|0x80)|(event->data[0]<<8)|(event->data[1]<<16)|(MEVT_SHORTMSG<<24);
newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
eventcount++;
break;
case MIDI_STATUS_SYSEX:
if (event->status == 0xFF && event->data[0] == 0x51) /* Tempo change */
{
int tempo = (event->extraData[0] << 16) |
(event->extraData[1] << 8) |
event->extraData[2];
newevent->dwDeltaTime=event->time;
newevent->dwEvent=(MEVT_TEMPO<<24) | tempo;
newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
eventcount++;
}
break;
132
}
133
134
135
136
137
138
139
140
141
142
event=event->next;
}
song->Size=eventcount*3*sizeof(DWORD);
{
int time;
int temptime;
143
song->NewPos=0;
144
145
146
time=0;
newevent=song->NewEvents;
while (song->NewPos<song->Size)
147
{
148
149
150
151
152
153
temptime=newevent->dwDeltaTime;
newevent->dwDeltaTime-=time;
time=temptime;
if ((song->NewPos+12)>=song->Size)
newevent->dwEvent |= MEVT_F_CALLBACK;
newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
154
155
156
song->NewPos+=12;
}
}
157
158
song->NewPos=0;
song->MusicLoaded=1;
159
160
}
161
162
void CALLBACK MidiProc( HMIDIIN hMidi, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
163
164
165
166
{
switch( uMsg )
{
case MOM_DONE:
167
if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->MidiStreamHdr))
168
169
170
BlockOut(currentsong);
break;
case MOM_POSITIONCB:
171
if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->MidiStreamHdr))
172
173
174
175
176
177
178
currentsong->MusicPlaying=0;
break;
default:
break;
}
}
179
int native_midi_detect()
180
181
182
183
{
MMRESULT merr;
HMIDISTRM MidiStream;
184
merr=midiStreamOpen(&MidiStream,&MidiDevice,(DWORD)1,(DWORD_PTR)MidiProc,(DWORD_PTR)0,CALLBACK_FUNCTION);
185
186
if (merr!=MMSYSERR_NOERROR)
return 0;
187
188
midiStreamClose(MidiStream);
return 1;
189
190
}
191
NativeMidiSong *native_midi_loadsong(const char *midifile)
192
{
193
NativeMidiSong *newsong;
194
MIDIEvent *evntlist = NULL;
195
SDL_RWops *rw;
196
197
198
199
200
newsong=malloc(sizeof(NativeMidiSong));
if (!newsong)
return NULL;
memset(newsong,0,sizeof(NativeMidiSong));
201
202
203
204
205
206
207
208
209
210
211
212
/* Attempt to load the midi file */
rw = SDL_RWFromFile(midifile, "rb");
if (rw) {
evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
SDL_RWclose(rw);
if (!evntlist)
{
free(newsong);
return NULL;
}
}
213
214
MIDItoStream(newsong, evntlist);
215
216
FreeMIDIEventList(evntlist);
217
218
return newsong;
219
220
}
221
222
NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
{
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
NativeMidiSong *newsong;
MIDIEvent *evntlist = NULL;
newsong=malloc(sizeof(NativeMidiSong));
if (!newsong)
return NULL;
memset(newsong,0,sizeof(NativeMidiSong));
/* Attempt to load the midi file */
evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
if (!evntlist)
{
free(newsong);
return NULL;
}
MIDItoStream(newsong, evntlist);
FreeMIDIEventList(evntlist);
return newsong;
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
void native_midi_freesong(NativeMidiSong *song)
{
if (hMidiStream)
{
midiStreamStop(hMidiStream);
midiStreamClose(hMidiStream);
}
if (song)
{
if (song->NewEvents)
free(song->NewEvents);
free(song);
}
}
void native_midi_start(NativeMidiSong *song)
{
MMRESULT merr;
MIDIPROPTIMEDIV mptd;
native_midi_stop();
if (!hMidiStream)
{
269
merr=midiStreamOpen(&hMidiStream,&MidiDevice,(DWORD)1,(DWORD_PTR)MidiProc,(DWORD_PTR)0,CALLBACK_FUNCTION);
270
271
if (merr!=MMSYSERR_NOERROR)
{
272
hMidiStream = NULL; // should I do midiStreamClose(hMidiStream) before?
273
274
275
276
277
278
279
return;
}
//midiStreamStop(hMidiStream);
currentsong=song;
currentsong->NewPos=0;
currentsong->MusicPlaying=1;
mptd.cbStruct=sizeof(MIDIPROPTIMEDIV);
280
mptd.dwTimeDiv=currentsong->ppqn;
281
282
283
284
285
286
287
288
289
290
291
292
293
merr=midiStreamProperty(hMidiStream,(LPBYTE)&mptd,MIDIPROP_SET | MIDIPROP_TIMEDIV);
BlockOut(song);
merr=midiStreamRestart(hMidiStream);
}
}
void native_midi_stop()
{
if (!hMidiStream)
return;
midiStreamStop(hMidiStream);
midiStreamClose(hMidiStream);
currentsong=NULL;
294
hMidiStream = NULL;
295
296
297
298
299
300
301
302
303
}
int native_midi_active()
{
return currentsong->MusicPlaying;
}
void native_midi_setvolume(int volume)
{
304
305
306
307
308
309
310
311
int calcVolume;
if (volume > 128)
volume = 128;
if (volume < 0)
volume = 0;
calcVolume = (65535 * volume / 128);
midiOutSetVolume((HMIDIOUT)hMidiStream, MAKELONG(calcVolume , calcVolume));
312
313
}
314
const char *native_midi_error(void)
315
316
317
318
{
return "";
}
319
#endif /* Windows native MIDI support */