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 &noteEvent = 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 &noteEvent = 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 &note_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 }