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