1 #include "innocent/musicparser.h"
3 #include "common/endian.h"
4 #include "sound/mididrv.h"
6 #include "innocent/resources.h"
7 #include "innocent/util.h"
12 DECLARE_SINGLETON(MusicParser
);
14 MusicParser::MusicParser() : MidiParser() {}
16 MusicParser::~MusicParser() {}
18 bool MusicParser::loadMusic(byte
*data
, uint32
/*size*/) {
19 _script
= MusicScript(data
);
22 setTimerRate(_driver
->getBaseTempo());
23 _driver
->setTimerCallback(this, &MidiParser::timerCallback
);
26 _clocks_per_tick
= 0x19;
31 void MusicParser::parseNextEvent(EventInfo
&info
) {
33 _script
.parseNextEvent(info
);
36 MusicScript::MusicScript() : _code(0) {}
38 MusicScript::MusicScript(const byte
*data
) :
40 _tune(READ_LE_UINT16(data
)),
47 void MusicScript::parseNextEvent(EventInfo
&info
) {
48 MusicCommand::Status ret
= _tune
.parseNextEvent(info
);
50 while (ret
!= MusicCommand::kThxBye
) {
51 while (ret
== MusicCommand::kCallMe
) {
52 switch (_code
[_offset
]) {
55 debugC(2, kDebugLevelMusic
, "will set beat to %d", _code
[_offset
+ 1]);
56 _tune
.setBeat(_code
[_offset
+ 1]);
58 ret
= MusicCommand::kThxBye
;
62 error("unhandled music script call %x", _code
[_offset
]);
65 ret
= _tune
.parseNextEvent(info
);
69 Tune::Tune() : _currentBeat(-1) {}
72 kTuneBeatCountOffset
= 0x21,
73 kTuneHeaderSize
= 0x25
76 Tune::Tune(uint16 index
) {
77 Res
.loadTune(index
, _data
);
79 uint16 nbeats
= READ_LE_UINT16(_data
+ kTuneBeatCountOffset
);
80 _beats
.resize(nbeats
);
82 const byte
*beat
= _data
+ kTuneHeaderSize
;
83 const byte
*channels
= beat
+ 8 * nbeats
;
85 for (uint i
= 0; i
< _beats
.size(); i
++) {
86 _beats
[i
] = Beat(beat
, channels
, _data
);
93 void Tune::setBeat(uint16 index
) {
95 _beats
[_currentBeat
].reset();
98 MusicCommand::Status
Tune::parseNextEvent(EventInfo
&info
) {
99 return _beats
[_currentBeat
].parseNextEvent(info
);
104 Beat::Beat(const byte
*def
, const byte
*channels
, const byte
*tune
) {
105 for (int i
= 0; i
< 8; i
++)
107 _channels
[i
] = Channel(channels
+ 16 * (def
[i
] - 1), tune
, i
+ 2);
111 for (int i
= 0; i
< 8; i
++)
112 _channels
[i
].reset();
115 MusicCommand::Status
Beat::parseNextEvent(EventInfo
&info
) {
117 uint32 bestdelta
= 0xffffffff;
118 for (int i
= 0; i
< 8; i
++) {
119 uint32 delta
= _channels
[i
].delta();
120 if (delta
< bestdelta
) {
122 best
= &_channels
[i
];
126 return best
->parseNextEvent(info
);
129 Channel::Channel() : _active(false) {}
131 Channel::Channel(const byte
*def
, const byte
*tune
, byte chanidx
) {
132 for (int i
= 0; i
< 4; i
++) {
133 const uint16 off
= READ_LE_UINT16(def
);
136 _notes
[i
] = Note(tune
+ off
);
139 for (int i
= 0; i
< 4; i
++) {
140 _init
[i
] = MusicCommand(def
);
144 _not_initialized
= true;
149 void Channel::reset() {
153 _not_initialized
= true;
156 for (int i
= 0; i
< 4; i
++)
160 uint32
Channel::delta() const {
164 if (_not_initialized
)
167 uint32 bestdelta
= 0xffffffff;
169 for (int i
= 0; i
< 4; i
++) {
170 uint32 d
= _notes
[i
].delta();
178 MusicCommand::Status
Channel::parseNextEvent(EventInfo
&info
) {
179 MusicCommand::Status ret
;
180 info
.event
= _chanidx
;
182 if (_not_initialized
) {
183 while (_initnote
< 4) {
184 unless (_init
[_initnote
].empty()) {
185 ret
= _init
[_initnote
++].parseNextEvent(info
);
191 // let's see if we're finished with initialization
194 unless (_init
[i
++].empty())
197 _not_initialized
= false;
199 uint32 bestdelta
= 0xffffffff;
202 for (int i
= 0; i
< 4; i
++) {
203 uint32 d
= _notes
[i
].delta();
210 info
.event
= _chanidx
;
211 ret
= best
->parseNextEvent(info
);
217 Note::Note() : _data(0) {}
219 Note::Note(const byte
*data
) :
220 _data(data
), _tick(0), _note(0), _begin(data
) {}
231 uint32
Note::delta() const {
234 if (_tick
<= Music
.getTick())
237 return _tick
- Music
._position
._last_event_tick
;
243 kSetExpression
= 0x89,
245 kCmdCallScript
= 0x8c,
252 kMidiChannelControl
= 0xb0,
253 kMidiSetProgram
= 0xc0
256 MusicCommand::Status
Note::parseNextEvent(EventInfo
&info
) {
257 MusicCommand
cmd(_data
);
259 info
.delta
= delta();
260 info
.basic
.param1
= _note
;
261 MusicCommand::Status ret
= cmd
.parseNextEvent(info
);
262 if ((info
.event
& 0xf0) == kMidiNoteOn
) {
264 debugC(2, kDebugLevelMusic
, "my note still playing, stopping it first");
265 info
.event
= kMidiNoteOff
| (info
.event
& 0xf);
266 info
.basic
.param1
= _note
;
268 return MusicCommand::kThxBye
;
270 _note
= info
.basic
.param1
;
276 if (_data
[0] == kHangNote
) {
280 _tick
= Music
.getTick();
281 _tick
+= d
* Music
.clocksPerTick();
286 MusicCommand::MusicCommand() : _command(0) {}
288 bool MusicCommand::empty() const {
289 return _command
== 0;
292 MusicCommand::MusicCommand(const byte
*def
) :
294 _parameter(def
[1]) {}
297 kMidiCtrlExpression
= 0xb
300 MusicCommand::Status
MusicCommand::parseNextEvent(EventInfo
&info
) {
304 debugC(2, kDebugLevelMusic
, "will set program on channel %d to %d in %d ticks", info
.event
, _parameter
, info
.delta
);
305 info
.event
|= kMidiSetProgram
;
306 info
.basic
.param1
= _parameter
;
310 debugC(2, kDebugLevelMusic
, "will set expression on channel %d to %d in %d ticks", info
.event
, _parameter
, info
.delta
);
311 info
.event
|= kMidiChannelControl
;
312 info
.basic
.param1
= kMidiCtrlExpression
;
313 info
.basic
.param2
= _parameter
;
317 debugC(2, kDebugLevelMusic
, "will turn off note %d on channel %d in %d ticks", info
.basic
.param1
, info
.event
, info
.delta
);
318 info
.event
|= kMidiNoteOff
;
322 debugC(2, kDebugLevelMusic
, "will call script");
326 debugC(2, kDebugLevelMusic
, "setting tempo to %d", _parameter
);
327 Music
.setClocksPerTick(_parameter
);
331 if (_command
< 0x80) {
332 debugC(2, kDebugLevelMusic
, "will play note %d at volume %d on %d in %d ticks", _command
, _parameter
, info
.event
, info
.delta
);
333 info
.event
|= kMidiNoteOn
;
334 info
.basic
.param1
= _command
;
335 info
.basic
.param2
= _parameter
;
339 error("unhandled music command %x", _command
);
345 } // End of namespace