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
);
24 setTimerRate(_driver
->getBaseTempo());
25 _driver
->setTimerCallback(this, &MidiParser::timerCallback
);
33 void MusicParser::parseNextEvent(EventInfo
&info
) {
34 _script
.parseNextEvent(info
);
37 MusicScript::MusicScript() : _code(0) {}
39 MusicScript::MusicScript(const byte
*data
) :
41 _tune(READ_LE_UINT16(data
)),
44 void MusicScript::parseNextEvent(EventInfo
&info
) {
45 MusicCommand::Status ret
= _tune
.parseNextEvent(info
);
47 while (ret
!= MusicCommand::kThxBye
)
48 if (ret
== MusicCommand::kCallMe
) {
49 switch (_code
[_offset
]) {
51 error("unhandled music script call %x", _code
[_offset
]);
57 Tune::Tune() : _currentBeat(-1) {}
60 kTuneBeatCountOffset
= 0x21,
61 kTuneHeaderSize
= 0x25
64 Tune::Tune(uint16 index
) {
66 Res
.loadTune(index
, _data
);
68 uint16 nbeats
= READ_LE_UINT16(_data
+ kTuneBeatCountOffset
);
69 _beats
.resize(nbeats
);
71 const byte
*beat
= _data
+ kTuneHeaderSize
;
72 const byte
*channels
= beat
+ 8 * nbeats
;
74 for (uint i
= 0; i
< _beats
.size(); i
++) {
75 _beats
[i
] = Beat(beat
, channels
, _data
);
82 MusicCommand::Status
Tune::parseNextEvent(EventInfo
&info
) {
83 return _beats
[_currentBeat
].parseNextEvent(info
);
88 Beat::Beat(const byte
*def
, const byte
*channels
, const byte
*tune
) {
89 for (int i
= 0; i
< 8; i
++)
91 _channels
[i
] = Channel(channels
+ 16 * (def
[i
] - 1), tune
, i
+ 2);
94 MusicCommand::Status
Beat::parseNextEvent(EventInfo
&info
) {
96 uint32 bestdelta
= 0xffffffff;
97 for (int i
= 0; i
< 8; i
++) {
98 uint32 delta
= _channels
[i
].delta();
99 if (delta
< bestdelta
) {
101 best
= &_channels
[i
];
105 return best
->parseNextEvent(info
);
108 Channel::Channel() : _active(false) {}
110 Channel::Channel(const byte
*def
, const byte
*tune
, byte chanidx
) {
111 for (int i
= 0; i
< 4; i
++) {
112 const uint16 off
= READ_LE_UINT16(def
);
115 _notes
[i
] = Note(tune
+ off
);
118 for (int i
= 0; i
< 4; i
++) {
119 _init
[i
] = MusicCommand(def
);
123 _not_initialized
= true;
128 uint32
Channel::delta() const {
132 if (_not_initialized
)
135 uint32 bestdelta
= 0xffffffff;
137 for (int i
= 0; i
< 4; i
++) {
138 uint32 d
= _notes
[i
].delta();
146 MusicCommand::Status
Channel::parseNextEvent(EventInfo
&info
) {
147 MusicCommand::Status ret
;
148 info
.event
= _chanidx
;
150 if (_not_initialized
) {
151 while (_initnote
< 4) {
152 unless (_init
[_initnote
].empty()) {
153 ret
= _init
[_initnote
++].parseNextEvent(info
);
159 // let's see if we're finished with initialization
162 unless (_init
[i
++].empty())
165 _not_initialized
= false;
167 uint32 bestdelta
= 0xffffffff;
170 for (int i
= 0; i
< 4; i
++) {
171 uint32 d
= _notes
[i
].delta();
178 info
.event
= _chanidx
;
179 ret
= best
->parseNextEvent(info
);
185 Note::Note() : _data(0) {}
187 Note::Note(const byte
*data
) :
188 _data(data
), _tick(0), _note(0) {}
190 uint32
Note::delta() const {
193 if (_tick
<= Music
.getTick())
196 return _tick
- Music
._position
._last_event_tick
;
201 kSetExpression
= 0x89,
203 kCmdCallScript
= 0x8c,
210 kMidiChannelControl
= 0xb0,
211 kMidiSetProgram
= 0xc0
214 MusicCommand::Status
Note::parseNextEvent(EventInfo
&info
) {
215 MusicCommand
cmd(_data
);
217 info
.delta
= delta();
218 info
.basic
.param1
= _note
;
219 MusicCommand::Status ret
= cmd
.parseNextEvent(info
);
220 if (info
.event
& 0xf0 == kMidiNoteOn
) {
222 info
.event
= kMidiNoteOff
| (info
.event
& 0xf);
223 info
.basic
.param1
= _note
;
225 return MusicCommand::kThxBye
;
227 _note
= info
.basic
.param1
;
233 if (_data
[0] == kHangNote
) {
237 _tick
= Music
.getTick();
243 MusicCommand::MusicCommand() : _command(0) {}
245 bool MusicCommand::empty() const {
246 return _command
== 0;
249 MusicCommand::MusicCommand(const byte
*def
) :
251 _parameter(def
[1]) {}
254 kMidiCtrlExpression
= 0xb
257 MusicCommand::Status
MusicCommand::parseNextEvent(EventInfo
&info
) {
261 debugC(2, kDebugLevelMusic
, "will set program on channel %d to %d in %d ticks", info
.event
, _parameter
, info
.delta
);
262 info
.event
|= kMidiSetProgram
;
263 info
.basic
.param1
= _parameter
;
267 debugC(2, kDebugLevelMusic
, "will set expression on channel %d to %d in %d ticks", info
.event
, _parameter
, info
.delta
);
268 info
.event
|= kMidiChannelControl
;
269 info
.basic
.param1
= kMidiCtrlExpression
;
270 info
.basic
.param2
= _parameter
;
274 debugC(2, kDebugLevelMusic
, "will turn off note %d on channel %d in %d ticks", info
.basic
.param1
, info
.event
, info
.delta
);
275 info
.event
|= kMidiNoteOff
;
279 debugC(2, kDebugLevelMusic
, "will call script");
283 if (_command
< 0x80) {
284 debugC(2, kDebugLevelMusic
, "will play note %d at volume %d on %d in %d ticks", _command
, _parameter
, info
.event
, info
.delta
);
285 info
.event
|= kMidiNoteOn
;
286 info
.basic
.param1
= _command
;
287 info
.basic
.param2
= _parameter
;
291 error("unhandled music command %x", _command
);
297 } // End of namespace