native_midi_win32.c
上传用户:nini_0081
上传日期:2022-07-21
资源大小:2628k
文件大小:7k
源码类别:

多媒体编程

开发平台:

DOS

  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. #include "SDL_config.h"
  19. /* everything below is currently one very big bad hack ;) Proff */
  20. #if __WIN32__
  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, DWORD_PTR dwInstance,
  143.                         DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
  144. {
  145.     switch( uMsg )
  146.     {
  147.     case MOM_DONE:
  148.       if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr))
  149.         BlockOut(currentsong);
  150.       break;
  151.     case MOM_POSITIONCB:
  152.       if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&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,(DWORD_PTR)MidiProc,(DWORD_PTR)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 /* Windows native MIDI support */