Mercurial > audlegacy-plugins
comparison src/adplug/core/rol.cxx @ 955:4709ce4e209e trunk
[svn] Run indent -ts4 -nut -bli0 -cdw on this messy lot. Upstream is not consistent with whitespace anyway, no loss there.
author | chainsaw |
---|---|
date | Sat, 14 Apr 2007 15:23:50 -0700 |
parents | 028350cb60b1 |
children | 88ba14f18587 |
comparison
equal
deleted
inserted
replaced
954:d7a6fd179cd2 | 955:4709ce4e209e |
---|---|
23 #include <algorithm> | 23 #include <algorithm> |
24 | 24 |
25 #include "rol.h" | 25 #include "rol.h" |
26 #include "debug.h" | 26 #include "debug.h" |
27 | 27 |
28 int const CrolPlayer::kSizeofDataRecord = 30; | 28 int const |
29 int const CrolPlayer::kMaxTickBeat = 60; | 29 CrolPlayer::kSizeofDataRecord = 30; |
30 int const CrolPlayer::kSilenceNote = -12; | 30 int const |
31 int const CrolPlayer::kNumMelodicVoices = 9; | 31 CrolPlayer::kMaxTickBeat = 60; |
32 int const CrolPlayer::kNumPercussiveVoices = 11; | 32 int const |
33 int const CrolPlayer::kBassDrumChannel = 6; | 33 CrolPlayer::kSilenceNote = -12; |
34 int const CrolPlayer::kSnareDrumChannel = 7; | 34 int const |
35 int const CrolPlayer::kTomtomChannel = 8; | 35 CrolPlayer::kNumMelodicVoices = 9; |
36 int const CrolPlayer::kTomtomFreq = 2;//4; | 36 int const |
37 int const CrolPlayer::kSnareDrumFreq = 2;//kTomtomFreq + 7; | 37 CrolPlayer::kNumPercussiveVoices = 11; |
38 float const CrolPlayer::kDefaultUpdateTme = 18.2f; | 38 int const |
39 float const CrolPlayer::kPitchFactor = 400.0f; | 39 CrolPlayer::kBassDrumChannel = 6; |
40 | 40 int const |
41 static const unsigned char drum_table[4] = {0x14, 0x12, 0x15, 0x11}; | 41 CrolPlayer::kSnareDrumChannel = 7; |
42 | 42 int const |
43 CrolPlayer::uint16 const CrolPlayer::kNoteTable[12] = | 43 CrolPlayer::kTomtomChannel = 8; |
44 { | 44 int const |
45 340, // C | 45 CrolPlayer::kTomtomFreq = 2; //4; |
46 363, // C# | 46 int const |
47 385, // D | 47 CrolPlayer::kSnareDrumFreq = 2; //kTomtomFreq + 7; |
48 408, // D# | 48 float const |
49 432, // E | 49 CrolPlayer::kDefaultUpdateTme = 18.2f; |
50 458, // F | 50 float const |
51 485, // F# | 51 CrolPlayer::kPitchFactor = 400.0f; |
52 514, // G | 52 |
53 544, // G# | 53 static const unsigned char |
54 577, // A | 54 drum_table[4] = { 0x14, 0x12, 0x15, 0x11 }; |
55 611, // A# | 55 |
56 647 // B | 56 CrolPlayer::uint16 const |
57 CrolPlayer::kNoteTable[12] = { | |
58 340, // C | |
59 363, // C# | |
60 385, // D | |
61 408, // D# | |
62 432, // E | |
63 458, // F | |
64 485, // F# | |
65 514, // G | |
66 544, // G# | |
67 577, // A | |
68 611, // A# | |
69 647 // B | |
57 }; | 70 }; |
58 | 71 |
59 /*** public methods **************************************/ | 72 /*** public methods **************************************/ |
60 | 73 |
61 CPlayer *CrolPlayer::factory(Copl *newopl) | 74 CPlayer * |
62 { | 75 CrolPlayer::factory (Copl * newopl) |
63 return new CrolPlayer(newopl); | 76 { |
64 } | 77 return new CrolPlayer (newopl); |
65 //--------------------------------------------------------- | 78 } |
66 CrolPlayer::CrolPlayer(Copl *newopl) | 79 |
67 : CPlayer ( newopl ) | 80 //--------------------------------------------------------- |
68 ,rol_header ( NULL ) | 81 CrolPlayer::CrolPlayer (Copl * newopl):CPlayer (newopl), rol_header (NULL), mNextTempoEvent (0), mCurrTick (0), |
69 ,mNextTempoEvent ( 0 ) | 82 mTimeOfLastNote (0), mRefresh (kDefaultUpdateTme), |
70 ,mCurrTick ( 0 ) | 83 bdRegister (0) |
71 ,mTimeOfLastNote ( 0 ) | 84 { |
72 ,mRefresh ( kDefaultUpdateTme ) | 85 int |
73 ,bdRegister ( 0 ) | 86 n; |
74 { | 87 |
75 int n; | 88 memset (bxRegister, 0, sizeof (bxRegister)); |
76 | 89 memset (volumeCache, 0, sizeof (volumeCache)); |
77 memset(bxRegister, 0, sizeof(bxRegister) ); | 90 memset (freqCache, 0, sizeof (freqCache)); |
78 memset(volumeCache, 0, sizeof(volumeCache) ); | 91 |
79 memset(freqCache, 0, sizeof(freqCache) ); | 92 for (n = 0; n < 11; n++) |
80 | 93 pitchCache[n] = 1.0f; |
81 for(n=0; n<11; n++) | 94 } |
82 pitchCache[n]=1.0f; | 95 |
83 } | 96 //--------------------------------------------------------- |
84 //--------------------------------------------------------- | 97 CrolPlayer::~CrolPlayer () |
85 CrolPlayer::~CrolPlayer() | 98 { |
86 { | 99 if (rol_header) |
87 if(rol_header) | 100 { |
88 { | 101 delete rol_header; |
89 delete rol_header; | 102 rol_header = 0; |
90 rol_header = 0; | 103 } |
91 } | 104 } |
92 } | 105 |
93 //--------------------------------------------------------- | 106 //--------------------------------------------------------- |
94 bool CrolPlayer::load(VFSFile *fd, const CFileProvider &fp) | 107 bool |
95 { | 108 CrolPlayer::load (VFSFile * fd, const CFileProvider & fp) |
96 binistream *f = fp.open(fd); if(!f) return false; | 109 { |
97 std::string filename(fd->uri); | 110 binistream *f = fp.open (fd); |
98 | 111 if (!f) |
99 char *fn = new char[filename.length()+12]; | 112 return false; |
100 int i; | 113 std::string filename (fd->uri); |
101 std::string bnk_filename; | 114 |
102 | 115 char *fn = new char[filename.length () + 12]; |
103 AdPlug_LogWrite("*** CrolPlayer::load(f, \"%s\") ***\n", filename.c_str()); | 116 int i; |
104 strcpy(fn,filename.data()); | 117 std::string bnk_filename; |
105 for (i=strlen(fn)-1; i>=0; i--) | 118 |
106 if (fn[i] == '/' || fn[i] == '\\') | 119 AdPlug_LogWrite ("*** CrolPlayer::load(f, \"%s\") ***\n", |
107 break; | 120 filename.c_str ()); |
108 strcpy(fn+i+1,"standard.bnk"); | 121 strcpy (fn, filename.data ()); |
109 bnk_filename = fn; | 122 for (i = strlen (fn) - 1; i >= 0; i--) |
110 delete [] fn; fn = 0; | 123 if (fn[i] == '/' || fn[i] == '\\') |
111 AdPlug_LogWrite("bnk_filename = \"%s\"\n",bnk_filename.c_str()); | 124 break; |
112 | 125 strcpy (fn + i + 1, "standard.bnk"); |
113 rol_header = new SRolHeader; | 126 bnk_filename = fn; |
114 memset( rol_header, 0, sizeof(SRolHeader) ); | 127 delete[]fn; |
115 | 128 fn = 0; |
116 rol_header->version_major = f->readInt( 2 ); | 129 AdPlug_LogWrite ("bnk_filename = \"%s\"\n", bnk_filename.c_str ()); |
117 rol_header->version_minor = f->readInt( 2 ); | 130 |
118 | 131 rol_header = new SRolHeader; |
119 // Version check | 132 memset (rol_header, 0, sizeof (SRolHeader)); |
120 if(rol_header->version_major != 0 || rol_header->version_minor != 4) { | 133 |
121 AdPlug_LogWrite("Unsupported file version %d.%d or not a ROL file!\n", | 134 rol_header->version_major = f->readInt (2); |
122 rol_header->version_major, rol_header->version_minor); | 135 rol_header->version_minor = f->readInt (2); |
123 AdPlug_LogWrite("--- CrolPlayer::load ---\n"); | 136 |
124 fp.close(f); | 137 // Version check |
125 return false; | 138 if (rol_header->version_major != 0 || rol_header->version_minor != 4) |
126 } | 139 { |
127 | 140 AdPlug_LogWrite ("Unsupported file version %d.%d or not a ROL file!\n", |
128 f->seek( 40, binio::Add ); | 141 rol_header->version_major, rol_header->version_minor); |
129 | 142 AdPlug_LogWrite ("--- CrolPlayer::load ---\n"); |
130 rol_header->ticks_per_beat = f->readInt( 2 ); | 143 fp.close (f); |
131 rol_header->beats_per_measure = f->readInt( 2 ); | 144 return false; |
132 rol_header->edit_scale_y = f->readInt( 2 ); | 145 } |
133 rol_header->edit_scale_x = f->readInt( 2 ); | 146 |
134 | 147 f->seek (40, binio::Add); |
135 f->seek( 1, binio::Add ); | 148 |
136 | 149 rol_header->ticks_per_beat = f->readInt (2); |
137 rol_header->mode = f->readInt(1); | 150 rol_header->beats_per_measure = f->readInt (2); |
138 | 151 rol_header->edit_scale_y = f->readInt (2); |
139 f->seek( 90+38+15, binio::Add ); | 152 rol_header->edit_scale_x = f->readInt (2); |
140 | 153 |
141 rol_header->basic_tempo = f->readFloat( binio::Single ); | 154 f->seek (1, binio::Add); |
142 | 155 |
143 load_tempo_events( f ); | 156 rol_header->mode = f->readInt (1); |
144 | 157 |
145 mTimeOfLastNote = 0; | 158 f->seek (90 + 38 + 15, binio::Add); |
146 | 159 |
147 if( load_voice_data( f, bnk_filename, fp ) != true ) | 160 rol_header->basic_tempo = f->readFloat (binio::Single); |
148 { | 161 |
149 AdPlug_LogWrite("CrolPlayer::load_voice_data(f) failed!\n"); | 162 load_tempo_events (f); |
150 AdPlug_LogWrite("--- CrolPlayer::load ---\n"); | 163 |
151 | 164 mTimeOfLastNote = 0; |
152 fp.close( f ); | 165 |
153 return false; | 166 if (load_voice_data (f, bnk_filename, fp) != true) |
154 } | 167 { |
155 | 168 AdPlug_LogWrite ("CrolPlayer::load_voice_data(f) failed!\n"); |
156 fp.close( f ); | 169 AdPlug_LogWrite ("--- CrolPlayer::load ---\n"); |
157 | 170 |
158 rewind( 0 ); | 171 fp.close (f); |
159 AdPlug_LogWrite("--- CrolPlayer::load ---\n"); | 172 return false; |
173 } | |
174 | |
175 fp.close (f); | |
176 | |
177 rewind (0); | |
178 AdPlug_LogWrite ("--- CrolPlayer::load ---\n"); | |
179 return true; | |
180 } | |
181 | |
182 //--------------------------------------------------------- | |
183 bool | |
184 CrolPlayer::update () | |
185 { | |
186 if (mNextTempoEvent < mTempoEvents.size () && | |
187 mTempoEvents[mNextTempoEvent].time == mCurrTick) | |
188 { | |
189 SetRefresh (mTempoEvents[mNextTempoEvent].multiplier); | |
190 ++mNextTempoEvent; | |
191 } | |
192 | |
193 TVoiceData::iterator curr = voice_data.begin (); | |
194 TVoiceData::iterator end = voice_data.end (); | |
195 int voice = 0; | |
196 | |
197 while (curr != end) | |
198 { | |
199 UpdateVoice (voice, *curr); | |
200 ++curr; | |
201 ++voice; | |
202 } | |
203 | |
204 ++mCurrTick; | |
205 | |
206 if (mCurrTick > mTimeOfLastNote) | |
207 { | |
208 return false; | |
209 } | |
210 | |
211 return true; | |
212 //return ( mCurrTick > mTimeOfLastNote ) ? false : true; | |
213 } | |
214 | |
215 //--------------------------------------------------------- | |
216 void | |
217 CrolPlayer::rewind (int subsong) | |
218 { | |
219 TVoiceData::iterator curr = voice_data.begin (); | |
220 TVoiceData::iterator end = voice_data.end (); | |
221 | |
222 while (curr != end) | |
223 { | |
224 CVoiceData & voice = *curr; | |
225 | |
226 voice.Reset (); | |
227 ++curr; | |
228 } | |
229 | |
230 memset (bxRegister, 0, sizeof (bxRegister)); | |
231 memset (volumeCache, 0, sizeof (volumeCache)); | |
232 | |
233 bdRegister = 0; | |
234 | |
235 opl->init (); // initialize to melodic by default | |
236 opl->write (1, 0x20); // Enable waveform select (bit 5) | |
237 | |
238 if (rol_header->mode == 0) | |
239 { | |
240 opl->write (0xbd, 0x20); // select rhythm mode (bit 5) | |
241 bdRegister = 0x20; | |
242 | |
243 SetFreq (kTomtomChannel, 24); | |
244 SetFreq (kSnareDrumChannel, 31); | |
245 } | |
246 | |
247 mNextTempoEvent = 0; | |
248 mCurrTick = 0; | |
249 | |
250 SetRefresh (1.0f); | |
251 } | |
252 | |
253 //--------------------------------------------------------- | |
254 inline float | |
255 fmin (int const a, int const b) | |
256 { | |
257 return static_cast < float >(a < b ? a : b); | |
258 } | |
259 | |
260 //--------------------------------------------------------- | |
261 void | |
262 CrolPlayer::SetRefresh (float const multiplier) | |
263 { | |
264 float const tickBeat = fmin (kMaxTickBeat, rol_header->ticks_per_beat); | |
265 | |
266 mRefresh = (tickBeat * rol_header->basic_tempo * multiplier) / 60.0f; | |
267 } | |
268 | |
269 //--------------------------------------------------------- | |
270 float | |
271 CrolPlayer::getrefresh () | |
272 { | |
273 return mRefresh; | |
274 } | |
275 | |
276 //--------------------------------------------------------- | |
277 void | |
278 CrolPlayer::UpdateVoice (int const voice, CVoiceData & voiceData) | |
279 { | |
280 TNoteEvents const &nEvents = voiceData.note_events; | |
281 | |
282 if (nEvents.empty () || voiceData.mEventStatus & CVoiceData::kES_NoteEnd) | |
283 { | |
284 return; // no note data to process, don't bother doing anything. | |
285 } | |
286 | |
287 TInstrumentEvents & iEvents = voiceData.instrument_events; | |
288 TVolumeEvents & vEvents = voiceData.volume_events; | |
289 TPitchEvents & pEvents = voiceData.pitch_events; | |
290 | |
291 if (!(voiceData.mEventStatus & CVoiceData::kES_InstrEnd) && | |
292 iEvents[voiceData.next_instrument_event].time == mCurrTick) | |
293 { | |
294 if (voiceData.next_instrument_event < iEvents.size ()) | |
295 { | |
296 send_ins_data_to_chip (voice, | |
297 iEvents[voiceData.next_instrument_event]. | |
298 ins_index); | |
299 ++voiceData.next_instrument_event; | |
300 } | |
301 else | |
302 { | |
303 voiceData.mEventStatus |= CVoiceData::kES_InstrEnd; | |
304 } | |
305 } | |
306 | |
307 if (!(voiceData.mEventStatus & CVoiceData::kES_VolumeEnd) && | |
308 vEvents[voiceData.next_volume_event].time == mCurrTick) | |
309 { | |
310 SVolumeEvent const &volumeEvent = vEvents[voiceData.next_volume_event]; | |
311 | |
312 if (voiceData.next_volume_event < vEvents.size ()) | |
313 { | |
314 int const volume = (int) (63.0f * (1.0f - volumeEvent.multiplier)); | |
315 | |
316 SetVolume (voice, volume); | |
317 | |
318 ++voiceData.next_volume_event; // move to next volume event | |
319 } | |
320 else | |
321 { | |
322 voiceData.mEventStatus |= CVoiceData::kES_VolumeEnd; | |
323 } | |
324 } | |
325 | |
326 if (voiceData.mForceNote | |
327 || voiceData.current_note_duration > voiceData.mNoteDuration - 1) | |
328 { | |
329 if (mCurrTick != 0) | |
330 { | |
331 ++voiceData.current_note; | |
332 } | |
333 | |
334 if (voiceData.current_note < nEvents.size ()) | |
335 { | |
336 SNoteEvent const ¬eEvent = nEvents[voiceData.current_note]; | |
337 | |
338 SetNote (voice, noteEvent.number); | |
339 voiceData.current_note_duration = 0; | |
340 voiceData.mNoteDuration = noteEvent.duration; | |
341 voiceData.mForceNote = false; | |
342 } | |
343 else | |
344 { | |
345 SetNote (voice, kSilenceNote); | |
346 voiceData.mEventStatus |= CVoiceData::kES_NoteEnd; | |
347 return; | |
348 } | |
349 } | |
350 | |
351 if (!(voiceData.mEventStatus & CVoiceData::kES_PitchEnd) && | |
352 pEvents[voiceData.next_pitch_event].time == mCurrTick) | |
353 { | |
354 if (voiceData.next_pitch_event < pEvents.size ()) | |
355 { | |
356 SetPitch (voice, pEvents[voiceData.next_pitch_event].variation); | |
357 ++voiceData.next_pitch_event; | |
358 } | |
359 else | |
360 { | |
361 voiceData.mEventStatus |= CVoiceData::kES_PitchEnd; | |
362 } | |
363 } | |
364 | |
365 ++voiceData.current_note_duration; | |
366 } | |
367 | |
368 //--------------------------------------------------------- | |
369 void | |
370 CrolPlayer::SetNote (int const voice, int const note) | |
371 { | |
372 if (voice < kBassDrumChannel || rol_header->mode) | |
373 { | |
374 SetNoteMelodic (voice, note); | |
375 } | |
376 else | |
377 { | |
378 SetNotePercussive (voice, note); | |
379 } | |
380 } | |
381 | |
382 //--------------------------------------------------------- | |
383 void | |
384 CrolPlayer::SetNotePercussive (int const voice, int const note) | |
385 { | |
386 int const bit_pos = 4 - voice + kBassDrumChannel; | |
387 | |
388 bdRegister &= ~(1 << bit_pos); | |
389 opl->write (0xbd, bdRegister); | |
390 | |
391 if (note != kSilenceNote) | |
392 { | |
393 switch (voice) | |
394 { | |
395 case kTomtomChannel: | |
396 SetFreq (kSnareDrumChannel, note + 7); | |
397 case kBassDrumChannel: | |
398 SetFreq (voice, note); | |
399 break; | |
400 } | |
401 | |
402 bdRegister |= 1 << bit_pos; | |
403 opl->write (0xbd, bdRegister); | |
404 } | |
405 } | |
406 | |
407 //--------------------------------------------------------- | |
408 void | |
409 CrolPlayer::SetNoteMelodic (int const voice, int const note) | |
410 { | |
411 opl->write (0xb0 + voice, bxRegister[voice] & ~0x20); | |
412 | |
413 if (note != kSilenceNote) | |
414 { | |
415 SetFreq (voice, note, true); | |
416 } | |
417 } | |
418 | |
419 //--------------------------------------------------------- | |
420 void | |
421 CrolPlayer::SetPitch (int const voice, real32 const variation) | |
422 { | |
423 pitchCache[voice] = variation; | |
424 freqCache[voice] += | |
425 (uint16) ((((float) freqCache[voice]) * (variation - 1.0f)) / | |
426 kPitchFactor); | |
427 | |
428 opl->write (0xa0 + voice, freqCache[voice] & 0xff); | |
429 } | |
430 | |
431 //--------------------------------------------------------- | |
432 void | |
433 CrolPlayer::SetFreq (int const voice, int const note, bool const keyOn) | |
434 { | |
435 uint16 freq = kNoteTable[note % 12] + ((note / 12) << 10); | |
436 freq += | |
437 (uint16) ((((float) freq) * (pitchCache[voice] - 1.0f)) / kPitchFactor); | |
438 | |
439 freqCache[voice] = freq; | |
440 bxRegister[voice] = ((freq >> 8) & 0x1f); | |
441 | |
442 opl->write (0xa0 + voice, freq & 0xff); | |
443 opl->write (0xb0 + voice, bxRegister[voice] | (keyOn ? 0x20 : 0x0)); | |
444 } | |
445 | |
446 //--------------------------------------------------------- | |
447 void | |
448 CrolPlayer::SetVolume (int const voice, int const volume) | |
449 { | |
450 volumeCache[voice] = (volumeCache[voice] & 0xc0) | volume; | |
451 | |
452 int const op_offset = (voice < kSnareDrumChannel || rol_header->mode) ? | |
453 op_table[voice] + 3 : drum_table[voice - kSnareDrumChannel]; | |
454 | |
455 opl->write (0x40 + op_offset, volumeCache[voice]); | |
456 } | |
457 | |
458 //--------------------------------------------------------- | |
459 void | |
460 CrolPlayer::send_ins_data_to_chip (int const voice, int const ins_index) | |
461 { | |
462 SRolInstrument & instrument = ins_list[ins_index].instrument; | |
463 | |
464 send_operator (voice, instrument.modulator, instrument.carrier); | |
465 } | |
466 | |
467 //--------------------------------------------------------- | |
468 void | |
469 CrolPlayer::send_operator (int const voice, SOPL2Op const &modulator, | |
470 SOPL2Op const &carrier) | |
471 { | |
472 if (voice < kSnareDrumChannel || rol_header->mode) | |
473 { | |
474 int const op_offset = op_table[voice]; | |
475 | |
476 opl->write (0x20 + op_offset, modulator.ammulti); | |
477 opl->write (0x40 + op_offset, modulator.ksltl); | |
478 opl->write (0x60 + op_offset, modulator.ardr); | |
479 opl->write (0x80 + op_offset, modulator.slrr); | |
480 opl->write (0xc0 + voice, modulator.fbc); | |
481 opl->write (0xe0 + op_offset, modulator.waveform); | |
482 | |
483 volumeCache[voice] = (carrier.ksltl & 0xc0) | volumeCache[voice] & 0x3f; | |
484 | |
485 opl->write (0x23 + op_offset, carrier.ammulti); | |
486 opl->write (0x43 + op_offset, volumeCache[voice]); | |
487 opl->write (0x63 + op_offset, carrier.ardr); | |
488 opl->write (0x83 + op_offset, carrier.slrr); | |
489 // opl->write( 0xc3+voice , carrier.fbc ); <- don't bother writing this. | |
490 opl->write (0xe3 + op_offset, carrier.waveform); | |
491 } | |
492 else | |
493 { | |
494 int const op_offset = drum_table[voice - kSnareDrumChannel]; | |
495 | |
496 volumeCache[voice] = (modulator.ksltl & 0xc0) | volumeCache[voice] & 0x3f; | |
497 | |
498 opl->write (0x20 + op_offset, modulator.ammulti); | |
499 opl->write (0x40 + op_offset, volumeCache[voice]); | |
500 opl->write (0x60 + op_offset, modulator.ardr); | |
501 opl->write (0x80 + op_offset, modulator.slrr); | |
502 opl->write (0xc0 + voice, modulator.fbc); | |
503 opl->write (0xe0 + op_offset, modulator.waveform); | |
504 } | |
505 } | |
506 | |
507 //--------------------------------------------------------- | |
508 void | |
509 CrolPlayer::load_tempo_events (binistream * f) | |
510 { | |
511 int16 const num_tempo_events = f->readInt (2); | |
512 | |
513 mTempoEvents.reserve (num_tempo_events); | |
514 | |
515 for (int i = 0; i < num_tempo_events; ++i) | |
516 { | |
517 STempoEvent event; | |
518 | |
519 event.time = f->readInt (2); | |
520 event.multiplier = f->readFloat (binio::Single); | |
521 mTempoEvents.push_back (event); | |
522 } | |
523 } | |
524 | |
525 //--------------------------------------------------------- | |
526 bool | |
527 CrolPlayer::load_voice_data (binistream * f, std::string const &bnk_filename, | |
528 const CFileProvider & fp) | |
529 { | |
530 SBnkHeader bnk_header; | |
531 VFSFile *fd = vfs_fopen (bnk_filename.c_str (), "rb"); | |
532 binistream *bnk_file = fp.open (fd); | |
533 | |
534 if (bnk_file) | |
535 { | |
536 load_bnk_info (bnk_file, bnk_header); | |
537 | |
538 int const numVoices = | |
539 rol_header->mode ? kNumMelodicVoices : kNumPercussiveVoices; | |
540 | |
541 voice_data.reserve (numVoices); | |
542 for (int i = 0; i < numVoices; ++i) | |
543 { | |
544 CVoiceData voice; | |
545 | |
546 load_note_events (f, voice); | |
547 load_instrument_events (f, voice, bnk_file, bnk_header); | |
548 load_volume_events (f, voice); | |
549 load_pitch_events (f, voice); | |
550 | |
551 voice_data.push_back (voice); | |
552 } | |
553 | |
554 fp.close (bnk_file); | |
555 vfs_fclose (fd); | |
556 | |
160 return true; | 557 return true; |
161 } | 558 } |
162 //--------------------------------------------------------- | 559 |
163 bool CrolPlayer::update() | 560 return false; |
164 { | 561 } |
165 if( mNextTempoEvent < mTempoEvents.size() && | 562 |
166 mTempoEvents[mNextTempoEvent].time == mCurrTick ) | 563 //--------------------------------------------------------- |
167 { | 564 void |
168 SetRefresh( mTempoEvents[mNextTempoEvent].multiplier ); | 565 CrolPlayer::load_note_events (binistream * f, CVoiceData & voice) |
169 ++mNextTempoEvent; | 566 { |
170 } | 567 f->seek (15, binio::Add); |
171 | 568 |
172 TVoiceData::iterator curr = voice_data.begin(); | 569 int16 const time_of_last_note = f->readInt (2); |
173 TVoiceData::iterator end = voice_data.end(); | 570 |
174 int voice = 0; | 571 if (time_of_last_note != 0) |
175 | 572 { |
176 while( curr != end ) | 573 TNoteEvents & note_events = voice.note_events; |
177 { | 574 int16 total_duration = 0; |
178 UpdateVoice( voice, *curr ); | 575 |
179 ++curr; | 576 do |
180 ++voice; | 577 { |
181 } | 578 SNoteEvent event; |
182 | 579 |
183 ++mCurrTick; | 580 event.number = f->readInt (2); |
184 | 581 event.duration = f->readInt (2); |
185 if( mCurrTick > mTimeOfLastNote ) | 582 |
186 { | 583 event.number += kSilenceNote; // adding -12 |
187 return false; | 584 |
188 } | 585 note_events.push_back (event); |
189 | 586 |
190 return true; | 587 total_duration += event.duration; |
191 //return ( mCurrTick > mTimeOfLastNote ) ? false : true; | 588 } while (total_duration < time_of_last_note); |
192 } | 589 |
193 //--------------------------------------------------------- | 590 if (time_of_last_note > mTimeOfLastNote) |
194 void CrolPlayer::rewind( int subsong ) | 591 { |
195 { | 592 mTimeOfLastNote = time_of_last_note; |
196 TVoiceData::iterator curr = voice_data.begin(); | 593 } |
197 TVoiceData::iterator end = voice_data.end(); | 594 } |
198 | 595 |
199 while( curr != end ) | 596 f->seek (15, binio::Add); |
200 { | 597 } |
201 CVoiceData &voice = *curr; | 598 |
202 | 599 //--------------------------------------------------------- |
203 voice.Reset(); | 600 void |
204 ++curr; | 601 CrolPlayer::load_instrument_events (binistream * f, CVoiceData & voice, |
205 } | 602 binistream * bnk_file, |
206 | 603 SBnkHeader const &bnk_header) |
207 memset(bxRegister, 0, sizeof(bxRegister) ); | 604 { |
208 memset(volumeCache, 0, sizeof(volumeCache) ); | 605 int16 const number_of_instrument_events = f->readInt (2); |
209 | 606 |
210 bdRegister = 0; | 607 TInstrumentEvents & instrument_events = voice.instrument_events; |
211 | 608 |
212 opl->init(); // initialize to melodic by default | 609 instrument_events.reserve (number_of_instrument_events); |
213 opl->write(1,0x20); // Enable waveform select (bit 5) | 610 |
214 | 611 for (int i = 0; i < number_of_instrument_events; ++i) |
215 if( rol_header->mode == 0 ) | 612 { |
216 { | 613 SInstrumentEvent event; |
217 opl->write( 0xbd, 0x20 ); // select rhythm mode (bit 5) | 614 event.time = f->readInt (2); |
218 bdRegister = 0x20; | 615 f->readString (event.name, 9); |
219 | 616 |
220 SetFreq( kTomtomChannel, 24 ); | 617 std::string event_name = event.name; |
221 SetFreq( kSnareDrumChannel, 31 ); | 618 event.ins_index = load_rol_instrument (bnk_file, bnk_header, event_name); |
222 } | 619 |
223 | 620 instrument_events.push_back (event); |
224 mNextTempoEvent = 0; | 621 |
225 mCurrTick = 0; | 622 f->seek (1 + 2, binio::Add); |
226 | 623 } |
227 SetRefresh(1.0f); | 624 |
228 } | 625 f->seek (15, binio::Add); |
229 //--------------------------------------------------------- | 626 } |
230 inline float fmin( int const a, int const b ) | 627 |
231 { | 628 //--------------------------------------------------------- |
232 return static_cast<float>( a < b ? a : b ); | 629 void |
233 } | 630 CrolPlayer::load_volume_events (binistream * f, CVoiceData & voice) |
234 //--------------------------------------------------------- | 631 { |
235 void CrolPlayer::SetRefresh( float const multiplier ) | 632 int16 const number_of_volume_events = f->readInt (2); |
236 { | 633 |
237 float const tickBeat = fmin(kMaxTickBeat, rol_header->ticks_per_beat); | 634 TVolumeEvents & volume_events = voice.volume_events; |
238 | 635 |
239 mRefresh = (tickBeat*rol_header->basic_tempo*multiplier) / 60.0f; | 636 volume_events.reserve (number_of_volume_events); |
240 } | 637 |
241 //--------------------------------------------------------- | 638 for (int i = 0; i < number_of_volume_events; ++i) |
242 float CrolPlayer::getrefresh() | 639 { |
243 { | 640 SVolumeEvent event; |
244 return mRefresh; | 641 event.time = f->readInt (2); |
245 } | 642 event.multiplier = f->readFloat (binio::Single); |
246 //--------------------------------------------------------- | 643 |
247 void CrolPlayer::UpdateVoice( int const voice, CVoiceData &voiceData ) | 644 volume_events.push_back (event); |
248 { | 645 } |
249 TNoteEvents const &nEvents = voiceData.note_events; | 646 |
250 | 647 f->seek (15, binio::Add); |
251 if( nEvents.empty() || voiceData.mEventStatus & CVoiceData::kES_NoteEnd ) | 648 } |
252 { | 649 |
253 return; // no note data to process, don't bother doing anything. | 650 //--------------------------------------------------------- |
254 } | 651 void |
255 | 652 CrolPlayer::load_pitch_events (binistream * f, CVoiceData & voice) |
256 TInstrumentEvents &iEvents = voiceData.instrument_events; | 653 { |
257 TVolumeEvents &vEvents = voiceData.volume_events; | 654 int16 const number_of_pitch_events = f->readInt (2); |
258 TPitchEvents &pEvents = voiceData.pitch_events; | 655 |
259 | 656 TPitchEvents & pitch_events = voice.pitch_events; |
260 if( !(voiceData.mEventStatus & CVoiceData::kES_InstrEnd ) && | 657 |
261 iEvents[voiceData.next_instrument_event].time == mCurrTick ) | 658 pitch_events.reserve (number_of_pitch_events); |
262 { | 659 |
263 if( voiceData.next_instrument_event < iEvents.size() ) | 660 for (int i = 0; i < number_of_pitch_events; ++i) |
264 { | 661 { |
265 send_ins_data_to_chip( voice, iEvents[voiceData.next_instrument_event].ins_index ); | 662 SPitchEvent event; |
266 ++voiceData.next_instrument_event; | 663 event.time = f->readInt (2); |
267 } | 664 event.variation = f->readFloat (binio::Single); |
268 else | 665 |
269 { | 666 pitch_events.push_back (event); |
270 voiceData.mEventStatus |= CVoiceData::kES_InstrEnd; | 667 } |
271 } | 668 } |
272 } | 669 |
273 | 670 //--------------------------------------------------------- |
274 if( !(voiceData.mEventStatus & CVoiceData::kES_VolumeEnd ) && | 671 bool |
275 vEvents[voiceData.next_volume_event].time == mCurrTick ) | 672 CrolPlayer::load_bnk_info (binistream * f, SBnkHeader & header) |
276 { | 673 { |
277 SVolumeEvent const &volumeEvent = vEvents[voiceData.next_volume_event]; | 674 header.version_major = f->readInt (1); |
278 | 675 header.version_minor = f->readInt (1); |
279 if( voiceData.next_volume_event < vEvents.size() ) | 676 f->readString (header.signature, 6); |
280 { | 677 |
281 int const volume = (int)(63.0f*(1.0f - volumeEvent.multiplier)); | 678 header.number_of_list_entries_used = f->readInt (2); |
282 | 679 header.total_number_of_list_entries = f->readInt (2); |
283 SetVolume( voice, volume ); | 680 |
284 | 681 header.abs_offset_of_name_list = f->readInt (4); |
285 ++voiceData.next_volume_event; // move to next volume event | 682 header.abs_offset_of_data = f->readInt (4); |
286 } | 683 |
287 else | 684 f->seek (header.abs_offset_of_name_list, binio::Set); |
288 { | 685 |
289 voiceData.mEventStatus |= CVoiceData::kES_VolumeEnd; | 686 TInstrumentNames & ins_name_list = header.ins_name_list; |
290 } | 687 ins_name_list.reserve (header.number_of_list_entries_used); |
291 } | 688 |
292 | 689 for (int i = 0; i < header.number_of_list_entries_used; ++i) |
293 if( voiceData.mForceNote || voiceData.current_note_duration > voiceData.mNoteDuration-1 ) | 690 { |
294 { | 691 SInstrumentName instrument; |
295 if( mCurrTick != 0 ) | 692 |
296 { | 693 instrument.index = f->readInt (2); |
297 ++voiceData.current_note; | 694 instrument.record_used = f->readInt (1); |
298 } | 695 f->readString (instrument.name, 9); |
299 | 696 |
300 if( voiceData.current_note < nEvents.size() ) | 697 // printf("%s = #%d\n", instrument.name, i ); |
301 { | 698 |
302 SNoteEvent const ¬eEvent = nEvents[voiceData.current_note]; | 699 ins_name_list.push_back (instrument); |
303 | 700 } |
304 SetNote( voice, noteEvent.number ); | |
305 voiceData.current_note_duration = 0; | |
306 voiceData.mNoteDuration = noteEvent.duration; | |
307 voiceData.mForceNote = false; | |
308 } | |
309 else | |
310 { | |
311 SetNote( voice, kSilenceNote ); | |
312 voiceData.mEventStatus |= CVoiceData::kES_NoteEnd; | |
313 return; | |
314 } | |
315 } | |
316 | |
317 if( !(voiceData.mEventStatus & CVoiceData::kES_PitchEnd ) && | |
318 pEvents[voiceData.next_pitch_event].time == mCurrTick ) | |
319 { | |
320 if( voiceData.next_pitch_event < pEvents.size() ) | |
321 { | |
322 SetPitch(voice,pEvents[voiceData.next_pitch_event].variation); | |
323 ++voiceData.next_pitch_event; | |
324 } | |
325 else | |
326 { | |
327 voiceData.mEventStatus |= CVoiceData::kES_PitchEnd; | |
328 } | |
329 } | |
330 | |
331 ++voiceData.current_note_duration; | |
332 } | |
333 //--------------------------------------------------------- | |
334 void CrolPlayer::SetNote( int const voice, int const note ) | |
335 { | |
336 if( voice < kBassDrumChannel || rol_header->mode ) | |
337 { | |
338 SetNoteMelodic( voice, note ); | |
339 } | |
340 else | |
341 { | |
342 SetNotePercussive( voice, note ); | |
343 } | |
344 } | |
345 //--------------------------------------------------------- | |
346 void CrolPlayer::SetNotePercussive( int const voice, int const note ) | |
347 { | |
348 int const bit_pos = 4-voice+kBassDrumChannel; | |
349 | |
350 bdRegister &= ~( 1<<bit_pos ); | |
351 opl->write( 0xbd, bdRegister ); | |
352 | |
353 if( note != kSilenceNote ) | |
354 { | |
355 switch( voice ) | |
356 { | |
357 case kTomtomChannel: | |
358 SetFreq( kSnareDrumChannel, note+7 ); | |
359 case kBassDrumChannel: | |
360 SetFreq( voice, note ); | |
361 break; | |
362 } | |
363 | |
364 bdRegister |= 1<<bit_pos; | |
365 opl->write( 0xbd, bdRegister ); | |
366 } | |
367 } | |
368 //--------------------------------------------------------- | |
369 void CrolPlayer::SetNoteMelodic( int const voice, int const note ) | |
370 { | |
371 opl->write( 0xb0+voice, bxRegister[voice] & ~0x20 ); | |
372 | |
373 if( note != kSilenceNote ) | |
374 { | |
375 SetFreq( voice, note, true ); | |
376 } | |
377 } | |
378 //--------------------------------------------------------- | |
379 void CrolPlayer::SetPitch(int const voice, real32 const variation) | |
380 { | |
381 pitchCache[voice] = variation; | |
382 freqCache[voice] += (uint16)((((float)freqCache[voice])*(variation-1.0f)) / kPitchFactor); | |
383 | |
384 opl->write(0xa0+voice,freqCache[voice] & 0xff); | |
385 } | |
386 //--------------------------------------------------------- | |
387 void CrolPlayer::SetFreq( int const voice, int const note, bool const keyOn ) | |
388 { | |
389 uint16 freq = kNoteTable[note%12] + ((note/12) << 10); | |
390 freq += (uint16)((((float)freq)*(pitchCache[voice]-1.0f))/kPitchFactor); | |
391 | |
392 freqCache[voice] = freq; | |
393 bxRegister[voice] = ((freq >> 8) & 0x1f); | |
394 | |
395 opl->write( 0xa0+voice, freq & 0xff ); | |
396 opl->write( 0xb0+voice, bxRegister[voice] | (keyOn ? 0x20 : 0x0) ); | |
397 } | |
398 //--------------------------------------------------------- | |
399 void CrolPlayer::SetVolume( int const voice, int const volume ) | |
400 { | |
401 volumeCache[voice] = (volumeCache[voice] &0xc0) | volume; | |
402 | |
403 int const op_offset = ( voice < kSnareDrumChannel || rol_header->mode ) ? | |
404 op_table[voice]+3 : drum_table[voice-kSnareDrumChannel]; | |
405 | |
406 opl->write( 0x40+op_offset, volumeCache[voice] ); | |
407 } | |
408 //--------------------------------------------------------- | |
409 void CrolPlayer::send_ins_data_to_chip( int const voice, int const ins_index ) | |
410 { | |
411 SRolInstrument &instrument = ins_list[ins_index].instrument; | |
412 | |
413 send_operator( voice, instrument.modulator, instrument.carrier ); | |
414 } | |
415 //--------------------------------------------------------- | |
416 void CrolPlayer::send_operator( int const voice, SOPL2Op const &modulator, SOPL2Op const &carrier ) | |
417 { | |
418 if( voice < kSnareDrumChannel || rol_header->mode ) | |
419 { | |
420 int const op_offset = op_table[voice]; | |
421 | |
422 opl->write( 0x20+op_offset, modulator.ammulti ); | |
423 opl->write( 0x40+op_offset, modulator.ksltl ); | |
424 opl->write( 0x60+op_offset, modulator.ardr ); | |
425 opl->write( 0x80+op_offset, modulator.slrr ); | |
426 opl->write( 0xc0+voice , modulator.fbc ); | |
427 opl->write( 0xe0+op_offset, modulator.waveform ); | |
428 | |
429 volumeCache[voice] = (carrier.ksltl & 0xc0) | volumeCache[voice] & 0x3f; | |
430 | |
431 opl->write( 0x23+op_offset, carrier.ammulti ); | |
432 opl->write( 0x43+op_offset, volumeCache[voice] ); | |
433 opl->write( 0x63+op_offset, carrier.ardr ); | |
434 opl->write( 0x83+op_offset, carrier.slrr ); | |
435 // opl->write( 0xc3+voice , carrier.fbc ); <- don't bother writing this. | |
436 opl->write( 0xe3+op_offset, carrier.waveform ); | |
437 } | |
438 else | |
439 { | |
440 int const op_offset = drum_table[voice-kSnareDrumChannel]; | |
441 | |
442 volumeCache[voice] = (modulator.ksltl & 0xc0) | volumeCache[voice] & 0x3f; | |
443 | |
444 opl->write( 0x20+op_offset, modulator.ammulti ); | |
445 opl->write( 0x40+op_offset, volumeCache[voice] ); | |
446 opl->write( 0x60+op_offset, modulator.ardr ); | |
447 opl->write( 0x80+op_offset, modulator.slrr ); | |
448 opl->write( 0xc0+voice , modulator.fbc ); | |
449 opl->write( 0xe0+op_offset, modulator.waveform ); | |
450 } | |
451 } | |
452 //--------------------------------------------------------- | |
453 void CrolPlayer::load_tempo_events( binistream *f ) | |
454 { | |
455 int16 const num_tempo_events = f->readInt( 2 ); | |
456 | |
457 mTempoEvents.reserve( num_tempo_events ); | |
458 | |
459 for(int i=0; i<num_tempo_events; ++i) | |
460 { | |
461 STempoEvent event; | |
462 | |
463 event.time = f->readInt( 2 ); | |
464 event.multiplier = f->readFloat( binio::Single ); | |
465 mTempoEvents.push_back( event ); | |
466 } | |
467 } | |
468 //--------------------------------------------------------- | |
469 bool CrolPlayer::load_voice_data( binistream *f, std::string const &bnk_filename, const CFileProvider &fp ) | |
470 { | |
471 SBnkHeader bnk_header; | |
472 VFSFile *fd = vfs_fopen(bnk_filename.c_str(), "rb"); | |
473 binistream *bnk_file = fp.open(fd); | |
474 | |
475 if( bnk_file ) | |
476 { | |
477 load_bnk_info( bnk_file, bnk_header ); | |
478 | |
479 int const numVoices = rol_header->mode ? kNumMelodicVoices : kNumPercussiveVoices; | |
480 | |
481 voice_data.reserve( numVoices ); | |
482 for(int i=0; i<numVoices; ++i) | |
483 { | |
484 CVoiceData voice; | |
485 | |
486 load_note_events( f, voice ); | |
487 load_instrument_events( f, voice, bnk_file, bnk_header ); | |
488 load_volume_events( f, voice ); | |
489 load_pitch_events( f, voice ); | |
490 | |
491 voice_data.push_back( voice ); | |
492 } | |
493 | |
494 fp.close(bnk_file); | |
495 vfs_fclose(fd); | |
496 | |
497 return true; | |
498 } | |
499 | |
500 return false; | |
501 } | |
502 //--------------------------------------------------------- | |
503 void CrolPlayer::load_note_events( binistream *f, CVoiceData &voice ) | |
504 { | |
505 f->seek( 15, binio::Add ); | |
506 | |
507 int16 const time_of_last_note = f->readInt( 2 ); | |
508 | |
509 if( time_of_last_note != 0 ) | |
510 { | |
511 TNoteEvents ¬e_events = voice.note_events; | |
512 int16 total_duration = 0; | |
513 | |
514 do | |
515 { | |
516 SNoteEvent event; | |
517 | |
518 event.number = f->readInt( 2 ); | |
519 event.duration = f->readInt( 2 ); | |
520 | |
521 event.number += kSilenceNote; // adding -12 | |
522 | |
523 note_events.push_back( event ); | |
524 | |
525 total_duration += event.duration; | |
526 } while( total_duration < time_of_last_note ); | |
527 | |
528 if( time_of_last_note > mTimeOfLastNote ) | |
529 { | |
530 mTimeOfLastNote = time_of_last_note; | |
531 } | |
532 } | |
533 | |
534 f->seek( 15, binio::Add ); | |
535 } | |
536 //--------------------------------------------------------- | |
537 void CrolPlayer::load_instrument_events( binistream *f, CVoiceData &voice, | |
538 binistream *bnk_file, SBnkHeader const &bnk_header ) | |
539 { | |
540 int16 const number_of_instrument_events = f->readInt( 2 ); | |
541 | |
542 TInstrumentEvents &instrument_events = voice.instrument_events; | |
543 | |
544 instrument_events.reserve( number_of_instrument_events ); | |
545 | |
546 for(int i=0; i<number_of_instrument_events; ++i) | |
547 { | |
548 SInstrumentEvent event; | |
549 event.time = f->readInt( 2 ); | |
550 f->readString( event.name, 9 ); | |
551 | |
552 std::string event_name = event.name; | |
553 event.ins_index = load_rol_instrument( bnk_file, bnk_header, event_name ); | |
554 | |
555 instrument_events.push_back( event ); | |
556 | |
557 f->seek( 1+2, binio::Add ); | |
558 } | |
559 | |
560 f->seek( 15, binio::Add ); | |
561 } | |
562 //--------------------------------------------------------- | |
563 void CrolPlayer::load_volume_events( binistream *f, CVoiceData &voice ) | |
564 { | |
565 int16 const number_of_volume_events = f->readInt( 2 ); | |
566 | |
567 TVolumeEvents &volume_events = voice.volume_events; | |
568 | |
569 volume_events.reserve( number_of_volume_events ); | |
570 | |
571 for(int i=0; i<number_of_volume_events; ++i) | |
572 { | |
573 SVolumeEvent event; | |
574 event.time = f->readInt( 2 ); | |
575 event.multiplier = f->readFloat( binio::Single ); | |
576 | |
577 volume_events.push_back( event ); | |
578 } | |
579 | |
580 f->seek( 15, binio::Add ); | |
581 } | |
582 //--------------------------------------------------------- | |
583 void CrolPlayer::load_pitch_events( binistream *f, CVoiceData &voice ) | |
584 { | |
585 int16 const number_of_pitch_events = f->readInt( 2 ); | |
586 | |
587 TPitchEvents &pitch_events = voice.pitch_events; | |
588 | |
589 pitch_events.reserve( number_of_pitch_events ); | |
590 | |
591 for(int i=0; i<number_of_pitch_events; ++i) | |
592 { | |
593 SPitchEvent event; | |
594 event.time = f->readInt( 2 ); | |
595 event.variation = f->readFloat( binio::Single ); | |
596 | |
597 pitch_events.push_back( event ); | |
598 } | |
599 } | |
600 //--------------------------------------------------------- | |
601 bool CrolPlayer::load_bnk_info( binistream *f, SBnkHeader &header ) | |
602 { | |
603 header.version_major = f->readInt(1); | |
604 header.version_minor = f->readInt(1); | |
605 f->readString( header.signature, 6 ); | |
606 | |
607 header.number_of_list_entries_used = f->readInt( 2 ); | |
608 header.total_number_of_list_entries = f->readInt( 2 ); | |
609 | |
610 header.abs_offset_of_name_list = f->readInt( 4 ); | |
611 header.abs_offset_of_data = f->readInt( 4 ); | |
612 | |
613 f->seek( header.abs_offset_of_name_list, binio::Set ); | |
614 | |
615 TInstrumentNames &ins_name_list = header.ins_name_list; | |
616 ins_name_list.reserve( header.number_of_list_entries_used ); | |
617 | |
618 for(int i=0; i<header.number_of_list_entries_used; ++i) | |
619 { | |
620 SInstrumentName instrument; | |
621 | |
622 instrument.index = f->readInt( 2 ); | |
623 instrument.record_used = f->readInt(1); | |
624 f->readString( instrument.name, 9 ); | |
625 | |
626 // printf("%s = #%d\n", instrument.name, i ); | |
627 | |
628 ins_name_list.push_back( instrument ); | |
629 } | |
630 | 701 |
631 //std::sort( ins_name_list.begin(), ins_name_list.end(), StringCompare() ); | 702 //std::sort( ins_name_list.begin(), ins_name_list.end(), StringCompare() ); |
632 | 703 |
633 return true; | 704 return true; |
634 } | 705 } |
635 //--------------------------------------------------------- | 706 |
636 int CrolPlayer::load_rol_instrument( binistream *f, SBnkHeader const &header, std::string &name ) | 707 //--------------------------------------------------------- |
637 { | 708 int |
638 TInstrumentNames const &ins_name_list = header.ins_name_list; | 709 CrolPlayer::load_rol_instrument (binistream * f, SBnkHeader const &header, |
639 | 710 std::string & name) |
640 int const ins_index = get_ins_index( name ); | 711 { |
641 | 712 TInstrumentNames const &ins_name_list = header.ins_name_list; |
642 if( ins_index != -1 ) | 713 |
643 { | 714 int const ins_index = get_ins_index (name); |
644 return ins_index; | 715 |
645 } | 716 if (ins_index != -1) |
646 | 717 { |
647 typedef TInstrumentNames::const_iterator TInsIter; | 718 return ins_index; |
648 typedef std::pair<TInsIter, TInsIter> TInsIterPair; | 719 } |
649 | 720 |
650 TInsIterPair range = std::equal_range( ins_name_list.begin(), | 721 typedef TInstrumentNames::const_iterator TInsIter; |
651 ins_name_list.end(), | 722 typedef std::pair < TInsIter, TInsIter > TInsIterPair; |
652 name, | 723 |
653 StringCompare() ); | 724 TInsIterPair range = std::equal_range (ins_name_list.begin (), |
654 | 725 ins_name_list.end (), |
655 if( range.first != range.second ) | 726 name, |
656 { | 727 StringCompare ()); |
657 int const seekOffs = header.abs_offset_of_data + (range.first->index*kSizeofDataRecord); | 728 |
658 f->seek( seekOffs, binio::Set ); | 729 if (range.first != range.second) |
659 } | 730 { |
660 | 731 int const seekOffs = |
661 SUsedList usedIns; | 732 header.abs_offset_of_data + (range.first->index * kSizeofDataRecord); |
662 usedIns.name = name; | 733 f->seek (seekOffs, binio::Set); |
663 | 734 } |
664 if( range.first != range.second ) | 735 |
665 { | 736 SUsedList usedIns; |
666 read_rol_instrument( f, usedIns.instrument ); | 737 usedIns.name = name; |
667 } | 738 |
668 else | 739 if (range.first != range.second) |
669 { | 740 { |
670 // set up default instrument data here | 741 read_rol_instrument (f, usedIns.instrument); |
671 memset( &usedIns.instrument, 0, kSizeofDataRecord ); | 742 } |
672 } | 743 else |
673 ins_list.push_back( usedIns ); | 744 { |
674 | 745 // set up default instrument data here |
675 return ins_list.size()-1; | 746 memset (&usedIns.instrument, 0, kSizeofDataRecord); |
676 } | 747 } |
677 //--------------------------------------------------------- | 748 ins_list.push_back (usedIns); |
678 int CrolPlayer::get_ins_index( std::string const &name ) const | 749 |
679 { | 750 return ins_list.size () - 1; |
680 for(unsigned int i=0; i<ins_list.size(); ++i) | 751 } |
681 { | 752 |
682 if( stricmp(ins_list[i].name.c_str(), name.c_str()) == 0 ) | 753 //--------------------------------------------------------- |
683 { | 754 int |
684 return i; | 755 CrolPlayer::get_ins_index (std::string const &name) const const |
685 } | 756 { |
686 } | 757 for (unsigned int i = 0; i < ins_list.size (); ++i) |
687 | 758 { |
688 return -1; | 759 if (stricmp (ins_list[i].name.c_str (), name.c_str ()) == 0) |
689 } | 760 { |
690 //--------------------------------------------------------- | 761 return i; |
691 void CrolPlayer::read_rol_instrument( binistream *f, SRolInstrument &ins ) | 762 } |
692 { | 763 } |
693 ins.mode = f->readInt(1); | 764 |
694 ins.voice_number = f->readInt(1); | 765 return -1; |
695 | 766 } |
696 read_fm_operator( f, ins.modulator ); | 767 |
697 read_fm_operator( f, ins.carrier ); | 768 //--------------------------------------------------------- |
698 | 769 void |
699 ins.modulator.waveform = f->readInt(1); | 770 CrolPlayer::read_rol_instrument (binistream * f, SRolInstrument & ins) |
700 ins.carrier.waveform = f->readInt(1); | 771 { |
701 } | 772 ins.mode = f->readInt (1); |
702 //--------------------------------------------------------- | 773 ins.voice_number = f->readInt (1); |
703 void CrolPlayer::read_fm_operator( binistream *f, SOPL2Op &opl2_op ) | 774 |
775 read_fm_operator (f, ins.modulator); | |
776 read_fm_operator (f, ins.carrier); | |
777 | |
778 ins.modulator.waveform = f->readInt (1); | |
779 ins.carrier.waveform = f->readInt (1); | |
780 } | |
781 | |
782 //--------------------------------------------------------- | |
783 void | |
784 CrolPlayer::read_fm_operator (binistream * f, SOPL2Op & opl2_op) | |
704 { | 785 { |
705 SFMOperator fm_op; | 786 SFMOperator fm_op; |
706 | 787 |
707 fm_op.key_scale_level = f->readInt(1); | 788 fm_op.key_scale_level = f->readInt (1); |
708 fm_op.freq_multiplier = f->readInt(1); | 789 fm_op.freq_multiplier = f->readInt (1); |
709 fm_op.feed_back = f->readInt(1); | 790 fm_op.feed_back = f->readInt (1); |
710 fm_op.attack_rate = f->readInt(1); | 791 fm_op.attack_rate = f->readInt (1); |
711 fm_op.sustain_level = f->readInt(1); | 792 fm_op.sustain_level = f->readInt (1); |
712 fm_op.sustaining_sound = f->readInt(1); | 793 fm_op.sustaining_sound = f->readInt (1); |
713 fm_op.decay_rate = f->readInt(1); | 794 fm_op.decay_rate = f->readInt (1); |
714 fm_op.release_rate = f->readInt(1); | 795 fm_op.release_rate = f->readInt (1); |
715 fm_op.output_level = f->readInt(1); | 796 fm_op.output_level = f->readInt (1); |
716 fm_op.amplitude_vibrato = f->readInt(1); | 797 fm_op.amplitude_vibrato = f->readInt (1); |
717 fm_op.frequency_vibrato = f->readInt(1); | 798 fm_op.frequency_vibrato = f->readInt (1); |
718 fm_op.envelope_scaling = f->readInt(1); | 799 fm_op.envelope_scaling = f->readInt (1); |
719 fm_op.fm_type = f->readInt(1); | 800 fm_op.fm_type = f->readInt (1); |
720 | 801 |
721 opl2_op.ammulti = fm_op.amplitude_vibrato << 7 | fm_op.frequency_vibrato << 6 | fm_op.sustaining_sound << 5 | fm_op.envelope_scaling << 4 | fm_op.freq_multiplier; | 802 opl2_op.ammulti = |
722 opl2_op.ksltl = fm_op.key_scale_level << 6 | fm_op.output_level; | 803 fm_op.amplitude_vibrato << 7 | fm_op.frequency_vibrato << 6 | fm_op. |
723 opl2_op.ardr = fm_op.attack_rate << 4 | fm_op.decay_rate; | 804 sustaining_sound << 5 | fm_op.envelope_scaling << 4 | fm_op. |
724 opl2_op.slrr = fm_op.sustain_level << 4 | fm_op.release_rate; | 805 freq_multiplier; |
725 opl2_op.fbc = fm_op.feed_back << 1 | (fm_op.fm_type ^ 1); | 806 opl2_op.ksltl = fm_op.key_scale_level << 6 | fm_op.output_level; |
726 } | 807 opl2_op.ardr = fm_op.attack_rate << 4 | fm_op.decay_rate; |
808 opl2_op.slrr = fm_op.sustain_level << 4 | fm_op.release_rate; | |
809 opl2_op.fbc = fm_op.feed_back << 1 | (fm_op.fm_type ^ 1); | |
810 } |