Subversion Repositories Kolibri OS

Rev

Rev 8647 | Rev 9133 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8645 turbocat 1
//
2
//      ID Engine
3
//      ID_SD.c - Sound Manager for Wolfenstein 3D
4
//      v1.2
5
//      By Jason Blochowiak
6
//
7
 
8
//
9
//      This module handles dealing with generating sound on the appropriate
10
//              hardware
11
//
12
//      Depends on: User Mgr (for parm checking)
13
//
14
//      Globals:
15
//              For User Mgr:
16
//                      SoundBlasterPresent - SoundBlaster card present?
17
//                      AdLibPresent - AdLib card present?
18
//                      SoundMode - What device is used for sound effects
19
//                              (Use SM_SetSoundMode() to set)
20
//                      MusicMode - What device is used for music
21
//                              (Use SM_SetMusicMode() to set)
22
//                      DigiMode - What device is used for digitized sound effects
23
//                              (Use SM_SetDigiDevice() to set)
24
//
25
//              For Cache Mgr:
26
//                      NeedsDigitized - load digitized sounds?
27
//                      NeedsMusic - load music?
28
//
29
 
30
#include "wl_def.h"
31
#include "SDL_mixer/SDL_mixer.h"
32
#if defined(GP2X_940)
33
#include "gp2x/fmopl.h"
34
#else
35
#include "mame/fmopl.h"
36
#endif
37
 
38
#pragma hdrstop
39
 
40
#define ORIGSAMPLERATE 7042
41
 
42
typedef struct
43
{
44
	char RIFF[4];
45
	longword filelenminus8;
46
	char WAVE[4];
47
	char fmt_[4];
48
	longword formatlen;
49
	word val0x0001;
50
	word channels;
51
	longword samplerate;
52
	longword bytespersec;
53
	word bytespersample;
54
	word bitspersample;
55
} headchunk;
56
 
57
typedef struct
58
{
59
	char chunkid[4];
60
	longword chunklength;
61
} wavechunk;
62
 
63
typedef struct
64
{
65
    uint32_t startpage;
66
    uint32_t length;
67
} digiinfo;
68
 
69
static Mix_Chunk *SoundChunks[ STARTMUSIC - STARTDIGISOUNDS];
70
static byte      *SoundBuffers[STARTMUSIC - STARTDIGISOUNDS];
71
 
72
globalsoundpos channelSoundPos[MIX_CHANNELS];
73
 
74
//      Global variables
75
        boolean         AdLibPresent,
76
                        SoundBlasterPresent,SBProPresent,
77
                        SoundPositioned;
78
        SDMode          SoundMode;
79
        SMMode          MusicMode;
80
        SDSMode         DigiMode;
81
static  byte          **SoundTable;
82
        int             DigiMap[LASTSOUND];
83
        int             DigiChannel[STARTMUSIC - STARTDIGISOUNDS];
84
 
85
//      Internal variables
86
static  boolean                 SD_Started;
87
static  boolean                 nextsoundpos;
88
static  soundnames              SoundNumber;
89
static  soundnames              DigiNumber;
90
static  word                    SoundPriority;
91
static  word                    DigiPriority;
92
static  int                     LeftPosition;
93
static  int                     RightPosition;
94
 
95
        word                    NumDigi;
96
static  digiinfo               *DigiList;
97
static  boolean                 DigiPlaying;
98
 
99
//      PC Sound variables
100
static  volatile byte           pcLastSample;
101
static  byte * volatile         pcSound;
102
static  longword                pcLengthLeft;
103
 
104
//      AdLib variables
105
static  byte * volatile         alSound;
106
static  byte                    alBlock;
107
static  longword                alLengthLeft;
108
static  longword                alTimeCount;
109
static  Instrument              alZeroInst;
110
 
111
//      Sequencer variables
112
static  volatile boolean        sqActive;
113
static  word                   *sqHack;
114
static  word                   *sqHackPtr;
115
static  int                     sqHackLen;
116
static  int                     sqHackSeqLen;
117
static  longword                sqHackTime;
118
 
119
 
120
static void SDL_SoundFinished(void)
121
{
122
	SoundNumber   = (soundnames)0;
123
	SoundPriority = 0;
124
}
125
 
126
 
127
#ifdef NOTYET
128
 
129
void SDL_turnOnPCSpeaker(word timerval);
130
#pragma aux SDL_turnOnPCSpeaker = \
131
        "mov    al,0b6h" \
132
        "out    43h,al" \
133
        "mov    al,bl" \
134
        "out    42h,al" \
135
        "mov    al,bh" \
136
        "out    42h,al" \
137
        "in     al,61h" \
138
        "or     al,3"   \
139
        "out    61h,al" \
140
        parm [bx] \
141
        modify exact [al]
142
 
143
void SDL_turnOffPCSpeaker();
144
#pragma aux SDL_turnOffPCSpeaker = \
145
        "in     al,61h" \
146
        "and    al,0fch" \
147
        "out    61h,al" \
148
        modify exact [al]
149
 
150
void SDL_setPCSpeaker(byte val);
151
#pragma aux SDL_setPCSpeaker = \
152
        "in     al,61h" \
153
        "and    al,0fch" \
154
        "or     al,ah" \
155
        "out    61h,al" \
156
        parm [ah] \
157
        modify exact [al]
158
 
159
void inline SDL_DoFX()
160
{
161
        if(pcSound)
162
        {
163
                if(*pcSound!=pcLastSample)
164
                {
165
                        pcLastSample=*pcSound;
166
 
167
                        if(pcLastSample)
168
                                SDL_turnOnPCSpeaker(pcLastSample*60);
169
                        else
170
                                SDL_turnOffPCSpeaker();
171
                }
172
                pcSound++;
173
                pcLengthLeft--;
174
                if(!pcLengthLeft)
175
                {
176
                        pcSound=0;
177
                        SoundNumber=(soundnames)0;
178
                        SoundPriority=0;
179
                        SDL_turnOffPCSpeaker();
180
                }
181
        }
182
 
183
        // [adlib sound stuff removed...]
184
}
185
 
186
static void SDL_DigitizedDoneInIRQ(void);
187
 
188
void inline SDL_DoFast()
189
{
190
        count_fx++;
191
        if(count_fx>=5)
192
        {
193
                count_fx=0;
194
 
195
                SDL_DoFX();
196
 
197
                count_time++;
198
                if(count_time>=2)
199
                {
200
                        TimeCount++;
201
                        count_time=0;
202
                }
203
        }
204
 
205
        // [adlib music and soundsource stuff removed...]
206
 
207
        TimerCount+=TimerDivisor;
208
        if(*((word *)&TimerCount+1))
209
        {
210
                *((word *)&TimerCount+1)=0;
211
                t0OldService();
212
        }
213
        else
214
        {
215
                outp(0x20,0x20);
216
        }
217
}
218
 
219
// Timer 0 ISR for 7000Hz interrupts
220
void __interrupt SDL_t0ExtremeAsmService(void)
221
{
222
        if(pcindicate)
223
        {
224
                if(pcSound)
225
                {
226
                        SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
227
                        pcLengthLeft--;
228
                        if(!pcLengthLeft)
229
                        {
230
                                pcSound=0;
231
                                SDL_turnOffPCSpeaker();
232
                                SDL_DigitizedDoneInIRQ();
233
                        }
234
                }
235
        }
236
        extreme++;
237
        if(extreme>=10)
238
        {
239
                extreme=0;
240
                SDL_DoFast();
241
        }
242
        else
243
                outp(0x20,0x20);
244
}
245
 
246
// Timer 0 ISR for 700Hz interrupts
247
void __interrupt SDL_t0FastAsmService(void)
248
{
249
        SDL_DoFast();
250
}
251
 
252
// Timer 0 ISR for 140Hz interrupts
253
void __interrupt SDL_t0SlowAsmService(void)
254
{
255
        count_time++;
256
        if(count_time>=2)
257
        {
258
                TimeCount++;
259
                count_time=0;
260
        }
261
 
262
        SDL_DoFX();
263
 
264
        TimerCount+=TimerDivisor;
265
        if(*((word *)&TimerCount+1))
266
        {
267
                *((word *)&TimerCount+1)=0;
268
                t0OldService();
269
        }
270
        else
271
                outp(0x20,0x20);
272
}
273
 
274
void SDL_IndicatePC(boolean ind)
275
{
276
        pcindicate=ind;
277
}
278
 
279
///////////////////////////////////////////////////////////////////////////
280
//
281
//      SDL_SetTimer0() - Sets system timer 0 to the specified speed
282
//
283
///////////////////////////////////////////////////////////////////////////
284
static void
285
SDL_SetTimer0(word speed)
286
{
287
#ifndef TPROF   // If using Borland's profiling, don't screw with the timer
288
//      _asm pushfd
289
        _asm cli
290
 
291
        outp(0x43,0x36);                                // Change timer 0
292
        outp(0x40,(byte)speed);
293
        outp(0x40,speed >> 8);
294
        // Kludge to handle special case for digitized PC sounds
295
        if (TimerDivisor == (1192030 / (TickBase * 100)))
296
                TimerDivisor = (1192030 / (TickBase * 10));
297
        else
298
                TimerDivisor = speed;
299
 
300
//      _asm popfd
301
        _asm    sti
302
#else
303
        TimerDivisor = 0x10000;
304
#endif
305
}
306
 
307
///////////////////////////////////////////////////////////////////////////
308
//
309
//      SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
310
//              interrupts generated by system timer 0 per second
311
//
312
///////////////////////////////////////////////////////////////////////////
313
static void
314
SDL_SetIntsPerSec(word ints)
315
{
316
        TimerRate = ints;
317
        SDL_SetTimer0(1192030 / ints);
318
}
319
 
320
static void
321
SDL_SetTimerSpeed(void)
322
{
323
        word    rate;
324
        void (_interrupt *isr)(void);
325
 
326
        if ((DigiMode == sds_PC) && DigiPlaying)
327
        {
328
                rate = TickBase * 100;
329
                isr = SDL_t0ExtremeAsmService;
330
        }
331
        else if ((MusicMode == smm_AdLib) || ((DigiMode == sds_SoundSource) && DigiPlaying)     )
332
        {
333
                rate = TickBase * 10;
334
                isr = SDL_t0FastAsmService;
335
        }
336
        else
337
        {
338
                rate = TickBase * 2;
339
                isr = SDL_t0SlowAsmService;
340
        }
341
 
342
        if (rate != TimerRate)
343
        {
344
                _dos_setvect(8,isr);
345
                SDL_SetIntsPerSec(rate);
346
                TimerRate = rate;
347
        }
348
}
349
 
350
//
351
//      PC Sound code
352
//
353
 
354
///////////////////////////////////////////////////////////////////////////
355
//
356
//      SDL_PCPlaySample() - Plays the specified sample on the PC speaker
357
//
358
///////////////////////////////////////////////////////////////////////////
359
#ifdef  _MUSE_
360
void
361
#else
362
static void
363
#endif
364
SDL_PCPlaySample(byte *data,longword len,boolean inIRQ)
365
{
366
        if(!inIRQ)
367
        {
368
//              _asm    pushfd
369
                _asm    cli
370
        }
371
 
372
        SDL_IndicatePC(true);
373
 
374
        pcLengthLeft = len;
375
        pcSound = (volatile byte *)data;
376
 
377
        if(!inIRQ)
378
        {
379
//              _asm    popfd
380
                _asm    sti
381
        }
382
}
383
 
384
///////////////////////////////////////////////////////////////////////////
385
//
386
//      SDL_PCStopSample() - Stops a sample playing on the PC speaker
387
//
388
///////////////////////////////////////////////////////////////////////////
389
#ifdef  _MUSE_
390
void
391
#else
392
static void
393
#endif
394
SDL_PCStopSampleInIRQ(void)
395
{
396
        pcSound = 0;
397
 
398
        SDL_IndicatePC(false);
399
 
400
        _asm    in      al,0x61                 // Turn the speaker off
401
        _asm    and     al,0xfd                 // ~2
402
        _asm    out     0x61,al
403
}
404
 
405
///////////////////////////////////////////////////////////////////////////
406
//
407
//      SDL_PCPlaySound() - Plays the specified sound on the PC speaker
408
//
409
///////////////////////////////////////////////////////////////////////////
410
#ifdef  _MUSE_
411
void
412
#else
413
static void
414
#endif
415
SDL_PCPlaySound(PCSound *sound)
416
{
417
//      _asm    pushfd
418
        _asm    cli
419
 
420
        pcLastSample = -1;
421
        pcLengthLeft = sound->common.length;
422
        pcSound = sound->data;
423
 
424
//      _asm    popfd
425
        _asm    sti
426
}
427
 
428
///////////////////////////////////////////////////////////////////////////
429
//
430
//      SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
431
//
432
///////////////////////////////////////////////////////////////////////////
433
#ifdef  _MUSE_
434
void
435
#else
436
static void
437
#endif
438
SDL_PCStopSound(void)
439
{
440
//      _asm    pushfd
441
        _asm    cli
442
 
443
        pcSound = 0;
444
 
445
        _asm    in      al,0x61                 // Turn the speaker off
446
        _asm    and     al,0xfd                 // ~2
447
        _asm    out     0x61,al
448
 
449
//      _asm    popfd
450
        _asm    sti
451
}
452
 
453
///////////////////////////////////////////////////////////////////////////
454
//
455
//      SDL_ShutPC() - Turns off the pc speaker
456
//
457
///////////////////////////////////////////////////////////////////////////
458
static void
459
SDL_ShutPC(void)
460
{
461
//      _asm    pushfd
462
        _asm    cli
463
 
464
        pcSound = 0;
465
 
466
        _asm    in      al,0x61                 // Turn the speaker & gate off
467
        _asm    and     al,0xfc                 // ~3
468
        _asm    out     0x61,al
469
 
470
//      _asm    popfd
471
        _asm    sti
472
}
473
 
474
#endif
475
 
476
void
477
SD_StopDigitized(void)
478
{
479
    DigiPlaying = false;
480
    DigiNumber = (soundnames) 0;
481
    DigiPriority = 0;
482
    SoundPositioned = false;
483
    if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
484
        SDL_SoundFinished();
485
 
486
    switch (DigiMode)
487
    {
488
        case sds_PC:
489
//            SDL_PCStopSampleInIRQ();
490
            break;
491
        case sds_SoundBlaster:
492
//            SDL_SBStopSampleInIRQ();
493
            Mix_HaltChannel(-1);
494
            break;
495
    }
496
}
497
 
498
int SD_GetChannelForDigi(int which)
499
{
500
    if(DigiChannel[which] != -1) return DigiChannel[which];
501
 
502
    int channel = Mix_GroupAvailable(1);
503
    if(channel == -1) channel = Mix_GroupOldest(1);
504
    if(channel == -1)           // All sounds stopped in the meantime?
505
        return Mix_GroupAvailable(1);
506
    return channel;
507
}
508
 
509
void SD_SetPosition(int channel, int leftpos, int rightpos)
510
{
511
    if((leftpos < 0) || (leftpos > 15) || (rightpos < 0) || (rightpos > 15)
512
            || ((leftpos == 15) && (rightpos == 15)))
513
        Quit("SD_SetPosition: Illegal position");
514
 
515
    switch (DigiMode)
516
    {
517
        case sds_SoundBlaster:
518
//            SDL_PositionSBP(leftpos,rightpos);
519
            Mix_SetPanning(channel, ((15 - leftpos) << 4) + 15,
520
                ((15 - rightpos) << 4) + 15);
521
            break;
522
    }
523
}
524
 
525
Sint16 GetSample(float csample, byte *samples, int size)
526
{
527
    float s0=0, s1=0, s2=0;
528
    int cursample = (int) csample;
529
    float sf = csample - (float) cursample;
530
 
531
    if(cursample-1 >= 0) s0 = (float) (samples[cursample-1] - 128);
532
    s1 = (float) (samples[cursample] - 128);
533
    if(cursample+1 < size) s2 = (float) (samples[cursample+1] - 128);
534
 
535
    float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2;
536
    int32_t intval = (int32_t) (val * 256);
537
    if(intval < -32768) intval = -32768;
538
    else if(intval > 32767) intval = 32767;
539
    return (Sint16) intval;
540
}
541
 
542
void SD_PrepareSound(int which)
543
{
544
    if(DigiList == NULL)
545
        Quit("SD_PrepareSound(%i): DigiList not initialized!\n", which);
546
 
547
    int page = DigiList[which].startpage;
548
    int size = DigiList[which].length;
549
 
550
    byte *origsamples = PM_GetSound(page);
551
    if(origsamples + size >= PM_GetEnd())
552
        Quit("SD_PrepareSound(%i): Sound reaches out of page file!\n", which);
553
 
554
    int destsamples = (int) ((float) size * (float) param_samplerate
555
        / (float) ORIGSAMPLERATE);
556
 
557
    byte *wavebuffer = (byte *) malloc(sizeof(headchunk) + sizeof(wavechunk)
558
        + destsamples * 2);     // dest are 16-bit samples
559
    if(wavebuffer == NULL)
560
        Quit("Unable to allocate wave buffer for sound %i!\n", which);
561
 
562
    headchunk head = {{'R','I','F','F'}, 0, {'W','A','V','E'},
563
        {'f','m','t',' '}, 0x10, 0x0001, 1, param_samplerate, param_samplerate*2, 2, 16};
564
    wavechunk dhead = {{'d', 'a', 't', 'a'}, destsamples*2};
565
    head.filelenminus8 = sizeof(head) + destsamples*2;  // (sizeof(dhead)-8 = 0)
566
    memcpy(wavebuffer, &head, sizeof(head));
567
    memcpy(wavebuffer+sizeof(head), &dhead, sizeof(dhead));
568
 
569
    // alignment is correct, as wavebuffer comes from malloc
570
    // and sizeof(headchunk) % 4 == 0 and sizeof(wavechunk) % 4 == 0
571
    Sint16 *newsamples = (Sint16 *)(void *) (wavebuffer + sizeof(headchunk)
572
        + sizeof(wavechunk));
573
    float cursample = 0.F;
574
    float samplestep = (float) ORIGSAMPLERATE / (float) param_samplerate;
575
    for(int i=0; i
576
    {
577
        newsamples[i] = GetSample((float)size * (float)i / (float)destsamples,
578
            origsamples, size);
579
    }
580
    SoundBuffers[which] = wavebuffer;
581
 
582
    SoundChunks[which] = Mix_LoadWAV_RW(SDL_RWFromMem(wavebuffer,
583
        sizeof(headchunk) + sizeof(wavechunk) + destsamples * 2), 1);
584
}
585
 
586
int SD_PlayDigitized(word which,int leftpos,int rightpos)
587
{
588
    if (!DigiMode)
589
        return 0;
590
 
591
    if (which >= NumDigi)
592
        Quit("SD_PlayDigitized: bad sound number %i", which);
593
 
594
    int channel = SD_GetChannelForDigi(which);
595
    SD_SetPosition(channel, leftpos,rightpos);
596
 
597
    DigiPlaying = true;
598
 
599
    Mix_Chunk *sample = SoundChunks[which];
600
    if(sample == NULL)
601
    {
602
        printf("SoundChunks[%i] is NULL!\n", which);
603
        return 0;
604
    }
605
 
606
    if(Mix_PlayChannel(channel, sample, 0) == -1)
607
    {
608
        printf("Unable to play sound: %s\n", Mix_GetError());
609
        return 0;
610
    }
611
 
612
    return channel;
613
}
614
 
615
void SD_ChannelFinished(int channel)
616
{
617
    channelSoundPos[channel].valid = 0;
618
}
619
 
620
void
621
SD_SetDigiDevice(SDSMode mode)
622
{
623
    boolean devicenotpresent;
624
 
625
    if (mode == DigiMode)
626
        return;
627
 
628
    SD_StopDigitized();
629
 
630
    devicenotpresent = false;
631
    switch (mode)
632
    {
633
        case sds_SoundBlaster:
634
            if (!SoundBlasterPresent)
635
                devicenotpresent = true;
636
            break;
637
    }
638
 
639
    if (!devicenotpresent)
640
    {
641
        DigiMode = mode;
642
 
643
#ifdef NOTYET
644
        SDL_SetTimerSpeed();
645
#endif
646
    }
647
}
648
 
649
void
650
SDL_SetupDigi(void)
651
{
652
    // Correct padding enforced by PM_Startup()
653
    word *soundInfoPage = (word *) (void *) PM_GetPage(ChunksInFile-1);
654
    NumDigi = (word) PM_GetPageSize(ChunksInFile - 1) / 4;
655
 
656
    DigiList = (digiinfo *) malloc(NumDigi * sizeof(digiinfo));
657
    int i;
658
    for(i = 0; i < NumDigi; i++)
659
    {
660
        // Calculate the size of the digi from the sizes of the pages between
661
        // the start page and the start page of the next sound
662
 
663
        DigiList[i].startpage = soundInfoPage[i * 2];
664
        if((int) DigiList[i].startpage >= ChunksInFile - 1)
665
        {
666
            NumDigi = i;
667
            break;
668
        }
669
 
670
        int lastPage;
671
        if(i < NumDigi - 1)
672
        {
673
            lastPage = soundInfoPage[i * 2 + 2];
674
            if(lastPage == 0 || lastPage + PMSoundStart > ChunksInFile - 1) lastPage = ChunksInFile - 1;
675
            else lastPage += PMSoundStart;
676
        }
677
        else lastPage = ChunksInFile - 1;
678
 
679
        int size = 0;
680
        for(int page = PMSoundStart + DigiList[i].startpage; page < lastPage; page++)
681
            size += PM_GetPageSize(page);
682
 
683
        // Don't include padding of sound info page, if padding was added
684
        if(lastPage == ChunksInFile - 1 && PMSoundInfoPagePadded) size--;
685
 
686
        // Patch lower 16-bit of size with size from sound info page.
687
        // The original VSWAP contains padding which is included in the page size,
688
        // but not included in the 16-bit size. So we use the more precise value.
689
        if((size & 0xffff0000) != 0 && (size & 0xffff) < soundInfoPage[i * 2 + 1])
690
            size -= 0x10000;
691
        size = (size & 0xffff0000) | soundInfoPage[i * 2 + 1];
692
 
693
        DigiList[i].length = size;
694
    }
695
 
696
    for(i = 0; i < LASTSOUND; i++)
697
    {
698
        DigiMap[i] = -1;
699
        DigiChannel[i] = -1;
700
    }
701
}
702
 
703
//      AdLib Code
704
 
705
///////////////////////////////////////////////////////////////////////////
706
//
707
//      SDL_ALStopSound() - Turns off any sound effects playing through the
708
//              AdLib card
709
//
710
///////////////////////////////////////////////////////////////////////////
711
static void
712
SDL_ALStopSound(void)
713
{
714
    alSound = 0;
715
    alOut(alFreqH + 0, 0);
716
}
717
 
718
static void
719
SDL_AlSetFXInst(Instrument *inst)
720
{
721
    byte c,m;
722
 
723
    m = 0;      // modulator cell for channel 0
724
    c = 3;      // carrier cell for channel 0
725
    alOut(m + alChar,inst->mChar);
726
    alOut(m + alScale,inst->mScale);
727
    alOut(m + alAttack,inst->mAttack);
728
    alOut(m + alSus,inst->mSus);
729
    alOut(m + alWave,inst->mWave);
730
    alOut(c + alChar,inst->cChar);
731
    alOut(c + alScale,inst->cScale);
732
    alOut(c + alAttack,inst->cAttack);
733
    alOut(c + alSus,inst->cSus);
734
    alOut(c + alWave,inst->cWave);
735
 
736
    // Note: Switch commenting on these lines for old MUSE compatibility
737
//    alOutInIRQ(alFeedCon,inst->nConn);
738
    alOut(alFeedCon,0);
739
}
740
 
741
///////////////////////////////////////////////////////////////////////////
742
//
743
//      SDL_ALPlaySound() - Plays the specified sound on the AdLib card
744
//
745
///////////////////////////////////////////////////////////////////////////
746
static void
747
SDL_ALPlaySound(AdLibSound *sound)
748
{
749
    Instrument      *inst;
750
    byte            *data;
751
 
752
    SDL_ALStopSound();
753
 
754
    alLengthLeft = sound->common.length;
755
    data = sound->data;
756
    alBlock = ((sound->block & 7) << 2) | 0x20;
757
    inst = &sound->inst;
758
 
759
    if (!(inst->mSus | inst->cSus))
760
    {
761
        Quit("SDL_ALPlaySound() - Bad instrument");
762
    }
763
 
764
    SDL_AlSetFXInst(inst);
765
    alSound = (byte *)data;
766
}
767
 
768
///////////////////////////////////////////////////////////////////////////
769
//
770
//      SDL_ShutAL() - Shuts down the AdLib card for sound effects
771
//
772
///////////////////////////////////////////////////////////////////////////
773
static void
774
SDL_ShutAL(void)
775
{
776
    alSound = 0;
777
    alOut(alEffects,0);
778
    alOut(alFreqH + 0,0);
779
    SDL_AlSetFXInst(&alZeroInst);
780
}
781
 
782
///////////////////////////////////////////////////////////////////////////
783
//
784
//      SDL_CleanAL() - Totally shuts down the AdLib card
785
//
786
///////////////////////////////////////////////////////////////////////////
787
static void
788
SDL_CleanAL(void)
789
{
790
    int     i;
791
 
792
    alOut(alEffects,0);
793
    for (i = 1; i < 0xf5; i++)
794
        alOut(i, 0);
795
}
796
 
797
///////////////////////////////////////////////////////////////////////////
798
//
799
//      SDL_StartAL() - Starts up the AdLib card for sound effects
800
//
801
///////////////////////////////////////////////////////////////////////////
802
static void
803
SDL_StartAL(void)
804
{
805
    alOut(alEffects, 0);
806
    SDL_AlSetFXInst(&alZeroInst);
807
}
808
 
809
///////////////////////////////////////////////////////////////////////////
810
//
811
//      SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
812
//              emulating an AdLib) present
813
//
814
///////////////////////////////////////////////////////////////////////////
815
static boolean
816
SDL_DetectAdLib(void)
817
{
818
    for (int i = 1; i <= 0xf5; i++)       // Zero all the registers
819
        alOut(i, 0);
820
 
821
    alOut(1, 0x20);             // Set WSE=1
822
//    alOut(8, 0);                // Set CSM=0 & SEL=0
823
 
824
    return true;
825
}
826
 
827
////////////////////////////////////////////////////////////////////////////
828
//
829
//      SDL_ShutDevice() - turns off whatever device was being used for sound fx
830
//
831
////////////////////////////////////////////////////////////////////////////
832
static void
833
SDL_ShutDevice(void)
834
{
835
    switch (SoundMode)
836
    {
837
        case sdm_PC:
838
//            SDL_ShutPC();
839
            break;
840
        case sdm_AdLib:
841
            SDL_ShutAL();
842
            break;
843
    }
844
    SoundMode = sdm_Off;
845
}
846
 
847
///////////////////////////////////////////////////////////////////////////
848
//
849
//      SDL_CleanDevice() - totally shuts down all sound devices
850
//
851
///////////////////////////////////////////////////////////////////////////
852
static void
853
SDL_CleanDevice(void)
854
{
855
    if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
856
        SDL_CleanAL();
857
}
858
 
859
///////////////////////////////////////////////////////////////////////////
860
//
861
//      SDL_StartDevice() - turns on whatever device is to be used for sound fx
862
//
863
///////////////////////////////////////////////////////////////////////////
864
static void
865
SDL_StartDevice(void)
866
{
867
    switch (SoundMode)
868
    {
869
        case sdm_AdLib:
870
            SDL_StartAL();
871
            break;
872
    }
873
    SoundNumber = (soundnames) 0;
874
    SoundPriority = 0;
875
}
876
 
877
//      Public routines
878
 
879
///////////////////////////////////////////////////////////////////////////
880
//
881
//      SD_SetSoundMode() - Sets which sound hardware to use for sound effects
882
//
883
///////////////////////////////////////////////////////////////////////////
884
boolean
885
SD_SetSoundMode(SDMode mode)
886
{
887
    boolean result = false;
888
    word    tableoffset;
889
 
890
    SD_StopSound();
891
 
892
    if ((mode == sdm_AdLib) && !AdLibPresent)
893
        mode = sdm_PC;
894
 
895
    switch (mode)
896
    {
897
        case sdm_Off:
898
            tableoffset = STARTADLIBSOUNDS;
899
            result = true;
900
            break;
901
        case sdm_PC:
902
            tableoffset = STARTPCSOUNDS;
903
            result = true;
904
            break;
905
        case sdm_AdLib:
906
            tableoffset = STARTADLIBSOUNDS;
907
            if (AdLibPresent)
908
                result = true;
909
            break;
910
        default:
911
            Quit("SD_SetSoundMode: Invalid sound mode %i", mode);
912
            return false;
913
    }
914
    SoundTable = &audiosegs[tableoffset];
915
 
916
    if (result && (mode != SoundMode))
917
    {
918
        SDL_ShutDevice();
919
        SoundMode = mode;
920
        SDL_StartDevice();
921
    }
922
 
923
    return(result);
924
}
925
 
926
///////////////////////////////////////////////////////////////////////////
927
//
928
//      SD_SetMusicMode() - sets the device to use for background music
929
//
930
///////////////////////////////////////////////////////////////////////////
931
boolean
932
SD_SetMusicMode(SMMode mode)
933
{
934
    boolean result = false;
935
 
936
    SD_FadeOutMusic();
937
    while (SD_MusicPlaying())
9097 turbocat 938
        uSDL_Delay(5);
8645 turbocat 939
 
940
    switch (mode)
941
    {
942
        case smm_Off:
943
            result = true;
944
            break;
945
        case smm_AdLib:
946
            if (AdLibPresent)
947
                result = true;
948
            break;
949
    }
950
 
951
    if (result)
952
        MusicMode = mode;
953
 
954
//    SDL_SetTimerSpeed();
955
 
956
    return(result);
957
}
958
 
959
int numreadysamples = 0;
960
byte *curAlSound = 0;
961
byte *curAlSoundPtr = 0;
962
longword curAlLengthLeft = 0;
963
int soundTimeCounter = 5;
964
int samplesPerMusicTick;
965
 
966
void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len)
967
{
968
    int stereolen = len>>1;
969
    int sampleslen = stereolen>>1;
970
    INT16 *stream16 = (INT16 *) (void *) stream;    // expect correct alignment
971
 
972
    while(1)
973
    {
974
        if(numreadysamples)
975
        {
976
            if(numreadysamples
977
            {
978
                YM3812UpdateOne(0, stream16, numreadysamples);
979
                stream16 += numreadysamples*2;
980
                sampleslen -= numreadysamples;
981
            }
982
            else
983
            {
984
                YM3812UpdateOne(0, stream16, sampleslen);
985
                numreadysamples -= sampleslen;
986
                return;
987
            }
988
        }
989
        soundTimeCounter--;
990
        if(!soundTimeCounter)
991
        {
992
            soundTimeCounter = 5;
993
            if(curAlSound != alSound)
994
            {
995
                curAlSound = curAlSoundPtr = alSound;
996
                curAlLengthLeft = alLengthLeft;
997
            }
998
            if(curAlSound)
999
            {
1000
                if(*curAlSoundPtr)
1001
                {
1002
                    alOut(alFreqL, *curAlSoundPtr);
1003
                    alOut(alFreqH, alBlock);
1004
                }
1005
                else alOut(alFreqH, 0);
1006
                curAlSoundPtr++;
1007
                curAlLengthLeft--;
1008
                if(!curAlLengthLeft)
1009
                {
1010
                    curAlSound = alSound = 0;
1011
                    SoundNumber = (soundnames) 0;
1012
                    SoundPriority = 0;
1013
                    alOut(alFreqH, 0);
1014
                }
1015
            }
1016
        }
1017
        if(sqActive)
1018
        {
1019
            do
1020
            {
1021
                if(sqHackTime > alTimeCount) break;
1022
                sqHackTime = alTimeCount + *(sqHackPtr+1);
1023
                alOut(*(byte *) sqHackPtr, *(((byte *) sqHackPtr)+1));
1024
                sqHackPtr += 2;
1025
                sqHackLen -= 4;
1026
            }
1027
            while(sqHackLen>0);
1028
            alTimeCount++;
1029
            if(!sqHackLen)
1030
            {
1031
                sqHackPtr = sqHack;
1032
                sqHackLen = sqHackSeqLen;
1033
                sqHackTime = 0;
1034
                alTimeCount = 0;
1035
            }
1036
        }
1037
        numreadysamples = samplesPerMusicTick;
1038
    }
1039
}
1040
 
1041
///////////////////////////////////////////////////////////////////////////
1042
//
1043
//      SD_Startup() - starts up the Sound Mgr
1044
//              Detects all additional sound hardware and installs my ISR
1045
//
1046
///////////////////////////////////////////////////////////////////////////
1047
void
1048
SD_Startup(void)
1049
{
1050
    int     i;
1051
 
1052
    if (SD_Started)
1053
        return;
1054
 
1055
    if(Mix_OpenAudio(param_samplerate, AUDIO_S16, 2, param_audiobuffer))
1056
    {
1057
        printf("Unable to open audio: %s\n", Mix_GetError());
1058
        return;
1059
    }
1060
 
1061
    Mix_ReserveChannels(2);  // reserve player and boss weapon channels
1062
    Mix_GroupChannels(2, MIX_CHANNELS-1, 1); // group remaining channels
1063
 
1064
    // Init music
1065
 
1066
    samplesPerMusicTick = param_samplerate / 700;    // SDL_t0FastAsmService played at 700Hz
1067
 
1068
    if(YM3812Init(1,3579545,param_samplerate))
1069
    {
1070
        printf("Unable to create virtual OPL!!\n");
1071
    }
1072
 
1073
    for(i=1;i<0xf6;i++)
1074
        YM3812Write(0,i,0);
1075
 
1076
    YM3812Write(0,1,0x20); // Set WSE=1
1077
//    YM3812Write(0,8,0); // Set CSM=0 & SEL=0		 // already set in for statement
1078
 
1079
    Mix_HookMusic(SDL_IMFMusicPlayer, 0);
1080
    Mix_ChannelFinished(SD_ChannelFinished);
1081
    AdLibPresent = true;
1082
    SoundBlasterPresent = true;
1083
 
1084
    alTimeCount = 0;
1085
 
1086
    SD_SetSoundMode(sdm_Off);
1087
    SD_SetMusicMode(smm_Off);
1088
 
1089
    SDL_SetupDigi();
1090
 
1091
    SD_Started = true;
1092
}
1093
 
1094
///////////////////////////////////////////////////////////////////////////
1095
//
1096
//      SD_Shutdown() - shuts down the Sound Mgr
1097
//              Removes sound ISR and turns off whatever sound hardware was active
1098
//
1099
///////////////////////////////////////////////////////////////////////////
1100
void
1101
SD_Shutdown(void)
1102
{
1103
    if (!SD_Started)
1104
        return;
1105
 
1106
    SD_MusicOff();
1107
    SD_StopSound();
1108
 
1109
    for(int i = 0; i < STARTMUSIC - STARTDIGISOUNDS; i++)
1110
    {
1111
        if(SoundChunks[i]) Mix_FreeChunk(SoundChunks[i]);
1112
        if(SoundBuffers[i]) free(SoundBuffers[i]);
1113
    }
1114
 
1115
    free(DigiList);
1116
 
1117
    SD_Started = false;
8647 turbocat 1118
    #ifdef _KOLIBRI
8646 turbocat 1119
    Mix_CloseAudio();
8647 turbocat 1120
    #endif
8645 turbocat 1121
}
1122
 
1123
///////////////////////////////////////////////////////////////////////////
1124
//
1125
//      SD_PositionSound() - Sets up a stereo imaging location for the next
1126
//              sound to be played. Each channel ranges from 0 to 15.
1127
//
1128
///////////////////////////////////////////////////////////////////////////
1129
void
1130
SD_PositionSound(int leftvol,int rightvol)
1131
{
1132
    LeftPosition = leftvol;
1133
    RightPosition = rightvol;
1134
    nextsoundpos = true;
1135
}
1136
 
1137
///////////////////////////////////////////////////////////////////////////
1138
//
1139
//      SD_PlaySound() - plays the specified sound on the appropriate hardware
1140
//
1141
///////////////////////////////////////////////////////////////////////////
1142
boolean
1143
SD_PlaySound(soundnames sound)
1144
{
1145
    boolean         ispos;
1146
    SoundCommon     *s;
1147
    int             lp,rp;
1148
 
1149
    lp = LeftPosition;
1150
    rp = RightPosition;
1151
    LeftPosition = 0;
1152
    RightPosition = 0;
1153
 
1154
    ispos = nextsoundpos;
1155
    nextsoundpos = false;
1156
 
1157
    if (sound == -1 || (DigiMode == sds_Off && SoundMode == sdm_Off))
1158
        return 0;
1159
 
1160
    s = (SoundCommon *) SoundTable[sound];
1161
 
1162
    if ((SoundMode != sdm_Off) && !s)
1163
            Quit("SD_PlaySound() - Uncached sound");
1164
 
1165
    if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
1166
    {
1167
        if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
1168
        {
1169
#ifdef NOTYET
1170
            if (s->priority < SoundPriority)
1171
                return 0;
1172
 
1173
            SDL_PCStopSound();
1174
 
1175
            SD_PlayDigitized(DigiMap[sound],lp,rp);
1176
            SoundPositioned = ispos;
1177
            SoundNumber = sound;
1178
            SoundPriority = s->priority;
1179
#else
1180
            return 0;
1181
#endif
1182
        }
1183
        else
1184
        {
1185
#ifdef NOTYET
1186
            if (s->priority < DigiPriority)
1187
                return(false);
1188
#endif
1189
 
1190
            int channel = SD_PlayDigitized(DigiMap[sound], lp, rp);
1191
            SoundPositioned = ispos;
1192
            DigiNumber = sound;
1193
            DigiPriority = s->priority;
1194
            return channel + 1;
1195
        }
1196
 
1197
        return(true);
1198
    }
1199
 
1200
    if (SoundMode == sdm_Off)
1201
        return 0;
1202
 
1203
    if (!s->length)
1204
        Quit("SD_PlaySound() - Zero length sound");
1205
    if (s->priority < SoundPriority)
1206
        return 0;
1207
 
1208
    switch (SoundMode)
1209
    {
1210
        case sdm_PC:
1211
//            SDL_PCPlaySound((PCSound *)s);
1212
            break;
1213
        case sdm_AdLib:
1214
            SDL_ALPlaySound((AdLibSound *)s);
1215
            break;
1216
    }
1217
 
1218
    SoundNumber = sound;
1219
    SoundPriority = s->priority;
1220
 
1221
    return 0;
1222
}
1223
 
1224
///////////////////////////////////////////////////////////////////////////
1225
//
1226
//      SD_SoundPlaying() - returns the sound number that's playing, or 0 if
1227
//              no sound is playing
1228
//
1229
///////////////////////////////////////////////////////////////////////////
1230
 
1231
word
1232
SD_SoundPlaying(void)
1233
{
1234
    boolean result = false;
1235
 
1236
    switch (SoundMode)
1237
    {
1238
        case sdm_PC:
1239
            result = pcSound? true : false;
1240
            break;
1241
        case sdm_AdLib:
1242
            result = alSound? true : false;
1243
            break;
1244
    }
1245
 
1246
    if (result)
1247
        return(SoundNumber);
1248
    else
1249
        return(false);
1250
}
1251
 
1252
///////////////////////////////////////////////////////////////////////////
1253
//
1254
//      SD_StopSound() - if a sound is playing, stops it
1255
//
1256
///////////////////////////////////////////////////////////////////////////
1257
void
1258
SD_StopSound(void)
1259
{
1260
    if (DigiPlaying)
1261
        SD_StopDigitized();
1262
 
1263
    switch (SoundMode)
1264
    {
1265
        case sdm_PC:
1266
//            SDL_PCStopSound();
1267
            break;
1268
        case sdm_AdLib:
1269
            SDL_ALStopSound();
1270
            break;
1271
    }
1272
 
1273
    SoundPositioned = false;
1274
 
1275
    SDL_SoundFinished();
1276
}
1277
 
1278
///////////////////////////////////////////////////////////////////////////
1279
//
1280
//      SD_WaitSoundDone() - waits until the current sound is done playing
1281
//
1282
///////////////////////////////////////////////////////////////////////////
1283
void
1284
SD_WaitSoundDone(void)
1285
{
1286
    while (SD_SoundPlaying())
9097 turbocat 1287
        uSDL_Delay(5);
8645 turbocat 1288
}
1289
 
1290
///////////////////////////////////////////////////////////////////////////
1291
//
1292
//      SD_MusicOn() - turns on the sequencer
1293
//
1294
///////////////////////////////////////////////////////////////////////////
1295
void
1296
SD_MusicOn(void)
1297
{
1298
    sqActive = true;
1299
}
1300
 
1301
///////////////////////////////////////////////////////////////////////////
1302
//
1303
//      SD_MusicOff() - turns off the sequencer and any playing notes
1304
//      returns the last music offset for music continue
1305
//
1306
///////////////////////////////////////////////////////////////////////////
1307
int
1308
SD_MusicOff(void)
1309
{
1310
    word    i;
1311
 
1312
    sqActive = false;
1313
    switch (MusicMode)
1314
    {
1315
        case smm_AdLib:
1316
            alOut(alEffects, 0);
1317
            for (i = 0;i < sqMaxTracks;i++)
1318
                alOut(alFreqH + i + 1, 0);
1319
            break;
1320
    }
1321
 
1322
    return (int) (sqHackPtr-sqHack);
1323
}
1324
 
1325
///////////////////////////////////////////////////////////////////////////
1326
//
1327
//      SD_StartMusic() - starts playing the music pointed to
1328
//
1329
///////////////////////////////////////////////////////////////////////////
1330
void
1331
SD_StartMusic(int chunk)
1332
{
1333
    SD_MusicOff();
1334
 
1335
    if (MusicMode == smm_AdLib)
1336
    {
1337
        int32_t chunkLen = CA_CacheAudioChunk(chunk);
1338
        sqHack = (word *)(void *) audiosegs[chunk];     // alignment is correct
1339
        if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen;
1340
        else sqHackLen = sqHackSeqLen = *sqHack++;
1341
        sqHackPtr = sqHack;
1342
        sqHackTime = 0;
1343
        alTimeCount = 0;
1344
        SD_MusicOn();
1345
    }
1346
}
1347
 
1348
void
1349
SD_ContinueMusic(int chunk, int startoffs)
1350
{
1351
    SD_MusicOff();
1352
 
1353
    if (MusicMode == smm_AdLib)
1354
    {
1355
        int32_t chunkLen = CA_CacheAudioChunk(chunk);
1356
        sqHack = (word *)(void *) audiosegs[chunk];     // alignment is correct
1357
        if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen;
1358
        else sqHackLen = sqHackSeqLen = *sqHack++;
1359
        sqHackPtr = sqHack;
1360
 
1361
        if(startoffs >= sqHackLen)
1362
        {
1363
            Quit("SD_StartMusic: Illegal startoffs provided!");
1364
        }
1365
 
1366
        // fast forward to correct position
1367
        // (needed to reconstruct the instruments)
1368
 
1369
        for(int i = 0; i < startoffs; i += 2)
1370
        {
1371
            byte reg = *(byte *)sqHackPtr;
1372
            byte val = *(((byte *)sqHackPtr) + 1);
1373
            if(reg >= 0xb1 && reg <= 0xb8) val &= 0xdf;           // disable play note flag
1374
            else if(reg == 0xbd) val &= 0xe0;                     // disable drum flags
1375
 
1376
            alOut(reg,val);
1377
            sqHackPtr += 2;
1378
            sqHackLen -= 4;
1379
        }
1380
        sqHackTime = 0;
1381
        alTimeCount = 0;
1382
 
1383
        SD_MusicOn();
1384
    }
1385
}
1386
 
1387
///////////////////////////////////////////////////////////////////////////
1388
//
1389
//      SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
1390
//              to see if the fadeout is complete
1391
//
1392
///////////////////////////////////////////////////////////////////////////
1393
void
1394
SD_FadeOutMusic(void)
1395
{
1396
    switch (MusicMode)
1397
    {
1398
        case smm_AdLib:
1399
            // DEBUG - quick hack to turn the music off
1400
            SD_MusicOff();
1401
            break;
1402
    }
1403
}
1404
 
1405
///////////////////////////////////////////////////////////////////////////
1406
//
1407
//      SD_MusicPlaying() - returns true if music is currently playing, false if
1408
//              not
1409
//
1410
///////////////////////////////////////////////////////////////////////////
1411
boolean
1412
SD_MusicPlaying(void)
1413
{
1414
    boolean result;
1415
 
1416
    switch (MusicMode)
1417
    {
1418
        case smm_AdLib:
1419
            result = sqActive;
1420
            break;
1421
        default:
1422
            result = false;
1423
            break;
1424
    }
1425
 
1426
    return(result);
1427
}