]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug-2.2.1/src/cmf.cpp
Please enter the commit message for your changes. Lines starting
[16.git] / 16 / adplug / adplug-2.2.1 / src / cmf.cpp
1 /*
2  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3  * Copyright (C) 1999 - 2009 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * cmf.cpp - CMF player by Adam Nielsen <malvineous@shikadi.net>
20  *   Subset of CMF reader in MOPL code (Malvineous' OPL player), no seeking etc.
21  */
22
23 #include <stdint.h> // for uintxx_t
24 #include <cassert>
25 #include <math.h> // for pow() etc.
26 #include <string.h> // for memset
27 #include "debug.h"
28 #include "cmf.h"
29
30 // ------------------------------
31 // OPTIONS
32 // ------------------------------
33
34 // The official Creative Labs CMF player seems to ignore the note velocity
35 // (playing every note at the same volume), but you can uncomment this to
36 // allow the note velocity to affect the volume (as presumably the composer
37 // originally intended.)
38 //
39 //#define USE_VELOCITY
40 //
41 // The Xargon demo song is a good example of a song that uses note velocity.
42
43 // OPL register offsets
44 #define BASE_CHAR_MULT  0x20
45 #define BASE_SCAL_LEVL  0x40
46 #define BASE_ATCK_DCAY  0x60
47 #define BASE_SUST_RLSE  0x80
48 #define BASE_FNUM_L     0xA0
49 #define BASE_KEYON_FREQ 0xB0
50 #define BASE_RHYTHM     0xBD
51 #define BASE_WAVE       0xE0
52 #define BASE_FEED_CONN  0xC0
53
54 #define OPLBIT_KEYON    0x20 // Bit in BASE_KEYON_FREQ register for turning a note on
55
56 // Supplied with a channel, return the offset from a base OPL register for the
57 // Modulator cell (e.g. channel 4's modulator is at offset 0x09.  Since 0x60 is
58 // the attack/decay function, register 0x69 will thus set the attack/decay for
59 // channel 4's modulator.)  (channels go from 0 to 8 inclusive)
60 #define OPLOFFSET(channel)   (((channel) / 3) * 8 + ((channel) % 3))
61
62 // These 16 instruments are repeated to fill up the 128 available slots.  A CMF
63 // file can override none/some/all of the 128 slots with custom instruments,
64 // so any that aren't overridden are still available for use with these default
65 // patches.  The Word Rescue CMFs are good examples of songs that rely on these
66 // default patches.
67 uint8_t cDefaultPatches[] =
68 "\x01\x11\x4F\x00\xF1\xD2\x53\x74\x00\x00\x06"
69 "\x07\x12\x4F\x00\xF2\xF2\x60\x72\x00\x00\x08"
70 "\x31\xA1\x1C\x80\x51\x54\x03\x67\x00\x00\x0E"
71 "\x31\xA1\x1C\x80\x41\x92\x0B\x3B\x00\x00\x0E"
72 "\x31\x16\x87\x80\xA1\x7D\x11\x43\x00\x00\x08"
73 "\x30\xB1\xC8\x80\xD5\x61\x19\x1B\x00\x00\x0C"
74 "\xF1\x21\x01\x00\x97\xF1\x17\x18\x00\x00\x08"
75 "\x32\x16\x87\x80\xA1\x7D\x10\x33\x00\x00\x08"
76 "\x01\x12\x4F\x00\x71\x52\x53\x7C\x00\x00\x0A"
77 "\x02\x03\x8D\x00\xD7\xF5\x37\x18\x00\x00\x04"
78 "\x21\x21\xD1\x00\xA3\xA4\x46\x25\x00\x00\x0A"
79 "\x22\x22\x0F\x00\xF6\xF6\x95\x36\x00\x00\x0A"
80 "\xE1\xE1\x00\x00\x44\x54\x24\x34\x02\x02\x07"
81 "\xA5\xB1\xD2\x80\x81\xF1\x03\x05\x00\x00\x02"
82 "\x71\x22\xC5\x00\x6E\x8B\x17\x0E\x00\x00\x02"
83 "\x32\x21\x16\x80\x73\x75\x24\x57\x00\x00\x0E";
84
85
86 CPlayer *CcmfPlayer::factory(Copl *newopl)
87 {
88   return new CcmfPlayer(newopl);
89 }
90
91 CcmfPlayer::CcmfPlayer(Copl *newopl) :
92         CPlayer(newopl),
93         data(NULL),
94         pInstruments(NULL),
95         bPercussive(false),
96         iTranspose(0),
97         iPrevCommand(0)
98 {
99         assert(OPLOFFSET(1-1) == 0x00);
100         assert(OPLOFFSET(5-1) == 0x09);
101         assert(OPLOFFSET(9-1) == 0x12);
102 }
103
104 CcmfPlayer::~CcmfPlayer()
105 {
106         if (this->data) delete[] data;
107         if (this->pInstruments) delete[] pInstruments;
108 }
109
110 bool CcmfPlayer::load(const std::string &filename, const CFileProvider &fp)
111 {
112   binistream *f = fp.open(filename); if(!f) return false;
113
114         char cSig[4];
115         f->readString(cSig, 4);
116         if (
117                 (cSig[0] != 'C') ||
118                 (cSig[1] != 'T') ||
119                 (cSig[2] != 'M') ||
120                 (cSig[3] != 'F')
121         ) {
122                 // Not a CMF file
123                 fp.close(f);
124                 return false;
125         }
126         uint16_t iVer = f->readInt(2);
127         if ((iVer != 0x0101) && (iVer != 0x0100)) {
128                 AdPlug_LogWrite("CMF file is not v1.0 or v1.1 (reports %d.%d)\n", iVer >> 8 , iVer & 0xFF);
129                 fp.close(f);
130                 return false;
131         }
132
133         this->cmfHeader.iInstrumentBlockOffset = f->readInt(2);
134         this->cmfHeader.iMusicOffset = f->readInt(2);
135         this->cmfHeader.iTicksPerQuarterNote = f->readInt(2);
136         this->cmfHeader.iTicksPerSecond = f->readInt(2);
137         this->cmfHeader.iTagOffsetTitle = f->readInt(2);
138         this->cmfHeader.iTagOffsetComposer = f->readInt(2);
139         this->cmfHeader.iTagOffsetRemarks = f->readInt(2);
140         f->readString((char *)this->cmfHeader.iChannelsInUse, 16);
141         if (iVer == 0x0100) {
142                 this->cmfHeader.iNumInstruments = f->readInt(1);
143                 this->cmfHeader.iTempo = 0;
144         } else { // 0x0101
145                 this->cmfHeader.iNumInstruments = f->readInt(2);
146                 this->cmfHeader.iTempo = f->readInt(2);
147         }
148
149         // Load the instruments
150
151         f->seek(this->cmfHeader.iInstrumentBlockOffset);
152         this->pInstruments = new SBI[
153                 (this->cmfHeader.iNumInstruments < 128) ? 128 : this->cmfHeader.iNumInstruments
154         ];  // Always at least 128 available for use
155
156         for (int i = 0; i < this->cmfHeader.iNumInstruments; i++) {
157                 this->pInstruments[i].op[0].iCharMult = f->readInt(1);
158                 this->pInstruments[i].op[1].iCharMult = f->readInt(1);
159                 this->pInstruments[i].op[0].iScalingOutput = f->readInt(1);
160                 this->pInstruments[i].op[1].iScalingOutput = f->readInt(1);
161                 this->pInstruments[i].op[0].iAttackDecay = f->readInt(1);
162                 this->pInstruments[i].op[1].iAttackDecay = f->readInt(1);
163                 this->pInstruments[i].op[0].iSustainRelease = f->readInt(1);
164                 this->pInstruments[i].op[1].iSustainRelease = f->readInt(1);
165                 this->pInstruments[i].op[0].iWaveSel = f->readInt(1);
166                 this->pInstruments[i].op[1].iWaveSel = f->readInt(1);
167                 this->pInstruments[i].iConnection = f->readInt(1);
168                 f->seek(5, binio::Add);  // skip over the padding bytes
169         }
170
171         // Set the rest of the instruments to the CMF defaults
172         for (int i = this->cmfHeader.iNumInstruments; i < 128; i++) {
173                 this->pInstruments[i].op[0].iCharMult =       cDefaultPatches[(i % 16) * 11 + 0];
174                 this->pInstruments[i].op[1].iCharMult =       cDefaultPatches[(i % 16) * 11 + 1];
175                 this->pInstruments[i].op[0].iScalingOutput =  cDefaultPatches[(i % 16) * 11 + 2];
176                 this->pInstruments[i].op[1].iScalingOutput =  cDefaultPatches[(i % 16) * 11 + 3];
177                 this->pInstruments[i].op[0].iAttackDecay =    cDefaultPatches[(i % 16) * 11 + 4];
178                 this->pInstruments[i].op[1].iAttackDecay =    cDefaultPatches[(i % 16) * 11 + 5];
179                 this->pInstruments[i].op[0].iSustainRelease = cDefaultPatches[(i % 16) * 11 + 6];
180                 this->pInstruments[i].op[1].iSustainRelease = cDefaultPatches[(i % 16) * 11 + 7];
181                 this->pInstruments[i].op[0].iWaveSel =        cDefaultPatches[(i % 16) * 11 + 8];
182                 this->pInstruments[i].op[1].iWaveSel =        cDefaultPatches[(i % 16) * 11 + 9];
183                 this->pInstruments[i].iConnection =           cDefaultPatches[(i % 16) * 11 + 10];
184         }
185
186         if (this->cmfHeader.iTagOffsetTitle) {
187                 f->seek(this->cmfHeader.iTagOffsetTitle);
188                 this->strTitle = f->readString('\0');
189         }
190         if (this->cmfHeader.iTagOffsetComposer) {
191                 f->seek(this->cmfHeader.iTagOffsetComposer);
192                 this->strComposer = f->readString('\0');
193         }
194         if (this->cmfHeader.iTagOffsetRemarks) {
195                 f->seek(this->cmfHeader.iTagOffsetRemarks);
196                 this->strRemarks = f->readString('\0');
197         }
198
199         // Load the MIDI data into memory
200   f->seek(this->cmfHeader.iMusicOffset);
201   this->iSongLen = fp.filesize(f) - this->cmfHeader.iMusicOffset;
202   this->data = new unsigned char[this->iSongLen];
203   f->readString((char *)data, this->iSongLen);
204
205   fp.close(f);
206         rewind(0);
207
208   return true;
209 }
210
211 bool CcmfPlayer::update()
212 {
213         // This has to be here and not in getrefresh() for some reason.
214         this->iDelayRemaining = 0;
215
216         // Read in the next event
217         while (!this->iDelayRemaining) {
218                 uint8_t iCommand = this->data[this->iPlayPointer++];
219                 if ((iCommand & 0x80) == 0) {
220                         // Running status, use previous command
221                         this->iPlayPointer--;
222                         iCommand = this->iPrevCommand;
223                 } else {
224                         this->iPrevCommand = iCommand;
225                 }
226                 uint8_t iChannel = iCommand & 0x0F;
227                 switch (iCommand & 0xF0) {
228                         case 0x80: { // Note off (two data bytes)
229                                 uint8_t iNote = this->data[this->iPlayPointer++];
230                                 uint8_t iVelocity = this->data[this->iPlayPointer++]; // release velocity
231                                 this->cmfNoteOff(iChannel, iNote, iVelocity);
232                                 break;
233                         }
234                         case 0x90: { // Note on (two data bytes)
235                                 uint8_t iNote = this->data[this->iPlayPointer++];
236                                 uint8_t iVelocity = this->data[this->iPlayPointer++]; // attack velocity
237                                 if (iVelocity) {
238                                         this->cmfNoteOn(iChannel, iNote, iVelocity);
239                                 } else {
240                                         // This is a note-off instead (velocity == 0)
241                                         this->cmfNoteOff(iChannel, iNote, iVelocity); // 64 is the MIDI default note-off velocity
242                                         break;
243                                 }
244                                 break;
245                         }
246                         case 0xA0: { // Polyphonic key pressure (two data bytes)
247                                 uint8_t iNote = this->data[this->iPlayPointer++];
248                                 uint8_t iPressure = this->data[this->iPlayPointer++];
249                                 AdPlug_LogWrite("CMF: Key pressure not yet implemented! (wanted ch%d/note %d set to %d)\n", iChannel, iNote, iPressure);
250                                 break;
251                         }
252                         case 0xB0: { // Controller (two data bytes)
253                                 uint8_t iController = this->data[this->iPlayPointer++];
254                                 uint8_t iValue = this->data[this->iPlayPointer++];
255                                 this->MIDIcontroller(iChannel, iController, iValue);
256                                 break;
257                         }
258                         case 0xC0: { // Instrument change (one data byte)
259                                 uint8_t iNewInstrument = this->data[this->iPlayPointer++];
260                                 this->chMIDI[iChannel].iPatch = iNewInstrument;
261                                 AdPlug_LogWrite("CMF: Remembering MIDI channel %d now uses patch %d\n", iChannel, iNewInstrument);
262                                 break;
263                         }
264                         case 0xD0: { // Channel pressure (one data byte)
265                                 uint8_t iPressure = this->data[this->iPlayPointer++];
266                                 AdPlug_LogWrite("CMF: Channel pressure not yet implemented! (wanted ch%d set to %d)\n", iChannel, iPressure);
267                                 break;
268                         }
269                         case 0xE0: { // Pitch bend (two data bytes)
270                                 uint8_t iLSB = this->data[this->iPlayPointer++];
271                                 uint8_t iMSB = this->data[this->iPlayPointer++];
272                                 uint16_t iValue = (iMSB << 7) | iLSB;
273                                 // 8192 is middle/off, 0 is -2 semitones, 16384 is +2 semitones
274                                 this->chMIDI[iChannel].iPitchbend = iValue;
275                                 AdPlug_LogWrite("CMF: Channel %d pitchbent to %d (%+.2f)\n", iChannel + 1, iValue, (float)(iValue - 8192) / 8192);
276                                 break;
277                         }
278                         case 0xF0: // System message (arbitrary data bytes)
279                                 switch (iCommand) {
280                                         case 0xF0: { // Sysex
281                                                 uint8_t iNextByte;
282                                                 AdPlug_LogWrite("Sysex message: ");
283                                                 do {
284                                                         iNextByte = this->data[this->iPlayPointer++];
285                                                         AdPlug_LogWrite("%02X", iNextByte);
286                                                 } while ((iNextByte & 0x80) == 0);
287                                                 AdPlug_LogWrite("\n");
288                                                 // This will have read in the terminating EOX (0xF7) message too
289                                                 break;
290                                         }
291                                         case 0xF1: // MIDI Time Code Quarter Frame
292                                                 this->data[this->iPlayPointer++]; // message data (ignored)
293                                                 break;
294                                         case 0xF2: // Song position pointer
295                                                 this->data[this->iPlayPointer++]; // message data (ignored)
296                                                 this->data[this->iPlayPointer++];
297                                                 break;
298                                         case 0xF3: // Song select
299                                                 this->data[this->iPlayPointer++]; // message data (ignored)
300                                                 AdPlug_LogWrite("CMF: MIDI Song Select is not implemented.\n");
301                                                 break;
302                                         case 0xF6: // Tune request
303                                                 break;
304                                         case 0xF7: // End of System Exclusive (EOX) - should never be read, should be absorbed by Sysex handling code
305                                                 break;
306
307                                         // These messages are "real time", meaning they can be sent between
308                                         // the bytes of other messages - but we're lazy and don't handle these
309                                         // here (hopefully they're not necessary in a MIDI file, and even less
310                                         // likely to occur in a CMF.)
311                                         case 0xF8: // Timing clock (sent 24 times per quarter note, only when playing)
312                                         case 0xFA: // Start
313                                         case 0xFB: // Continue
314                                         case 0xFE: // Active sensing (sent every 300ms or MIDI connection assumed lost)
315                                                 break;
316                                         case 0xFC: // Stop
317                                                 AdPlug_LogWrite("CMF: Received Real Time Stop message (0xFC)\n");
318                                                 this->bSongEnd = true;
319                                                 this->iPlayPointer = 0; // for repeat in endless-play mode
320                                                 break;
321                                         case 0xFF: { // System reset, used as meta-events in a MIDI file
322                                                 uint8_t iEvent = this->data[this->iPlayPointer++];
323                                                 switch (iEvent) {
324                                                         case 0x2F: // end of track
325                                                                 AdPlug_LogWrite("CMF: End-of-track, stopping playback\n");
326                                                                 this->bSongEnd = true;
327                                                                 this->iPlayPointer = 0; // for repeat in endless-play mode
328                                                                 break;
329                                                         default:
330                                                                 AdPlug_LogWrite("CMF: Unknown MIDI meta-event 0xFF 0x%02X\n", iEvent);
331                                                                 break;
332                                                 }
333                                                 break;
334                                         }
335                                         default:
336                                                 AdPlug_LogWrite("CMF: Unknown MIDI system command 0x%02X\n", iCommand);
337                                                 break;
338                                 }
339                                 break;
340                         default:
341                                 AdPlug_LogWrite("CMF: Unknown MIDI command 0x%02X\n", iCommand);
342                                 break;
343                 }
344
345                 if (this->iPlayPointer >= this->iSongLen) {
346                         this->bSongEnd = true;
347                         this->iPlayPointer = 0; // for repeat in endless-play mode
348                 }
349
350                 // Read in the number of ticks until the next event
351                 this->iDelayRemaining = this->readMIDINumber();
352         }
353
354         return !this->bSongEnd;
355 }
356
357 void CcmfPlayer::rewind(int subsong)
358 {
359   this->opl->init();
360
361         // Initialise
362
363   // Enable use of WaveSel register on OPL3 (even though we're only an OPL2!)
364   // Apparently this enables nine-channel mode?
365         this->writeOPL(0x01, 0x20);
366
367         // Disable OPL3 mode (can be left enabled by a previous non-CMF song)
368         this->writeOPL(0x05, 0x00);
369
370         // Really make sure CSM+SEL are off (again, Creative's player...)
371         this->writeOPL(0x08, 0x00);
372
373         // This freq setting is required for the hihat to sound correct at the start
374         // of funky.cmf, even though it's for an unrelated channel.
375         // If it's here however, it makes the hihat in Word Rescue's theme.cmf
376         // sound really bad.
377         // TODO: How do we figure out whether we need it or not???
378         this->writeOPL(BASE_FNUM_L + 8, 514 & 0xFF);
379         this->writeOPL(BASE_KEYON_FREQ + 8, (1 << 2) | (514 >> 8));
380
381         // default freqs?
382         this->writeOPL(BASE_FNUM_L + 7, 509 & 0xFF);
383         this->writeOPL(BASE_KEYON_FREQ + 7, (2 << 2) | (509 >> 8));
384         this->writeOPL(BASE_FNUM_L + 6, 432 & 0xFF);
385         this->writeOPL(BASE_KEYON_FREQ + 6, (2 << 2) | (432 >> 8));
386
387         // Amplify AM + VIB depth.  Creative's CMF player does this, and there
388         // doesn't seem to be any way to stop it from doing so - except for the
389         // non-standard controller 0x63 I added :-)
390         this->writeOPL(0xBD, 0xC0);
391
392         this->bSongEnd = false;
393         this->iPlayPointer = 0;
394         this->iPrevCommand = 0; // just in case
395
396         // Read in the number of ticks until the first event
397         this->iDelayRemaining = this->readMIDINumber();
398
399   // Reset song state.  This used to be in the constructor, but the XMMS2
400   // plugin sets the song length before starting playback.  AdPlug plays the
401   // song in its entirety (with no synth) to determine the song length, which
402   // results in the state variables below matching the end of the song.  When
403   // the real OPL synth is activated for playback, it no longer matches the
404   // state variables and the instruments are not set correctly!
405         for (int i = 0; i < 9; i++) {
406                 this->chOPL[i].iNoteStart = 0; // no note playing atm
407                 this->chOPL[i].iMIDINote = -1;
408                 this->chOPL[i].iMIDIChannel = -1;
409                 this->chOPL[i].iMIDIPatch = -1;
410
411                 this->chMIDI[i].iPatch = -2;
412                 this->chMIDI[i].iPitchbend = 8192;
413         }
414         for (int i = 9; i < 16; i++) {
415                 this->chMIDI[i].iPatch = -2;
416                 this->chMIDI[i].iPitchbend = 8192;
417         }
418
419         memset(this->iCurrentRegs, 0, 256);
420
421         return;
422 }
423
424 // Return value: 1 == 1 second, 2 == 0.5 seconds
425 float CcmfPlayer::getrefresh()
426 {
427         if (this->iDelayRemaining) {
428                 return (float)this->cmfHeader.iTicksPerSecond / (float)this->iDelayRemaining;
429         } else {
430                 // Delay-remaining is zero (e.g. start of song) so use a tiny delay
431                 return this->cmfHeader.iTicksPerSecond; // wait for one tick
432         }
433 }
434
435 std::string CcmfPlayer::gettitle()
436 {
437         return this->strTitle;
438 }
439 std::string CcmfPlayer::getauthor()
440 {
441         return this->strComposer;
442 }
443 std::string CcmfPlayer::getdesc()
444 {
445         return this->strRemarks;
446 }
447
448
449 //
450 // PROTECTED
451 //
452
453 // Read a variable-length integer from MIDI data
454 uint32_t CcmfPlayer::readMIDINumber()
455 {
456         uint32_t iValue = 0;
457         for (int i = 0; i < 4; i++) {
458                 uint8_t iNext = this->data[this->iPlayPointer++];
459                 iValue <<= 7;
460                 iValue |= (iNext & 0x7F); // ignore the MSB
461                 if ((iNext & 0x80) == 0) break; // last byte has the MSB unset
462         }
463         return iValue;
464 }
465
466 // iChannel: OPL channel (0-8)
467 // iOperator: 0 == Modulator, 1 == Carrier
468 //   Source - source operator to read from instrument definition
469 //   Dest - destination operator on OPL chip
470 // iInstrument: Index into this->pInstruments array of CMF instruments
471 void CcmfPlayer::writeInstrumentSettings(uint8_t iChannel, uint8_t iOperatorSource, uint8_t iOperatorDest, uint8_t iInstrument)
472 {
473         assert(iChannel <= 8);
474
475         uint8_t iOPLOffset = OPLOFFSET(iChannel);
476         if (iOperatorDest) iOPLOffset += 3; // Carrier if iOperator == 1 (else Modulator)
477
478         this->writeOPL(BASE_CHAR_MULT + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iCharMult);
479         this->writeOPL(BASE_SCAL_LEVL + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iScalingOutput);
480         this->writeOPL(BASE_ATCK_DCAY + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iAttackDecay);
481         this->writeOPL(BASE_SUST_RLSE + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iSustainRelease);
482         this->writeOPL(BASE_WAVE      + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iWaveSel);
483
484         // TODO: Check to see whether we should only be loading this for one or both operators
485         this->writeOPL(BASE_FEED_CONN + iChannel, this->pInstruments[iInstrument].iConnection);
486         return;
487 }
488
489 // Write a byte to the OPL "chip" and update the current record of register states
490 void CcmfPlayer::writeOPL(uint8_t iRegister, uint8_t iValue)
491 {
492         this->opl->write(iRegister, iValue);
493         this->iCurrentRegs[iRegister] = iValue;
494         return;
495 }
496
497 void CcmfPlayer::cmfNoteOn(uint8_t iChannel, uint8_t iNote, uint8_t iVelocity)
498 {
499         uint8_t iBlock = iNote / 12;
500         if (iBlock > 1) iBlock--; // keep in the same range as the Creative player
501         //if (iBlock > 7) iBlock = 7; // don't want to go out of range
502
503         double d = pow(2, (
504                 (double)iNote + (
505                         (this->chMIDI[iChannel].iPitchbend - 8192) / 8192.0
506                 ) + (
507                         this->iTranspose / 128
508                 ) - 9) / 12.0 - (iBlock - 20))
509                 * 440.0 / 32.0 / 50000.0;
510         uint16_t iOPLFNum = (uint16_t)(d+0.5);
511         if (iOPLFNum > 1023) AdPlug_LogWrite("CMF: This note is out of range! (send this song to malvineous@shikadi.net!)\n");
512
513         // See if we're playing a rhythm mode percussive instrument
514         if ((iChannel > 10) && (this->bPercussive)) {
515                 uint8_t iPercChannel = this->getPercChannel(iChannel);
516
517                 // Will have to set every time (easier) than figuring out whether the mod
518                 // or car needs to be changed.
519                 //if (this->chOPL[iPercChannel].iMIDIPatch != this->chMIDI[iChannel].iPatch) {
520                         this->MIDIchangeInstrument(iPercChannel, iChannel, this->chMIDI[iChannel].iPatch);
521                 //}
522
523                 /*  Velocity calculations - TODO: Work out the proper formula
524
525                 iVelocity -> iLevel  (values generated by Creative's player)
526                 7f -> 00
527                 7c -> 00
528
529                 7b -> 09
530                 73 -> 0a
531                 6b -> 0b
532                 63 -> 0c
533                 5b -> 0d
534                 53 -> 0e
535                 4b -> 0f
536                 43 -> 10
537                 3b -> 11
538                 33 -> 13
539                 2b -> 15
540                 23 -> 19
541                 1b -> 1b
542                 13 -> 1d
543                 0b -> 1f
544                 03 -> 21
545
546                 02 -> 21
547                 00 -> N/A (note off)
548                 */
549                 // Approximate formula, need to figure out more accurate one (my maths isn't so good...)
550                 int iLevel = 0x25 - sqrt(iVelocity * 16/*6*/);//(127 - iVelocity) * 0x20 / 127;
551                 if (iVelocity > 0x7b) iLevel = 0; // full volume
552                 if (iLevel < 0) iLevel = 0;
553                 if (iLevel > 0x3F) iLevel = 0x3F;
554                 //if (iVelocity < 0x40) iLevel = 0x10;
555
556                 int iOPLOffset = BASE_SCAL_LEVL + OPLOFFSET(iPercChannel);
557                 //if ((iChannel == 11) || (iChannel == 12) || (iChannel == 14)) {
558                 if (iChannel == 11) iOPLOffset += 3; // only do bassdrum carrier for volume control
559                 //iOPLOffset += 3; // carrier
560                 this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel);//(iVelocity * 0x3F / 127));
561                 //}
562                 // Bass drum (ch11) uses both operators
563                 //if (iChannel == 11) this->writeOPL(iOPLOffset + 3, (this->iCurrentRegs[iOPLOffset + 3] & ~0x3F) | iLevel);
564
565 /*              #ifdef USE_VELOCITY  // Official CMF player seems to ignore velocity levels
566                         uint16_t iLevel = 0x2F - (iVelocity * 0x2F / 127); // 0x2F should be 0x3F but it's too quiet then
567                         AdPlug_LogWrite("%02X + vel %d (lev %02X) == %02X\n", this->iCurrentRegs[iOPLOffset], iVelocity, iLevel, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel);
568                         //this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | (0x3F - (iVelocity >> 1)));//(iVelocity * 0x3F / 127));
569                         this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel);//(iVelocity * 0x3F / 127));
570                 #endif*/
571
572                 // Apparently you can't set the frequency for the cymbal or hihat?
573                 // Vinyl requires you don't set it, Kiloblaster requires you do!
574                 this->writeOPL(BASE_FNUM_L + iPercChannel, iOPLFNum & 0xFF);
575                 this->writeOPL(BASE_KEYON_FREQ + iPercChannel, (iBlock << 2) | ((iOPLFNum >> 8) & 0x03));
576
577                 uint8_t iBit = 1 << (15 - iChannel);
578
579                 // Turn the perc instrument off if it's already playing (OPL can't do
580                 // polyphonic notes w/ percussion)
581                 if (this->iCurrentRegs[BASE_RHYTHM] & iBit) this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~iBit);
582
583                 // I wonder whether we need to delay or anything here?
584
585                 // Turn the note on
586                 //if (iChannel == 15) {
587                 this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] | iBit);
588                 //AdPlug_LogWrite("CMF: Note %d on MIDI channel %d (mapped to OPL channel %d-1) - vel %02X, fnum %d/%d\n", iNote, iChannel, iPercChannel+1, iVelocity, iOPLFNum, iBlock);
589                 //}
590
591                 this->chOPL[iPercChannel].iNoteStart = ++this->iNoteCount;
592                 this->chOPL[iPercChannel].iMIDIChannel = iChannel;
593                 this->chOPL[iPercChannel].iMIDINote = iNote;
594
595         } else { // Non rhythm-mode or a normal instrument channel
596
597                 // Figure out which OPL channel to play this note on
598                 int iOPLChannel = -1;
599                 int iNumChannels = this->bPercussive ? 6 : 9;
600                 for (int i = iNumChannels - 1; i >= 0; i--) {
601                         // If there's no note playing on this OPL channel, use that
602                         if (this->chOPL[i].iNoteStart == 0) {
603                                 iOPLChannel = i;
604                                 // See if this channel is already set to the instrument we want.
605                                 if (this->chOPL[i].iMIDIPatch == this->chMIDI[iChannel].iPatch) {
606                                         // It is, so stop searching
607                                         break;
608                                 } // else keep searching just in case there's a better match
609                         }
610                 }
611                 if (iOPLChannel == -1) {
612                         // All channels were in use, find the one with the longest note
613                         iOPLChannel = 0;
614                         int iEarliest = this->chOPL[0].iNoteStart;
615                         for (int i = 1; i < iNumChannels; i++) {
616                                 if (this->chOPL[i].iNoteStart < iEarliest) {
617                                         // Found a channel with a note being played for longer
618                                         iOPLChannel = i;
619                                         iEarliest = this->chOPL[i].iNoteStart;
620                                 }
621                         }
622                         AdPlug_LogWrite("CMF: Too many polyphonic notes, cutting note on channel %d\n", iOPLChannel);
623                 }
624
625                 // Run through all the channels with negative notestart values - these
626                 // channels have had notes recently stop - and increment the counter
627                 // to slowly move the channel closer to being reused for a future note.
628                 //for (int i = 0; i < iNumChannels; i++) {
629                 //      if (this->chOPL[i].iNoteStart < 0) this->chOPL[i].iNoteStart++;
630                 //}
631
632                 // Now the new note should be played on iOPLChannel, but see if the instrument
633                 // is right first.
634                 if (this->chOPL[iOPLChannel].iMIDIPatch != this->chMIDI[iChannel].iPatch) {
635                         this->MIDIchangeInstrument(iOPLChannel, iChannel, this->chMIDI[iChannel].iPatch);
636                 }
637
638                 this->chOPL[iOPLChannel].iNoteStart = ++this->iNoteCount;
639                 this->chOPL[iOPLChannel].iMIDIChannel = iChannel;
640                 this->chOPL[iOPLChannel].iMIDINote = iNote;
641
642                 #ifdef USE_VELOCITY  // Official CMF player seems to ignore velocity levels
643                         // Adjust the channel volume to match the note velocity
644                         uint8_t iOPLOffset = BASE_SCAL_LEVL + OPLOFFSET(iChannel) + 3; // +3 == Carrier
645                         uint16_t iLevel = 0x2F - (iVelocity * 0x2F / 127); // 0x2F should be 0x3F but it's too quiet then
646                         this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel);
647                 #endif
648
649                 // Set the frequency and play the note
650                 this->writeOPL(BASE_FNUM_L + iOPLChannel, iOPLFNum & 0xFF);
651                 this->writeOPL(BASE_KEYON_FREQ + iOPLChannel, OPLBIT_KEYON | (iBlock << 2) | ((iOPLFNum & 0x300) >> 8));
652         }
653         return;
654 }
655
656 void CcmfPlayer::cmfNoteOff(uint8_t iChannel, uint8_t iNote, uint8_t iVelocity)
657 {
658         if ((iChannel > 10) && (this->bPercussive)) {
659                 int iOPLChannel = this->getPercChannel(iChannel);
660                 if (this->chOPL[iOPLChannel].iMIDINote != iNote) return; // there's a different note playing now
661                 this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~(1 << (15 - iChannel)));
662                 this->chOPL[iOPLChannel].iNoteStart = 0; // channel free
663         } else { // Non rhythm-mode or a normal instrument channel
664                 int iOPLChannel = -1;
665                 int iNumChannels = this->bPercussive ? 6 : 9;
666                 for (int i = 0; i < iNumChannels; i++) {
667                         if (
668                                 (this->chOPL[i].iMIDIChannel == iChannel) &&
669                                 (this->chOPL[i].iMIDINote == iNote) &&
670                                 (this->chOPL[i].iNoteStart != 0)
671                         ) {
672                                 // Found the note, switch it off
673                                 this->chOPL[i].iNoteStart = 0;
674                                 iOPLChannel = i;
675                                 break;
676                         }
677                 }
678                 if (iOPLChannel == -1) return;
679
680                 this->writeOPL(BASE_KEYON_FREQ + iOPLChannel, this->iCurrentRegs[BASE_KEYON_FREQ + iOPLChannel] & ~OPLBIT_KEYON);
681         }
682         return;
683 }
684
685 uint8_t CcmfPlayer::getPercChannel(uint8_t iChannel)
686 {
687         switch (iChannel) {
688                 case 11: return 7-1; // Bass drum
689                 case 12: return 8-1; // Snare drum
690                 case 13: return 9-1; // Tom tom
691                 case 14: return 9-1; // Top cymbal
692                 case 15: return 8-1; // Hihat
693         }
694         AdPlug_LogWrite("CMF ERR: Tried to get the percussion channel from MIDI channel %d - this shouldn't happen!\n", iChannel);
695         return 0;
696 }
697
698
699 void CcmfPlayer::MIDIchangeInstrument(uint8_t iOPLChannel, uint8_t iMIDIChannel, uint8_t iNewInstrument)
700 {
701         if ((iMIDIChannel > 10) && (this->bPercussive)) {
702                 switch (iMIDIChannel) {
703                         case 11: // Bass drum (operator 13+16 == channel 7 modulator+carrier)
704                                 this->writeInstrumentSettings(7-1, 0, 0, iNewInstrument);
705                                 this->writeInstrumentSettings(7-1, 1, 1, iNewInstrument);
706                                 break;
707                         case 12: // Snare drum (operator 17 == channel 8 carrier)
708                         //case 15:
709                                 this->writeInstrumentSettings(8-1, 0, 1, iNewInstrument);
710
711                                 //
712                                 //this->writeInstrumentSettings(8-1, 0, 0, iNewInstrument);
713                                 break;
714                         case 13: // Tom tom (operator 15 == channel 9 modulator)
715                         //case 14:
716                                 this->writeInstrumentSettings(9-1, 0, 0, iNewInstrument);
717
718                                 //
719                                 //this->writeInstrumentSettings(9-1, 0, 1, iNewInstrument);
720                                 break;
721                         case 14: // Top cymbal (operator 18 == channel 9 carrier)
722                                 this->writeInstrumentSettings(9-1, 0, 1, iNewInstrument);
723                                 break;
724                         case 15: // Hi-hat (operator 14 == channel 8 modulator)
725                                 this->writeInstrumentSettings(8-1, 0, 0, iNewInstrument);
726                                 break;
727                         default:
728                                 AdPlug_LogWrite("CMF: Invalid MIDI channel %d (not melodic and not percussive!)\n", iMIDIChannel + 1);
729                                 break;
730                 }
731                 this->chOPL[iOPLChannel].iMIDIPatch = iNewInstrument;
732         } else {
733                 // Standard nine OPL channels
734                 this->writeInstrumentSettings(iOPLChannel, 0, 0, iNewInstrument);
735                 this->writeInstrumentSettings(iOPLChannel, 1, 1, iNewInstrument);
736                 this->chOPL[iOPLChannel].iMIDIPatch = iNewInstrument;
737         }
738         return;
739 }
740
741 void CcmfPlayer::MIDIcontroller(uint8_t iChannel, uint8_t iController, uint8_t iValue)
742 {
743         switch (iController) {
744                 case 0x63:
745                         // Custom extension to allow CMF files to switch the AM+VIB depth on and
746                         // off (officially both are on, and there's no way to switch them off.)
747                         // Controller values:
748                         //   0 == AM+VIB off
749                         //   1 == VIB on
750                         //   2 == AM on
751                         //   3 == AM+VIB on
752                         if (iValue) {
753                                 this->writeOPL(BASE_RHYTHM, (this->iCurrentRegs[BASE_RHYTHM] & ~0xC0) | (iValue << 6)); // switch AM+VIB extension on
754                         } else {
755                                 this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~0xC0); // switch AM+VIB extension off
756                         }
757                         AdPlug_LogWrite("CMF: AM+VIB depth change - AM %s, VIB %s\n",
758                                 (this->iCurrentRegs[BASE_RHYTHM] & 0x80) ? "on" : "off",
759                                 (this->iCurrentRegs[BASE_RHYTHM] & 0x40) ? "on" : "off");
760                         break;
761                 case 0x66:
762                         AdPlug_LogWrite("CMF: Song set marker to 0x%02X\n", iValue);
763                         break;
764                 case 0x67:
765                         this->bPercussive = (iValue != 0);
766                         if (this->bPercussive) {
767                                 this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] | 0x20); // switch rhythm-mode on
768                         } else {
769                                 this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~0x20); // switch rhythm-mode off
770                         }
771                         AdPlug_LogWrite("CMF: Percussive/rhythm mode %s\n", this->bPercussive ? "enabled" : "disabled");
772                         break;
773                 case 0x68:
774                         // TODO: Shouldn't this just affect the one channel, not the whole song?  -- have pitchbends for that
775                         this->iTranspose = iValue;
776                         AdPlug_LogWrite("CMF: Transposing all notes up by %d * 1/128ths of a semitone.\n", iValue);
777                         break;
778                 case 0x69:
779                         this->iTranspose = -iValue;
780                         AdPlug_LogWrite("CMF: Transposing all notes down by %d * 1/128ths of a semitone.\n", iValue);
781                         break;
782                 default:
783                         AdPlug_LogWrite("CMF: Unsupported MIDI controller 0x%02X, ignoring.\n", iController);
784                         break;
785         }
786         return;
787 }