Ticket #8198: skymusicpatch.txt

File skymusicpatch.txt, 22.3 KB (added by lavosspawn, 21 years ago)
Line 
1diff -Nu sky/cd_intro.cpp sky/cd_intro.cpp
2--- sky/cd_intro.cpp 2003-04-21 20:00:12.000000000 +0200
3+++ sky/cd_intro.cpp 2003-04-21 20:00:33.000000000 +0200
4@@ -822,7 +822,7 @@
5 cd2_seq_data_1 = _skyDisk->loadFile(cd_104, NULL);
6 WAIT_SEQUENCE; //103
7
8- //fn_start_music(2);
9+ _music->startMusic(2);
10 fnFadeDown(0);
11 COPY_SCREEN;
12 showScreen();
13diff -Nu sky/intro.cpp sky/intro.cpp
14--- sky/intro.cpp 2003-04-21 20:00:12.000000000 +0200
15+++ sky/intro.cpp 2003-04-21 20:00:33.000000000 +0200
16@@ -237,12 +237,12 @@
17 _workScreen = _skyDisk->loadFile(60112, NULL); //while virgin screen is up, load rev screen
18 _tempPal = _skyDisk->loadFile(60113, NULL);
19
20- //loadSectionMusic(0);
21+ _music->loadSectionMusic(0);
22
23 delay(3000); //keep virgin screen up for 3 seconds
24
25 //if (!isCDVersion(_gameVersion))
26- // fn_start_music();
27+ // _music->startMusic(1);
28
29 delay(3000); //and another 3 seconds.
30 fnFadeDown(0); //remove virgin screen
31diff -Nu sky/skychannel.cpp sky/skychannel.cpp
32--- sky/skychannel.cpp 1970-01-01 01:00:00.000000000 +0100
33+++ sky/skychannel.cpp 2003-04-21 20:00:33.000000000 +0200
34@@ -0,0 +1,288 @@
35+#include "skychannel.h"
36+#include "sound/fmopl.h"
37+
38+SkyChannel::SkyChannel(uint8 *pMusicData, uint16 startOfData, FM_OPL *pOpl)
39+{
40+ _musicData = pMusicData;
41+ _opl = pOpl;
42+ _channelData.startOfData = startOfData;
43+ _channelData.eventDataPtr = startOfData;
44+ _channelData.channelActive = 1;
45+ _channelData.freqDataSize = 2;
46+ _channelData.tremoVibro = 0;
47+ _channelData.assignedInstrument = 0xFF;
48+ _channelData.channelVolume = 0x7F;
49+ _channelData.nextEventTime = getNextEventTime();
50+
51+ _channelData.adlibChannelNumber = _channelData.lastCommand = _channelData.note =
52+ _channelData.adlibReg1 = _channelData.adlibReg2 = _channelData.freqOffset = 0;
53+ _channelData.frequency = 0;
54+ _channelData.instrumentData = NULL;
55+
56+ uint16 instrumentDataLoc = (_musicData[0x1206] << 8) | _musicData[0x1205];
57+ _instrumentMap = _musicData+instrumentDataLoc;
58+ _instruments = (InstrumentStruct*)(_instrumentMap+0x80);
59+
60+ _frequenceTable = (uint16*)(_musicData+0x7FE);
61+ _registerTable = _musicData+0xDFE;
62+ _opOutputTable = _musicData+0xE10;
63+ _adlibRegMirror = _musicData+0xF5F;
64+ _musicVolume = 0x100;
65+}
66+
67+void SkyChannel::updateVolume(uint16 pVolume) {
68+
69+ _musicVolume = pVolume;
70+}
71+
72+/* This class uses the same area for the register mirror as the original
73+ asm driver did (_musicData[0xF5F..0x105E]), so the cache is indeed shared
74+ by all instances of the class.
75+*/
76+void SkyChannel::setRegister(uint8 regNum, uint8 value) {
77+
78+ if (_adlibRegMirror[regNum] != value) {
79+ OPLWriteReg(_opl,regNum,value);
80+ _adlibRegMirror[regNum] = value;
81+ }
82+}
83+
84+void SkyChannel::stopNote(void) {
85+
86+ if (_channelData.note & 0x20) {
87+ _channelData.note &= ~0x20;
88+ setRegister(0xB0 | _channelData.adlibChannelNumber, _channelData.note);
89+ }
90+}
91+
92+int32 SkyChannel::getNextEventTime(void)
93+{
94+ int32 retV = 0;
95+ uint8 cnt, lVal;
96+ for (cnt = 0; cnt < 4; cnt++) {
97+ lVal = _musicData[_channelData.eventDataPtr];
98+ _channelData.eventDataPtr++;
99+ retV = (retV << 7) | (lVal & 0x7F);
100+ if (!(lVal & 0x80)) break;
101+ }
102+ if (lVal & 0x80) { // should never happen
103+ return -1;
104+ } else return retV;
105+
106+}
107+
108+uint8 SkyChannel::process(uint16 aktTime) {
109+
110+ if (!_channelData.channelActive) {
111+ return 0;
112+ }
113+
114+ uint8 returnVal = 0;
115+
116+ _channelData.nextEventTime -= aktTime;
117+ uint8 opcode;
118+ while ((_channelData.nextEventTime < 0) && (_channelData.channelActive)) {
119+ opcode = _musicData[_channelData.eventDataPtr];
120+ _channelData.eventDataPtr++;
121+ if (opcode&0x80) {
122+ if (opcode == 0xFF) {
123+ // dummy opcode
124+ } else if (opcode > 0x9D) {
125+
126+ } else if (opcode >= 0x90) {
127+ switch (opcode&0xF) {
128+ case 0: com90_caseNoteOff(); break;
129+ case 1: com90_stopChannel(); break;
130+ case 2: com90_setupInstrument(); break;
131+ case 3:
132+ returnVal = com90_updateTempo();
133+ break;
134+ case 5: com90_getFreqOffset(); break;
135+ case 6: com90_getChannelVolume(); break;
136+ case 7: com90_getTremoVibro(); break;
137+ case 8: com90_rewindMusic(); break;
138+ case 9: com90_keyOff(); break;
139+ case 12: com90_setStartOfData(); break;
140+ case 4: //com90_dummy();
141+ case 10: //com90_error();
142+ case 11: //com90_doLodsb();
143+ case 13: //com90_do_two_Lodsb();
144+ error("SkyChannel: dummy music routine 0x%02X was called\n",opcode);
145+ _channelData.channelActive = 0;
146+ break;
147+ default:
148+ // these opcodes aren't implemented in original music driver
149+ error("SkyChannel: Not existant routine 0x%02X was called\n",opcode);
150+ _channelData.channelActive = 0;
151+ break;
152+ }
153+ } else {
154+ // new adlib channel assignment
155+ _channelData.adlibChannelNumber = opcode&0xF;
156+ _channelData.adlibReg1 = _registerTable[(opcode&0xF)<<1];
157+ _channelData.adlibReg2 = _registerTable[((opcode&0xF)<<1)|1];
158+ }
159+ } else {
160+ _channelData.lastCommand = opcode;
161+ stopNote();
162+ setupInstrument(opcode);
163+
164+ opcode = _musicData[_channelData.eventDataPtr];
165+ _channelData.eventDataPtr++;
166+ setupChannelVolume(opcode);
167+ }
168+ if (_channelData.channelActive)
169+ _channelData.nextEventTime += getNextEventTime();
170+ }
171+ return returnVal;
172+}
173+
174+void SkyChannel::setupInstrument(uint8 opcode) {
175+
176+ uint16 nextNote;
177+ if (_channelData.tremoVibro) {
178+ uint8 newInstrument = _instrumentMap[opcode];
179+ if (newInstrument != _channelData.assignedInstrument) {
180+ _channelData.assignedInstrument = newInstrument;
181+ _channelData.instrumentData = _instruments + newInstrument;
182+ adlibSetupInstrument();
183+ }
184+ _channelData.lastCommand = _channelData.instrumentData->bindedEffect;
185+ nextNote = getNextNote(_channelData.lastCommand);
186+ } else {
187+ nextNote = getNextNote(opcode - 0x18 + _channelData.instrumentData->bindedEffect);
188+ }
189+ _channelData.frequency = nextNote;
190+ setRegister(0xA0 | _channelData.adlibChannelNumber, (uint8)nextNote);
191+ setRegister(0xB0 | _channelData.adlibChannelNumber, (uint8)((nextNote >> 8) | 0x20));
192+ _channelData.note = (uint8)((nextNote >> 8) | 0x20);
193+}
194+
195+void SkyChannel::setupChannelVolume(uint8 volume) {
196+
197+ uint8 resultOp;
198+ uint32 resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op2 + 1)) << 1;
199+ resVol &= 0xFFFF;
200+ resVol *= (_channelData.channelVolume+1)<<1;
201+ resVol >>= 8;
202+ resVol *= _musicVolume;
203+ resVol >>= 16;
204+ resultOp = ((_channelData.instrumentData->scalingLevel << 6) & 0xC0) | _opOutputTable[resVol];
205+ setRegister(0x40 | _channelData.adlibReg2, resultOp);
206+ if (_channelData.instrumentData->feedBack & 1) {
207+ resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op1 + 1)) << 1;
208+ resVol &= 0xFFFF;
209+ resVol *= (_channelData.channelVolume + 1)<<1;
210+ resVol >>= 8;
211+ resVol *= (_musicVolume & 0xFF);
212+ resVol >>= 16;
213+ } else resVol = _channelData.instrumentData->totOutLev_Op1;
214+ resultOp = ((_channelData.instrumentData->scalingLevel << 2) & 0xC0) | _opOutputTable[resVol];
215+ setRegister(0x40 | _channelData.adlibReg1, resultOp);
216+}
217+
218+void SkyChannel::adlibSetupInstrument(void) {
219+
220+ setRegister(0x60 | _channelData.adlibReg1, _channelData.instrumentData->ad_Op1);
221+ setRegister(0x60 | _channelData.adlibReg2, _channelData.instrumentData->ad_Op2);
222+ setRegister(0x80 | _channelData.adlibReg1, _channelData.instrumentData->sr_Op1);
223+ setRegister(0x80 | _channelData.adlibReg2, _channelData.instrumentData->sr_Op2);
224+ setRegister(0xE0 | _channelData.adlibReg1, _channelData.instrumentData->waveSelect_Op1);
225+ setRegister(0xE0 | _channelData.adlibReg2, _channelData.instrumentData->waveSelect_Op2);
226+ setRegister(0xC0 | _channelData.adlibChannelNumber, _channelData.instrumentData->feedBack);
227+ setRegister(0x20 | _channelData.adlibReg1, _channelData.instrumentData->ampMod_Op1);
228+ setRegister(0x20 | _channelData.adlibReg2, _channelData.instrumentData->ampMod_Op2);
229+}
230+
231+#ifdef SCUMM_BIG_ENDIAN
232+#define ENDIAN16(x) ((x>>8)|((x&0xFF)<<8))
233+#else
234+#define ENDIAN16(x) (x)
235+#endif
236+
237+uint16 SkyChannel::getNextNote(uint8 param) {
238+
239+ int16 freqIndex = ((int16)_channelData.freqOffset)-0x40;
240+ if (freqIndex >= 0x3F) freqIndex++;
241+ freqIndex *= _channelData.freqDataSize;
242+ freqIndex += param<<6;
243+ uint16 freqData = ENDIAN16(_frequenceTable[freqIndex%0x300]);
244+ if ((freqIndex%0x300 >= 0x1C0) || (freqIndex/0x300 > 0)) {
245+ return (((freqIndex/0x300)-1)<<10)+(freqData&0x7FF);
246+ } else {
247+ // looks like a bug. dunno why. It's what the ASM code says.
248+ return (uint16)(((int16)freqData) >> 1);
249+ }
250+}
251+
252+//- command 90h routines
253+
254+void SkyChannel::com90_caseNoteOff(void) {
255+
256+ if (_musicData[_channelData.eventDataPtr] == _channelData.lastCommand)
257+ stopNote();
258+ _channelData.eventDataPtr++;
259+}
260+
261+void SkyChannel::com90_stopChannel(void) {
262+
263+ stopNote();
264+ _channelData.channelActive = 0;
265+}
266+
267+void SkyChannel::com90_setupInstrument(void) {
268+
269+ _channelData.channelVolume = 0x7F;
270+ _channelData.freqOffset = 0x40;
271+ _channelData.assignedInstrument = _musicData[_channelData.eventDataPtr];
272+ _channelData.eventDataPtr++;
273+ _channelData.instrumentData = _instruments + _channelData.assignedInstrument;
274+ adlibSetupInstrument();
275+}
276+
277+uint8 SkyChannel::com90_updateTempo(void) {
278+
279+ uint8 retV = _musicData[_channelData.eventDataPtr];
280+ _channelData.eventDataPtr++;
281+ return retV;
282+}
283+
284+void SkyChannel::com90_getFreqOffset(void) {
285+
286+ _channelData.freqOffset = _musicData[_channelData.eventDataPtr];
287+ _channelData.eventDataPtr++;
288+ if (_channelData.note) {
289+ uint16 nextNote = getNextNote(
290+ _channelData.lastCommand - 0x18 + _channelData.instrumentData->bindedEffect);
291+ setRegister(0xA0|_channelData.adlibChannelNumber, (uint8)nextNote);
292+ setRegister(0xB0|_channelData.adlibChannelNumber, (uint8)((nextNote>>8)|0x20));
293+ _channelData.note = (uint8)(nextNote>>8)|0x20;
294+ }
295+}
296+
297+void SkyChannel::com90_getChannelVolume(void) {
298+
299+ _channelData.channelVolume = _musicData[_channelData.eventDataPtr];
300+ _channelData.eventDataPtr++;
301+}
302+
303+void SkyChannel::com90_getTremoVibro(void) {
304+
305+ _channelData.tremoVibro = _musicData[_channelData.eventDataPtr];
306+ _channelData.eventDataPtr++;
307+}
308+
309+void SkyChannel::com90_rewindMusic(void) {
310+
311+ _channelData.eventDataPtr = _channelData.startOfData;
312+}
313+
314+void SkyChannel::com90_keyOff(void) {
315+
316+ stopNote();
317+}
318+
319+void SkyChannel::com90_setStartOfData(void) {
320+
321+ _channelData.startOfData = _channelData.eventDataPtr;
322+}
323diff -Nu sky/skychannel.h sky/skychannel.h
324--- sky/skychannel.h 1970-01-01 01:00:00.000000000 +0100
325+++ sky/skychannel.h 2003-04-21 20:00:33.000000000 +0200
326@@ -0,0 +1,85 @@
327+/*
328+ * C++ implementation of "Tony William's Sound Images Generation 2"-drivers
329+ * by Robert "LavosSpawn" Göffringmann
330+ */
331+
332+#ifndef __SkyChannel__
333+#define __SkyChannel__
334+
335+#include "stdafx.h"
336+#include "sound/fmopl.h"
337+#include "common/engine.h"
338+
339+typedef struct {
340+ uint8 ad_Op1, ad_Op2;
341+ uint8 sr_Op1, sr_Op2;
342+ uint8 ampMod_Op1, ampMod_Op2;
343+ uint8 waveSelect_Op1, waveSelect_Op2;
344+ uint8 bindedEffect;
345+ uint8 feedBack;
346+ uint8 totOutLev_Op1, totOutLev_Op2;
347+ uint8 scalingLevel;
348+ uint8 pad1, pad2, pad3;
349+} InstrumentStruct;
350+
351+typedef struct {
352+ uint16 eventDataPtr;
353+ int32 nextEventTime;
354+ uint16 startOfData;
355+ uint8 adlibChannelNumber;
356+ uint8 lastCommand;
357+ uint8 channelActive;
358+ uint8 note;
359+ uint8 adlibReg1, adlibReg2;
360+ InstrumentStruct *instrumentData;
361+ uint8 assignedInstrument;
362+ uint8 channelVolume;
363+ uint8 padding; // field_12 / not used by original driver
364+ uint8 tremoVibro;
365+ uint8 freqDataSize;
366+ uint8 freqOffset;
367+ uint16 frequency;
368+} ChannelType;
369+
370+class SkyChannel {
371+public:
372+ SkyChannel(uint8 *pMusicData, uint16 startOfData, FM_OPL *pOpl);
373+ void stopNote(void);
374+ uint8 process(uint16 aktTime);
375+ void updateVolume(uint16 pVolume);
376+private:
377+ uint8 *_musicData;
378+ uint16 _musicVolume;
379+ FM_OPL *_opl;
380+ ChannelType _channelData;
381+ //-
382+ InstrumentStruct *_instruments;
383+ uint16 *_frequenceTable;
384+ uint8 *_instrumentMap;
385+ uint8 *_registerTable, *_opOutputTable;
386+ uint8 *_adlibRegMirror;
387+ //- normal subs
388+ void setRegister(uint8 regNum, uint8 value);
389+ int32 getNextEventTime(void);
390+ uint16 getNextNote(uint8 param);
391+ void adlibSetupInstrument(void);
392+ void setupInstrument(uint8 opcode);
393+ void setupChannelVolume(uint8 volume);
394+ //- Streamfunctions from Command90hTable
395+ void com90_caseNoteOff(void); // 0
396+ void com90_stopChannel(void); // 1
397+ void com90_setupInstrument(void); // 2
398+ uint8 com90_updateTempo(void); // 3
399+ //void com90_dummy(void); // 4
400+ void com90_getFreqOffset(void); // 5
401+ void com90_getChannelVolume(void); // 6
402+ void com90_getTremoVibro(void); // 7
403+ void com90_rewindMusic(void); // 8
404+ void com90_keyOff(void); // 9
405+ //void com90_error(void); // 10
406+ //void com90_doLodsb(void); // 11
407+ void com90_setStartOfData(void); // 12
408+ //void com90_do_two_Lodsb(void); // 13
409+};
410+
411+#endif //__SkyChannel__
412diff -Nu sky/sky.cpp sky/sky.cpp
413--- sky/sky.cpp 2003-04-21 20:00:12.000000000 +0200
414+++ sky/sky.cpp 2003-04-21 20:10:52.000000000 +0200
415@@ -83,6 +83,7 @@
416 _dump_file = stdout;
417
418 initialise();
419+
420 if (!isDemo(_gameVersion) || isCDVersion(_gameVersion))
421 intro();
422
423@@ -95,11 +96,10 @@
424
425 //initialise_memory();
426 initTimer();
427- //init_music();
428
429 _sound = new SkySound(_mixer);
430-
431 _skyDisk = new SkyDisk(_gameDataPath);
432+ _music = new SkyMusic(_mixer,_skyDisk);
433 _gameVersion = _skyDisk->determineGameVersion();
434 _skyText = getSkyText();
435
436diff -Nu sky/sky.h sky/sky.h
437--- sky/sky.h 2003-04-21 20:00:12.000000000 +0200
438+++ sky/sky.h 2003-04-21 20:05:28.000000000 +0200
439@@ -30,6 +30,7 @@
440 #include "sky/sound.h"
441 #include "sky/text.h"
442 #include "sky/disk.h"
443+#include "sky/skymusic.h"
444
445 class SkyState : public Engine {
446 void errorString(const char *buf_input, char *buf_output);
447@@ -67,6 +68,7 @@
448
449 SkySound *_sound;
450 SkyDisk *_skyDisk;
451+ SkyMusic *_music;
452
453 byte *_workScreen;
454 byte *_backScreen;
455diff -Nu sky/skymusic.cpp sky/skymusic.cpp
456--- sky/skymusic.cpp 1970-01-01 01:00:00.000000000 +0100
457+++ sky/skymusic.cpp 2003-04-21 20:02:21.000000000 +0200
458@@ -0,0 +1,219 @@
459+#include "skymusic.h"
460+
461+void SkyMusic::passMixerFunc(void *param, int16 *buf, uint len) {
462+
463+ ((SkyMusic*)param)->premixerCall(buf, len);
464+}
465+
466+void SkyMusic::premixerCall(int16 *buf, uint len) {
467+
468+ if (_musicData == NULL) {
469+ // no music loaded
470+ memset(buf, 0, len * sizeof(int16));
471+ return;
472+ } else if ((_currentMusic == 0) || (_numberOfChannels == 0)) {
473+ // music loaded but not played as of yet
474+ memset(buf, 0, len * sizeof(int16));
475+ // poll anyways as pollMusic() can activate the music
476+ pollMusic();
477+ _nextMusicPoll = _sampleRate/50;
478+ return;
479+ }
480+ uint32 render;
481+ while (len) {
482+ render = (len > _nextMusicPoll) ? (_nextMusicPoll) : (len);
483+ len -= render;
484+ _nextMusicPoll -= render;
485+ YM3812UpdateOne(_opl, buf, render);
486+ buf += render;
487+ if (_nextMusicPoll == 0) {
488+ pollMusic();
489+ _nextMusicPoll = _sampleRate/50;
490+ }
491+ }
492+}
493+
494+SkyMusic::SkyMusic(SoundMixer *mixer, SkyDisk *pSkyDisk) {
495+
496+ _musicData = NULL;
497+ _allowedCommands = 0;
498+ _mixer = mixer;
499+ _sampleRate = g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0);
500+ int env_bits = g_system->property(OSystem::PROP_GET_FMOPL_ENV_BITS, NULL);
501+ int eg_ent = g_system->property(OSystem::PROP_GET_FMOPL_EG_ENT, NULL);
502+ OPLBuildTables((env_bits ? env_bits : FMOPL_ENV_BITS_HQ), (eg_ent ? eg_ent : FMOPL_EG_ENT_HQ));
503+ _opl = OPLCreate(OPL_TYPE_YM3812, 3579545, _sampleRate);
504+ _mixer->setupPremix(this, passMixerFunc);
505+ _skyDisk = pSkyDisk;
506+}
507+
508+SkyMusic::~SkyMusic(void)
509+{
510+ if (_currentMusic) stopMusic();
511+ _mixer->setupPremix(NULL, NULL);
512+ if (_musicData) free(_musicData);
513+ OPLDestroy(_opl);
514+}
515+
516+void SkyMusic::loadSectionMusic(uint8 pSection)
517+{
518+ if (_currentMusic) stopMusic();
519+ if (_musicData) free(_musicData);
520+ _musicData = _skyDisk->loadFile(MUSIC_BASE_FILE + FILES_PER_SECTION*pSection,NULL);
521+ _allowedCommands = 0;
522+ _musicTempo0 = 0x78; // init constants taken from idb file, area ~0x1060
523+ _musicTempo1 = 0xC0;
524+ _musicVolume = 0x100;
525+ _numberOfChannels = _currentMusic = 0;
526+ _musicDataLoc = (_musicData[0x1202]<<8)|_musicData[0x1201];
527+ _initSequence = _musicData+0xE91;
528+ _onNextPoll.doReInit = false;
529+ _onNextPoll.doStopMusic = false;
530+ _onNextPoll.musicToProcess = 0;
531+ _tempo = _aktTime = 0x10001;
532+ _nextMusicPoll = 0;
533+ startAdlibDriver();
534+}
535+
536+/*void SkyMusic::loadData(uint8 *pMusicData)
537+{
538+ if (_currentMusic) stopMusic();
539+ if (_musicData) free(_musicData);
540+ _musicData = pMusicData;
541+ _allowedCommands = 0;
542+ _musicTempo0 = 0x78; // init constants taken from idb file, area ~0x1060
543+ _musicTempo1 = 0xC0;
544+ _musicVolume = 0x100;
545+ _numberOfChannels = _currentMusic = 0;
546+ _musicDataLoc = (_musicData[0x1202]<<8)|_musicData[0x1201];
547+ _initSequence = _musicData+0xE91;
548+ _onNextPoll.doReInit = false;
549+ _onNextPoll.doStopMusic = false;
550+ _onNextPoll.musicToProcess = 0;
551+ _tempo = _aktTime = 0x10001;
552+ _nextMusicPoll = 0;
553+}*/
554+
555+void SkyMusic::musicCommand(uint16 command)
556+{
557+ if (_musicData == NULL) {
558+ debug(1,"Got music command but driver is not yet loaded.\n");
559+ return ;
560+ }
561+ if ((command >> 8) > _allowedCommands) {
562+ debug(1,"got musicCommand %d while expecting <= %d\n", command >> 8, _allowedCommands);
563+ return ;
564+ }
565+ switch(command >> 8) {
566+ case 0:
567+ //startAdlibDriver(); break;
568+ debug(1,"SkyMusic: got call to startAdlibDriver(). Not necessary in this implementation.\n");
569+ break;
570+ case 1:
571+ //StopDriver(command&0xFF); break;
572+ debug(1,"SkyMusic: got call to stopDriver(). Not necessary in this implementation.\n");
573+ break;
574+ case 2:
575+ debug(1,"SkyMusic: got call to SetTempo(). Tempo is fixed in this implementation.\n");
576+ break;
577+ case 3:
578+ debug(1,"SkyMusic: ignored direct call to driverPoll().\n");
579+ break;
580+ case 4:
581+ startMusic(command&0xFF);
582+ break;
583+ case 6:
584+ reinitFM();
585+ break;
586+ case 7:
587+ stopMusic();
588+ break;
589+ case 13:
590+ setFMVolume(command&0xFF);
591+ break;
592+ default:
593+ debug(1,"musicCommand %d ignored.\n",command>>8);
594+ }
595+}
596+
597+void SkyMusic::setFMVolume(uint16 param)
598+{
599+ _musicVolume = param;
600+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++)
601+ _channels[cnt]->updateVolume(_musicVolume);
602+}
603+
604+void SkyMusic::startAdlibDriver(void)
605+{
606+ uint16 cnt = 0;
607+ while (_initSequence[cnt] || _initSequence[cnt+1]) {
608+ OPLWriteReg(_opl, _initSequence[cnt], _initSequence[cnt+1]);
609+ cnt += 2;
610+ }
611+ _allowedCommands = 0xD;
612+}
613+
614+void SkyMusic::stopMusic(void)
615+{
616+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
617+ _channels[cnt]->stopNote();
618+ delete _channels[cnt];
619+ }
620+ _numberOfChannels = 0;
621+}
622+
623+void SkyMusic::updateTempo(void)
624+{
625+ uint16 tempoMul = _musicTempo0*_musicTempo1;
626+ uint16 divisor = 0x4446390/23864;
627+ _tempo = (tempoMul / divisor)<<16;
628+ _tempo |= (((tempoMul%divisor)<<16) | (tempoMul/divisor)) / divisor;
629+}
630+
631+void SkyMusic::loadNewMusic(void)
632+{
633+ uint16 musicPos;
634+ if (_onNextPoll.musicToProcess > _musicData[_musicDataLoc]) {
635+ error("Music %d requested but doesn't exist in file.\n", _onNextPoll.musicToProcess);
636+ return;
637+ }
638+ if (_currentMusic != 0) stopMusic();
639+
640+ _currentMusic = _onNextPoll.musicToProcess;
641+ _onNextPoll.musicToProcess = 0;
642+
643+ if (_currentMusic != 0) {
644+ musicPos = (_musicData[_musicDataLoc+2]<<8) | _musicData[_musicDataLoc+1];
645+ musicPos += _musicDataLoc+((_currentMusic-1)<<1);
646+ musicPos = ((_musicData[musicPos+1]<<8) | _musicData[musicPos]) + _musicDataLoc;
647+
648+ _musicTempo1 = _musicData[musicPos+1];
649+ _musicTempo0 = _musicData[musicPos];
650+ _numberOfChannels = _musicData[musicPos+2];
651+ musicPos += 3;
652+
653+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
654+ uint16 chDataStart = ((_musicData[musicPos+1]<<8) | _musicData[musicPos]) + _musicDataLoc;
655+ _channels[cnt] = new SkyChannel(_musicData, chDataStart, _opl);
656+ musicPos += 2;
657+ }
658+ updateTempo();
659+ }
660+}
661+
662+void SkyMusic::pollMusic(void)
663+{
664+ uint8 newTempo;
665+ if (_onNextPoll.doReInit) startAdlibDriver();
666+ if (_onNextPoll.doStopMusic) stopMusic();
667+ if (_onNextPoll.musicToProcess) loadNewMusic();
668+ _aktTime += _tempo;
669+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
670+ newTempo = _channels[cnt]->process((uint16)(_aktTime >> 16));
671+ if (newTempo) {
672+ _musicTempo1 = newTempo;
673+ updateTempo();
674+ }
675+ }
676+ _aktTime &= 0xFFFF;
677+}
678diff -Nu sky/skymusic.h sky/skymusic.h
679--- sky/skymusic.h 1970-01-01 01:00:00.000000000 +0100
680+++ sky/skymusic.h 2003-04-21 20:02:29.000000000 +0200
681@@ -0,0 +1,66 @@
682+/*
683+ * C++ implementation of "Tony William's Sound Images Generation 2"-drivers
684+ * by Robert "LavosSpawn" Göffringmann
685+ */
686+
687+#ifndef __SkyMusicDriver__
688+#define __SkyMusicDriver__
689+
690+#include "stdafx.h"
691+#include "sound/fmopl.h"
692+#include "sound/mixer.h"
693+#include "common/engine.h"
694+#include "skychannel.h"
695+#include "disk.h"
696+
697+#define MUSIC_BASE_FILE 60202 // usually 60200 ( + 0 for Roland and +2 for Adlib)
698+#define FILES_PER_SECTION 4
699+
700+typedef struct {
701+ bool doReInit, doStopMusic;
702+ uint8 musicToProcess;
703+} Actions;
704+
705+class SkyMusic {
706+public:
707+ SkyMusic(SoundMixer *mixer, SkyDisk *pSkyDisk);
708+ ~SkyMusic(void);
709+ //void loadData(uint8 *pMusicData);
710+ void loadSectionMusic(uint8 pSection);
711+ void musicCommand(uint16 command);
712+ void startMusic(uint16 param) { _onNextPoll.musicToProcess = param & 0xF; }; // 4
713+
714+private:
715+ SoundMixer *_mixer;
716+ SkyDisk *_skyDisk;
717+ FM_OPL *_opl;
718+ uint8 *_musicData;
719+ uint8 *_initSequence;
720+ uint8 _allowedCommands;
721+ uint16 _musicDataLoc;
722+ SkyChannel *_channels[10];
723+
724+ uint16 _musicVolume, _numberOfChannels;
725+ uint8 _currentMusic;
726+ uint8 _musicTempo0; // can be changed by music stream
727+ uint8 _musicTempo1; // given once per music
728+ uint32 _tempo; // calculated from musicTempo0 and musicTempo1
729+ uint32 _aktTime;
730+ uint32 _sampleRate, _nextMusicPoll;
731+ Actions _onNextPoll;
732+
733+ void premixerCall(int16 *buf, uint len);
734+ static void passMixerFunc(void *param, int16 *buf, uint len);
735+ void updateTempo(void);
736+ void loadNewMusic(void);
737+ //- functions from CommandTable @0x90 (the main interface)
738+ void startAdlibDriver(void); // 0
739+ void StopDriver(void); // 1
740+ void setTempo(uint16 newTempo); // 2
741+ void pollMusic(); // 3
742+ void reinitFM(void) { _onNextPoll.doReInit = true; }; // 6
743+ void stopMusic(); // 7
744+ void setFMVolume(uint16 param); // 13
745+};
746+
747+#endif //__SkyMusicDriver__