native_midi_win32.c 7.5 KB

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