]> icculus.org git repositories - btb/d2x.git/blob - unused/win95/winmidi.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / unused / win95 / winmidi.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15
16
17
18 #define _WIN32
19 #define WIN95
20 #define WIN32_LEAN_AND_MEAN
21
22 #include <windows.h>
23 #include <windowsx.h>
24 #include <mmsystem.h>
25 #include <mmreg.h>
26
27 #include "pstypes.h"
28 #include "mono.h"
29 #include "dxxerror.h"
30 #include "mem.h"
31 #include "winapp.h"
32 #include "winregs.h"
33
34
35 #include "midifile.h"
36 #include "midiseq.h"
37 #include "winmidi.h"
38
39
40 //      ----------------------------------------------------------------------------
41 //      Data
42 //      ----------------------------------------------------------------------------
43
44 BOOL    WMidi_NewStream = 0;
45
46 static BOOL                             WMidi_initialized = FALSE;
47 static SEQ                              MSeq;
48 static DWORD                    wmidi_volume = 0x80008000;
49 static BOOL                             LoopSong = FALSE;
50 static BOOL                             MidiVolChanges = TRUE;
51
52
53 void wmidi_deamp_song(DWORD vol);
54 int wmidi_get_tech();
55 void CALLBACK wmidi_seq_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
56
57
58 //      ----------------------------------------------------------------------------
59 //      Sequencer Initialization and destruction
60 //      ----------------------------------------------------------------------------
61
62 int wmidi_init(uint mmdev)
63 {
64         MIDIOUTCAPS midicaps;
65         //BYTE *hdr;
66         //DWORD bufsize;
67         //int i;
68         UINT ui;
69         
70         memset(&MSeq, 0, sizeof(SEQ));
71
72         WMidi_initialized = TRUE;
73
74 //      Initialize stream buffers
75         MSeq.uState = SEQ_S_NOFILE;
76         MSeq.lpmhFree = NULL;
77         MSeq.lpbAlloc = NULL;
78         MSeq.hmidi = NULL;
79
80         MSeq.cBuffer = 4;
81         MSeq.cbBuffer = 512;
82
83         if (seqAllocBuffers(&MSeq) != MMSYSERR_NOERROR)
84         return FALSE;
85
86 //      Setup sequencer some more
87         ui = midiOutGetDevCaps(mmdev, &midicaps, sizeof(midicaps));
88         if ( ui != MMSYSERR_NOERROR) {
89                 mprintf((1, "WMIDI:(%x) Unable to find requested device.\n", MSeq.mmrcLastErr));
90                 return 0;
91         }
92         
93         if ((midicaps.dwSupport & MIDICAPS_VOLUME) || (midicaps.dwSupport & MIDICAPS_LRVOLUME)) 
94                 MidiVolChanges = TRUE;
95         else MidiVolChanges = FALSE;
96
97         MSeq.uDeviceID = mmdev;
98
99 //      Now we must do a stupid Microsoft trick to determine whether we are
100 //      using WAVE TABLE volume or OPL volume.
101         MSeq.uMCIDeviceID = wmidi_get_tech();
102
103         logentry("MIDI technology: %d.\n", MSeq.uMCIDeviceID);
104         
105         return 1;
106 }
107                                 
108
109 void wmidi_close()
110 {
111         //MIDIHDR *hdr;
112
113         Assert(WMidi_initialized == TRUE);
114
115         seqFreeBuffers(&MSeq);
116         
117         WMidi_initialized = FALSE;
118 }
119
120
121 int wmidi_get_tech()
122 {
123         HKEY hKey;
124         long lres;
125         char key[32];   
126         char buf[256];
127         char *pstr;
128         DWORD len,type;
129
130
131         lres = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
132                                         0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_EXECUTE,
133                                         &hKey);
134         if (lres != ERROR_SUCCESS) return 0;
135
136         len = 32;
137         lres = RegQueryValueEx(hKey, "CurrentInstrument", NULL, &type, key, &len);
138         if (lres != ERROR_SUCCESS) {
139                 RegCloseKey(hKey);
140                 return 0;
141         }
142
143         RegCloseKey(hKey);
144
145         strcpy(buf, "System\\CurrentControlSet\\control\\MediaResources\\midi\\");
146         strcat(buf, key);
147         lres = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 
148                                         0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_EXECUTE,
149                                         &hKey);
150         if (lres != ERROR_SUCCESS) return 0;
151         
152         len =128;
153         lres = RegQueryValueEx(hKey, "Description", NULL, &type, buf, &len);
154         if (lres != ERROR_SUCCESS) {
155                 RegCloseKey(hKey);
156                 return 0;
157         }
158         RegCloseKey(hKey);
159
160 //      Okay, look for 'wave' or 'fm' or 'opl'
161         pstr = strlwr(buf);     
162         if (strstr(pstr, "wave")) return 1;
163
164         return 0;
165 }
166
167
168 int wmidi_support_volchange() {
169         return (int)MidiVolChanges;
170 }
171
172
173 //      ----------------------------------------------------------------------------
174 //      High level midi song play/stop/pause interface
175 //      ----------------------------------------------------------------------------
176
177 int wmidi_init_song(WMIDISONG *song)
178 {
179         DWORD bufsize;
180         SMF *smf;
181         MMRESULT mmrc;
182
183         if (MSeq.uState != SEQ_S_NOFILE) return 0;
184
185         Assert (song->data != NULL);
186
187    mmrc = seqStop(&MSeq);
188         if (mmrc != MMSYSERR_NOERROR)
189         {
190                 mprintf((1, "WMIDI: Stop song failed.\n"));;
191                 return 0;
192         }
193
194         wmidi_close_song();
195
196         if (song->looping) LoopSong = TRUE;
197         else LoopSong = FALSE;
198
199         if (smfOpenFile(song->data, song->length, (HSMF *)&smf) != SMF_SUCCESS) return 0;
200
201 //      song is confirmed to be a MIDI v1.0 compatible file
202         MSeq.hSmf = smf;
203         MSeq.dwTimeDivision = smf->dwTimeDivision;
204         MSeq.tkLength = smf->tkLength;
205         MSeq.cTrk = smf->dwTracks;
206
207         bufsize = min(MSeq.cbBuffer, smfGetStateMaxSize());
208
209         MSeq.uState = SEQ_S_OPENED;
210         
211         return 1;
212 }
213
214
215 int wmidi_play()
216 {
217         PREROLL         preroll;
218         MMRESULT        mmrc;
219         DWORD           vol;
220
221         preroll.tkBase = 0;
222         preroll.tkEnd = MSeq.tkLength;
223
224         mprintf((1, "wmidi_play: beginning playback.\n"));
225
226         if ((mmrc = seqPreroll(&MSeq, &preroll)) != MMSYSERR_NOERROR) {
227                 mprintf((1, "wmidi_play: preroll failed! (%x)\n", mmrc));
228                 return 0;
229         }
230
231         
232         Assert(MSeq.hmidi != NULL);
233
234 //      wmidi_deamp_song(wmidi_volume);
235
236         mmrc = midiOutSetVolume((HMIDIOUT)MSeq.hmidi, wmidi_volume);    
237         if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
238         midiOutGetVolume((HMIDIOUT)MSeq.hmidi, &vol);
239
240         if (seqStart(&MSeq) != MMSYSERR_NOERROR) return 0; 
241
242         return 1;
243 }
244
245
246 int wmidi_stop()
247 {
248         if (seqStop(&MSeq) != MMSYSERR_NOERROR) return 0;
249         return 1;
250 }
251
252
253 int wmidi_pause()
254 {
255         if (MSeq.uState != SEQ_S_PAUSED) {
256                 if (seqPause(&MSeq) != MMSYSERR_NOERROR) return 0;
257         }
258         return 1;
259 }
260                 
261 int wmidi_resume()
262 {
263         if (MSeq.uState == SEQ_S_PAUSED) {
264                 if (seqRestart(&MSeq) != MMSYSERR_NOERROR) return 0;
265         }
266         return 1;
267 }
268                 
269
270 int wmidi_close_song()
271 {
272
273         LPMIDIHDR               lpmh;
274     
275         if (SEQ_S_OPENED != MSeq.uState)
276                 return MCIERR_UNSUPPORTED_FUNCTION;
277
278         LoopSong = FALSE;
279     
280         if ((HSMF)NULL != MSeq.hSmf)
281         {
282                 smfCloseFile(MSeq.hSmf);
283                 MSeq.hSmf = (HSMF)NULL;
284    }
285
286 /* take care of any stream buffers or MIDI resources left open by
287         the sequencer */
288
289         if (MSeq.hmidi) {
290
291                 for (lpmh = MSeq.lpmhFree; lpmh; lpmh = lpmh->lpNext)
292                         midiOutUnprepareHeader(MSeq.hmidi, lpmh, sizeof(MIDIHDR));
293
294                 if (MSeq.lpmhPreroll) 
295                         midiOutUnprepareHeader(MSeq.hmidi, MSeq.lpmhPreroll, sizeof(MIDIHDR));
296
297                 midiStreamClose(MSeq.hmidi);
298                 MSeq.hmidi = NULL;
299         }
300
301         MSeq.uState = SEQ_S_NOFILE;
302         
303         return 1;
304 }
305
306
307 static uint funky_vol_log_table [] = {
308         0x00000,                                // 0
309         0x0b000,                                // 1
310         0x0c000,                                // 2
311         0x0c800,                                // 3
312         0x0e000,                                // 4
313         0x0e800,                                // 5
314         0x0f000,                                //      6
315         0x0f800,                                //      7
316         0x0ffff                         // 8
317 };
318
319
320
321 int wmidi_set_volume(uint volume)
322 {
323         DWORD vol;
324         //int i;
325         MMRESULT mmrc;
326         
327
328         Assert(volume < 128);
329         if (volume == 127) volume++;
330
331         volume = volume /16;
332
333         if (!volume) vol = 0;
334         else if (MSeq.uMCIDeviceID == 1)                                // WAVETABLE 
335                 vol = funky_vol_log_table[volume]|0x00ff;
336         else {                                                                                          // OPL2/OPL3 and others
337                 vol = volume * 0x2000;                          
338                 if (vol > 0) vol--;
339         }
340
341         vol = (vol<<16)+vol;
342
343         wmidi_volume = vol;
344
345
346         if (MSeq.hmidi) {
347 //              wmidi_deamp_song(wmidi_volume);
348                 mmrc = midiOutSetVolume((HMIDIOUT)MSeq.hmidi, wmidi_volume);    
349                 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
350                 midiOutGetVolume((HMIDIOUT)MSeq.hmidi, &vol);
351         }
352
353         return 1;
354 }
355
356
357 #define MIDI_CTRLCHANGE ((BYTE)0xB0)        // + ctrlr + value
358 #define MIDICTRL_VOLUME ((BYTE)0x07)
359  
360
361 void wmidi_deamp_song(DWORD vol)
362 {
363         float ptvol;
364         DWORD ptdvol;
365         DWORD dwvol, dwstatus, dwevent;
366         MMRESULT mmrc;
367         int i;  
368
369
370         vol = vol & 0x0000ffff;
371
372         ptvol = (float)(vol)*100.0/65536.0;
373         ptdvol = (DWORD)(ptvol);
374
375         mprintf((0, "Deamp = %d percent.\n", ptdvol));
376
377         for (i = 0, dwstatus = MIDI_CTRLCHANGE; i < 16; i++, dwstatus++)
378         {
379                 dwvol = ( 100 * ptdvol ) / 1000;
380            dwevent = dwstatus | ((DWORD)MIDICTRL_VOLUME << 8)
381             | ((DWORD)dwvol << 16);
382                 if(( mmrc= midiOutShortMsg( (HMIDIOUT)MSeq.hmidi, dwevent ))
383                             != MMSYSERR_NOERROR )
384       {
385                         mprintf((1, "WINMIDI::BAD MIDI VOLUME CHANGE!\n"));
386                 return;
387       }
388         }
389 }
390
391
392
393 /*****************************************************************************
394 *
395 *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
396 *  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
397 *  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
398 *  A PARTICULAR PURPOSE.
399 *
400 *  Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
401 *
402 ******************************************************************************/
403
404
405 PRIVATE void FAR PASCAL seqMIDICallback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
406 PRIVATE MMRESULT FNLOCAL XlatSMFErr(SMFRESULT smfrc);
407
408 /***************************************************************************
409 *  
410 * seqAllocBuffers
411 *
412 * Allocate buffers for this instance.
413 *
414 ***************************************************************************/
415 MMRESULT FNLOCAL seqAllocBuffers(
416     PSEQ                    pSeq)
417 {
418     DWORD                   dwEachBufferSize;
419     DWORD                   dwAlloc;
420     UINT                    i;
421     LPBYTE                  lpbWork;
422
423     Assert(pSeq != NULL);
424
425     pSeq->uState    = SEQ_S_NOFILE;
426     pSeq->lpmhFree  = NULL;
427     pSeq->lpbAlloc  = NULL;
428     pSeq->hSmf      = (HSMF)NULL;
429     
430     /* First make sure we can allocate the buffers they asked for
431     */
432     dwEachBufferSize = sizeof(MIDIHDR) + (DWORD)(pSeq->cbBuffer);
433     dwAlloc          = dwEachBufferSize * (DWORD)(pSeq->cBuffer);
434     
435     pSeq->lpbAlloc = GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE, dwAlloc);
436     if (NULL == pSeq->lpbAlloc)
437         return MCIERR_OUT_OF_MEMORY;
438
439     /* Initialize all MIDIHDR's and throw them into a free list
440     */
441     pSeq->lpmhFree = NULL;
442
443     lpbWork = pSeq->lpbAlloc;
444     for (i=0; i < pSeq->cBuffer; i++)
445     {
446         ((LPMIDIHDR)lpbWork)->lpNext            = pSeq->lpmhFree;
447
448         ((LPMIDIHDR)lpbWork)->lpData            = lpbWork + sizeof(MIDIHDR);
449         ((LPMIDIHDR)lpbWork)->dwBufferLength    = pSeq->cbBuffer;
450         ((LPMIDIHDR)lpbWork)->dwBytesRecorded   = 0;
451         ((LPMIDIHDR)lpbWork)->dwUser            = (DWORD)(UINT)pSeq;
452         ((LPMIDIHDR)lpbWork)->dwFlags           = 0;
453
454         pSeq->lpmhFree = (LPMIDIHDR)lpbWork;
455
456         lpbWork += dwEachBufferSize;
457     }
458
459     return MMSYSERR_NOERROR;
460 }
461
462 /***************************************************************************
463 *  
464 * seqFreeBuffers
465 *
466 * Free buffers for this instance.
467 *
468 ****************************************************************************/
469 VOID FNLOCAL seqFreeBuffers(
470     PSEQ                    pSeq)
471 {
472     LPMIDIHDR               lpmh;
473     
474     Assert(pSeq != NULL);
475
476     if (NULL != pSeq->lpbAlloc)
477     {
478         lpmh = (LPMIDIHDR)pSeq->lpbAlloc;
479         Assert(!(lpmh->dwFlags & MHDR_PREPARED));
480         
481         GlobalFreePtr(pSeq->lpbAlloc);
482     }
483 }
484
485
486 /***************************************************************************
487 *  
488 * seqPreroll
489 *
490 * Prepares the file for playback at the given position.
491 *
492 ****************************************************************************/
493 MMRESULT FNLOCAL seqPreroll(
494     PSEQ                    pSeq,
495     LPPREROLL               lpPreroll)
496 {
497     SMFRESULT           smfrc;
498     MMRESULT            mmrc        = MMSYSERR_NOERROR;
499     MIDIPROPTIMEDIV     mptd;
500     LPMIDIHDR           lpmh = NULL;
501     LPMIDIHDR           lpmhPreroll = NULL;
502     DWORD               cbPrerollBuffer;
503     UINT                uDeviceID;
504
505     Assert(pSeq != NULL);
506
507     pSeq->mmrcLastErr = MMSYSERR_NOERROR;
508
509     if (pSeq->uState != SEQ_S_OPENED &&
510         pSeq->uState != SEQ_S_PREROLLED)
511         return MCIERR_UNSUPPORTED_FUNCTION;
512
513         pSeq->tkBase = lpPreroll->tkBase;
514         pSeq->tkEnd = lpPreroll->tkEnd;
515
516     if (pSeq->hmidi)
517     {
518         // Recollect buffers from MMSYSTEM back into free queue
519         //
520         pSeq->uState = SEQ_S_RESET;
521         midiOutReset(pSeq->hmidi);
522
523                 while (pSeq->uBuffersInMMSYSTEM)
524                         Sleep(0);
525     }
526     
527     pSeq->uBuffersInMMSYSTEM = 0;
528     pSeq->uState = SEQ_S_PREROLLING;
529     
530     //
531     // We've successfully opened the file and all of the tracks; now
532     // open the MIDI device and set the time division.
533     //
534     // NOTE: seqPreroll is equivalent to seek; device might already be open
535     //
536     if (NULL == pSeq->hmidi)
537     {
538         uDeviceID = pSeq->uDeviceID;
539         if ((mmrc = midiStreamOpen(&pSeq->hmidi,
540                                    &uDeviceID,
541                                    1,
542                                    (DWORD)seqMIDICallback,
543                                    0,
544                                    CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
545         {
546             pSeq->hmidi = NULL;
547             goto seq_Preroll_Cleanup;
548         }
549         
550         mptd.cbStruct  = sizeof(mptd);
551         mptd.dwTimeDiv = pSeq->dwTimeDivision;
552         if ((mmrc = midiStreamProperty(
553                                        (HMIDI)pSeq->hmidi,
554                                        (LPBYTE)&mptd,
555                                        MIDIPROP_SET|MIDIPROP_TIMEDIV)) != MMSYSERR_NOERROR)
556         {
557             mprintf((1, "midiStreamProperty() -> %04X\n", (WORD)mmrc));
558             midiStreamClose(pSeq->hmidi);
559             pSeq->hmidi = NULL;
560             mmrc = MCIERR_DEVICE_NOT_READY;
561             goto seq_Preroll_Cleanup;
562         }
563     }
564
565     mmrc = MMSYSERR_NOERROR;
566
567     //
568     //  Allocate a preroll buffer.  Then if we don't have enough room for
569     //  all the preroll info, we make the buffer larger.  
570     //
571     if (!pSeq->lpmhPreroll)
572     {
573         cbPrerollBuffer = 4096;
574         lpmhPreroll = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE,
575                                                             cbPrerollBuffer);
576     }
577     else
578     {
579         cbPrerollBuffer = pSeq->cbPreroll;
580         lpmhPreroll = pSeq->lpmhPreroll;
581     }
582
583     lpmhPreroll->lpNext            = pSeq->lpmhFree;
584     lpmhPreroll->lpData            = (LPBYTE)lpmhPreroll + sizeof(MIDIHDR);
585     lpmhPreroll->dwBufferLength    = cbPrerollBuffer - sizeof(MIDIHDR);
586     lpmhPreroll->dwBytesRecorded   = 0;
587     lpmhPreroll->dwUser            = (DWORD)(UINT)pSeq;
588     lpmhPreroll->dwFlags           = 0;
589
590     do
591     {
592         smfrc = smfSeek(pSeq->hSmf, pSeq->tkBase, lpmhPreroll);
593         if( SMF_SUCCESS != smfrc )
594         {
595             if( ( SMF_NO_MEMORY != smfrc )  ||
596                 ( cbPrerollBuffer >= 32768L ) )
597             {
598                 mprintf((1, "smfSeek() returned %lu\n", (DWORD)smfrc));
599
600                 GlobalFreePtr(lpmhPreroll);
601                 pSeq->lpmhPreroll = NULL;
602
603                 mmrc = XlatSMFErr(smfrc);
604                 goto seq_Preroll_Cleanup;
605             }
606             else   //  Try to grow buffer.
607             {
608                 cbPrerollBuffer *= 2;
609                 lpmh = (LPMIDIHDR)GlobalReAllocPtr( lpmhPreroll, cbPrerollBuffer, 0 );
610                 if( NULL == lpmh )
611                 {
612                     mprintf((1,"seqPreroll - realloc failed, aborting preroll.\n"));
613                     mmrc = MCIERR_OUT_OF_MEMORY;
614                     goto seq_Preroll_Cleanup;
615                 }
616
617                 lpmhPreroll = lpmh;
618                 lpmhPreroll->lpData = (LPBYTE)lpmhPreroll + sizeof(MIDIHDR);
619                 lpmhPreroll->dwBufferLength = cbPrerollBuffer - sizeof(MIDIHDR);
620
621                 pSeq->lpmhPreroll = lpmhPreroll;
622                 pSeq->cbPreroll = cbPrerollBuffer;
623             }
624         }
625     } while( SMF_SUCCESS != smfrc );
626
627     if (MMSYSERR_NOERROR != (mmrc = midiOutPrepareHeader(pSeq->hmidi, lpmhPreroll, sizeof(MIDIHDR))))
628     {
629         mprintf((1, "midiOutPrepare(preroll) -> %lu!\n", (DWORD)mmrc));
630
631         mmrc = MCIERR_DEVICE_NOT_READY;
632         goto seq_Preroll_Cleanup;
633     }
634
635     ++pSeq->uBuffersInMMSYSTEM;
636
637     if (MMSYSERR_NOERROR != (mmrc = midiStreamOut(pSeq->hmidi, lpmhPreroll, sizeof(MIDIHDR))))
638     {
639         mprintf((1, "midiStreamOut(preroll) -> %lu!\n", (DWORD)mmrc));
640
641         mmrc = MCIERR_DEVICE_NOT_READY;
642         --pSeq->uBuffersInMMSYSTEM;
643         goto seq_Preroll_Cleanup;
644     }
645     mprintf((1,"seqPreroll: midiStreamOut(0x%x,0x%lx,%u) returned %u.\n",pSeq->hmidi,lpmhPreroll,sizeof(MIDIHDR),mmrc));
646
647     pSeq->fdwSeq &= ~SEQ_F_EOF;
648     while (pSeq->lpmhFree)
649     {
650         lpmh = pSeq->lpmhFree;
651         pSeq->lpmhFree = lpmh->lpNext;
652
653         smfrc = smfReadEvents(pSeq->hSmf, lpmh, pSeq->tkEnd);
654         if (SMF_SUCCESS != smfrc && SMF_END_OF_FILE != smfrc)
655         {
656             mprintf((1, "SFP: smfReadEvents() -> %u\n", (UINT)smfrc));
657             mmrc = XlatSMFErr(smfrc);
658             goto seq_Preroll_Cleanup;
659         }
660
661         if (MMSYSERR_NOERROR != (mmrc = midiOutPrepareHeader(pSeq->hmidi, lpmh, sizeof(*lpmh))))
662         {
663             mprintf((1, "SFP: midiOutPrepareHeader failed\n"));
664             goto seq_Preroll_Cleanup;
665         }
666
667         if (MMSYSERR_NOERROR != (mmrc = midiStreamOut(pSeq->hmidi, lpmh, sizeof(*lpmh))))
668         {
669             mprintf((1, "SFP: midiStreamOut failed\n"));
670             goto seq_Preroll_Cleanup;
671         }
672
673         ++pSeq->uBuffersInMMSYSTEM; 
674
675         if (SMF_END_OF_FILE == smfrc)
676         {
677             pSeq->fdwSeq |= SEQ_F_EOF;
678             break;
679         }
680     } 
681
682 seq_Preroll_Cleanup:
683     if (MMSYSERR_NOERROR != mmrc)
684     {
685         pSeq->uState = SEQ_S_OPENED;
686         pSeq->fdwSeq &= ~SEQ_F_WAITING;
687     }
688     else
689     {
690         pSeq->uState = SEQ_S_PREROLLED;
691     }
692
693     return mmrc;
694 }
695
696 /***************************************************************************
697 *  
698 * seqStart
699 *
700 * Starts playback at the current position.
701 *       
702 ***************************************************************************/
703 MMRESULT FNLOCAL seqStart(
704     PSEQ                    pSeq)
705 {
706     Assert(NULL != pSeq);
707
708     if (SEQ_S_PREROLLED != pSeq->uState)
709     {
710         mprintf((1, "seqStart(): State is wrong! [%u]\n", pSeq->uState));
711         return MCIERR_UNSUPPORTED_FUNCTION;
712     }
713
714     pSeq->uState = SEQ_S_PLAYING;
715
716     return midiStreamRestart(pSeq->hmidi);
717 }
718
719 /***************************************************************************
720 *  
721 * seqPause
722 *
723 ***************************************************************************/
724 MMRESULT FNLOCAL seqPause(
725     PSEQ                    pSeq)
726 {
727     Assert(NULL != pSeq);
728     
729     if (SEQ_S_PLAYING != pSeq->uState)
730         return MCIERR_UNSUPPORTED_FUNCTION;
731
732     pSeq->uState = SEQ_S_PAUSED;
733     midiStreamPause(pSeq->hmidi);
734     
735     return MMSYSERR_NOERROR;
736 }
737
738 /***************************************************************************
739 *  
740 * seqRestart
741 *
742 ***************************************************************************/
743 MMRESULT FNLOCAL seqRestart(
744     PSEQ                    pSeq)
745 {
746     Assert(NULL != pSeq);
747
748     if (SEQ_S_PAUSED != pSeq->uState)
749         return MCIERR_UNSUPPORTED_FUNCTION;
750
751     pSeq->uState = SEQ_S_PLAYING;
752     midiStreamRestart(pSeq->hmidi);
753
754     return MMSYSERR_NOERROR;
755 }
756
757 /***************************************************************************
758 *  
759 * seqStop
760 *
761 * Totally stops playback of an instance.
762 *
763 ***************************************************************************/
764 MMRESULT FNLOCAL seqStop(
765     PSEQ                    pSeq)
766 {
767     Assert(NULL != pSeq);
768
769     /* Automatic success if we're already stopped
770     */
771     if (SEQ_S_PLAYING != pSeq->uState &&
772         SEQ_S_PAUSED != pSeq->uState)
773     {
774         pSeq->fdwSeq &= ~SEQ_F_WAITING;
775         return MMSYSERR_NOERROR;
776     }
777
778     pSeq->uState = SEQ_S_STOPPING;
779     pSeq->fdwSeq |= SEQ_F_WAITING;
780     
781     if (MMSYSERR_NOERROR != (pSeq->mmrcLastErr = midiStreamStop(pSeq->hmidi)))
782     {
783         mprintf((1, "midiOutStop() returned %lu in seqStop()!\n", (DWORD)pSeq->mmrcLastErr));
784         
785         pSeq->fdwSeq &= ~SEQ_F_WAITING;
786         return MCIERR_DEVICE_NOT_READY;
787     }
788
789         while (pSeq->uBuffersInMMSYSTEM)
790                 Sleep(0);
791     
792     return MMSYSERR_NOERROR;
793 }
794
795 /***************************************************************************
796 *  
797 * seqTime
798 *
799 ***************************************************************************/
800 MMRESULT FNLOCAL seqTime(
801     PSEQ                    pSeq,
802     PTICKS                  pTicks)
803 {
804     MMRESULT                mmr;
805     MMTIME                  mmt;
806     
807     Assert(pSeq != NULL);
808
809     if (SEQ_S_PLAYING != pSeq->uState &&
810         SEQ_S_PAUSED != pSeq->uState &&
811         SEQ_S_PREROLLING != pSeq->uState &&
812         SEQ_S_PREROLLED != pSeq->uState &&
813         SEQ_S_OPENED != pSeq->uState)
814     {
815         mprintf((1, "seqTime(): State wrong! [is %u]\n", pSeq->uState));
816         return MCIERR_UNSUPPORTED_FUNCTION;
817     }
818
819     *pTicks = 0;
820     if (SEQ_S_OPENED != pSeq->uState)
821     {
822         *pTicks = pSeq->tkBase;
823         if (SEQ_S_PREROLLED != pSeq->uState)
824         {
825             mmt.wType = TIME_TICKS;
826             mmr = midiStreamPosition(pSeq->hmidi, &mmt, sizeof(mmt));
827             if (MMSYSERR_NOERROR != mmr)
828             {
829                 mprintf((1, "midiStreamPosition() returned %lu\n", (DWORD)mmr));
830                 return MCIERR_DEVICE_NOT_READY;
831             }
832
833             *pTicks += mmt.u.ticks;
834         }
835     }
836
837     return MMSYSERR_NOERROR;
838 }
839                               
840 /***************************************************************************
841 *  
842 * seqMillisecsToTicks
843 *
844 * Given a millisecond offset in the output stream, returns the associated
845 * tick position.
846 *
847 ***************************************************************************/
848 TICKS FNLOCAL seqMillisecsToTicks(
849     PSEQ                    pSeq,
850     DWORD                   msOffset)
851 {
852     return smfMillisecsToTicks(pSeq->hSmf, msOffset);
853 }
854
855 /***************************************************************************
856 *  
857 * seqTicksToMillisecs
858 *
859 * Given a tick offset in the output stream, returns the associated
860 * millisecond position.
861 *
862 ***************************************************************************/
863 DWORD FNLOCAL seqTicksToMillisecs(
864     PSEQ                    pSeq,
865     TICKS                   tkOffset)
866 {
867     return smfTicksToMillisecs(pSeq->hSmf, tkOffset);
868 }
869
870 /***************************************************************************
871 *  
872 * seqMIDICallback
873 *
874 * Called by the system when a buffer is done
875 *
876 * dw1                       - The buffer that has completed playback.
877 *
878 ***************************************************************************/
879
880 PRIVATE void FAR PASCAL seqMIDICallback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
881 {
882         LPMIDIHDR                                       lpmh            = (LPMIDIHDR)dw1;
883     PSEQ                    pSeq;
884     MMRESULT                mmrc;
885     SMFRESULT               smfrc;
886         //DWORD vol;
887
888         if (uMsg != MOM_DONE)
889                 return;
890
891         Assert(NULL != lpmh);
892
893     pSeq = (PSEQ)(lpmh->dwUser);
894
895     Assert(pSeq != NULL);
896
897     --pSeq->uBuffersInMMSYSTEM;
898     
899         if (pSeq->uState == SEQ_S_NOFILE) 
900                 mprintf((1, "seqCallback: No file!!\n"));
901
902     if (SEQ_S_RESET == pSeq->uState)
903     {
904         // We're recollecting buffers from MMSYSTEM
905         //
906                 if (lpmh != pSeq->lpmhPreroll)
907                 {
908                 lpmh->lpNext   = pSeq->lpmhFree;
909                 pSeq->lpmhFree = lpmh;
910                 }
911
912         return;
913     }
914     
915
916     if ((SEQ_S_STOPPING == pSeq->uState) || (pSeq->fdwSeq & SEQ_F_EOF))
917     {
918         /*
919         ** Reached EOF, just put the buffer back on the free
920         ** list 
921         */
922                 if (lpmh != pSeq->lpmhPreroll)
923                 {
924                 lpmh->lpNext   = pSeq->lpmhFree;
925                 pSeq->lpmhFree = lpmh;
926                 }
927                         if (!pSeq->hmidi) 
928                                 mprintf((1, "seqCallback: NULL MIDI HANDLE.\n"));
929
930         if (MMSYSERR_NOERROR != (mmrc = midiOutUnprepareHeader(pSeq->hmidi, lpmh, sizeof(*lpmh))))
931         {
932             mprintf((1, "midiOutUnprepareHeader failed in seqBufferDone! (%lu)\n", (DWORD)mmrc));
933         }
934
935         if (0 == pSeq->uBuffersInMMSYSTEM)
936         {
937                                 int stop_loop=0;
938             mprintf((1, "seqBufferDone: normal sequencer shutdown.\n"));
939             
940             /* Totally done! Free device and notify.
941             */
942             midiStreamClose(pSeq->hmidi);
943             
944                                 if ((SEQ_S_STOPPING == pSeq->uState) && (pSeq->fdwSeq & SEQ_F_EOF) && LoopSong) {
945                                         stop_loop = 1;
946                                         mprintf((1, "seqMIDICallback: cancelling loop.\n"));
947                                 }
948             pSeq->hmidi = NULL;
949             pSeq->uState = SEQ_S_OPENED;
950             pSeq->mmrcLastErr = MMSYSERR_NOERROR;
951             pSeq->fdwSeq &= ~SEQ_F_WAITING;
952
953                                 if ((pSeq->fdwSeq & SEQ_F_EOF) && LoopSong && !stop_loop)
954                                         wmidi_play(); 
955         }
956     }
957     else
958     {
959         /*
960         ** Not EOF yet; attempt to fill another buffer
961         */
962                   DWORD vol;
963
964         smfrc = smfReadEvents(pSeq->hSmf, lpmh, pSeq->tkEnd);
965         
966         switch(smfrc)
967         {
968             case SMF_SUCCESS:
969                 break;
970
971             case SMF_END_OF_FILE:
972                 pSeq->fdwSeq |= SEQ_F_EOF;
973                 smfrc = SMF_SUCCESS;
974                 break;
975
976             default:
977                 mprintf((1, "smfReadEvents returned %lu in callback!\n", (DWORD)smfrc));
978                 pSeq->uState = SEQ_S_STOPPING;
979                 break;
980         }
981
982         if (SMF_SUCCESS == smfrc)
983         {
984             ++pSeq->uBuffersInMMSYSTEM;
985
986                                 Assert(pSeq->hmidi != NULL);
987
988 //                              wmidi_deamp_song(wmidi_volume);
989                                 mmrc = midiOutSetVolume((HMIDIOUT)MIDI_MAPPER, wmidi_volume);   
990                                 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
991                                 midiOutGetVolume((HMIDIOUT)MIDI_MAPPER, &vol);
992
993             mmrc = midiStreamOut(pSeq->hmidi, lpmh, sizeof(*lpmh));
994                                 WMidi_NewStream++;
995             if (MMSYSERR_NOERROR != mmrc)
996             {
997                 mprintf((1, "seqBufferDone(): midiStreamOut() returned %lu!\n", (DWORD)mmrc));
998                 
999                 --pSeq->uBuffersInMMSYSTEM;
1000                 pSeq->uState = SEQ_S_STOPPING;
1001          --pSeq->uBuffersInMMSYSTEM;
1002                 pSeq->uState = SEQ_S_STOPPING;
1003             }
1004         }
1005     }
1006
1007 }
1008
1009 /***************************************************************************
1010 *  
1011 * XlatSMFErr
1012 *
1013 * Translates an error from the SMF layer into an appropriate MCI error.
1014 *
1015 ***************************************************************************/
1016 PRIVATE MMRESULT FNLOCAL XlatSMFErr(
1017     SMFRESULT               smfrc)
1018 {
1019     switch(smfrc)
1020     {
1021         case SMF_SUCCESS:
1022             return MMSYSERR_NOERROR;
1023
1024         case SMF_NO_MEMORY:
1025             return MCIERR_OUT_OF_MEMORY;
1026
1027         case SMF_INVALID_FILE:
1028         case SMF_OPEN_FAILED:
1029         case SMF_INVALID_TRACK:
1030             return MCIERR_INVALID_FILE;
1031
1032         default:
1033             return MCIERR_UNSUPPORTED_FUNCTION;
1034     }
1035 }
1036
1037
1038
1039
1040
1041