diff --git a/README.md b/README.md index 288886f..c105d61 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,32 @@ -# OPL2 Audio Board -This repository contains the OPL2 Audio Board library for Arduino, Teensy, Raspberry Pi and compatible boards as well as a number of examples on how the board can be used. You can use the OPL2 Audio Board to: -* Experiment with the YM3812 chip +# Arduino OPL2 Library +This repository contains the OPL2 / OPL3 audio library for the OPL2 Audio Board or OPL3 Duo! board. It is compatible with Arduino, Teensy, Raspberry Pi and other Arduino-like boards. A number of examples are included on how the library can be used. You can use the OPL2 Audio Board or OPL3 Duo! to: +* Experiment with the YM3812 or YMF262 chip * Build your own synthesizer * Play your own OPL2 tunes -* Instrument definitions from Adlib, The Fat Man and Windows 3.1 included in the library +* Instrument definitions from Adlib and The Fat Man are included in the library for both 2-op OPL3 and 4-op OPL3. * Play exported OPL2 music (DRO, IMF, VGM) or Reality Adlib Tracker music files * Use the board as a MIDI synthesizer (Teensy++ 2.0 and later example included) * Emulation with DosBox; you can use the board to output MIDI music (Teensy++ 2.0 and later) * Use the board directly as a synthesizer by using the [OPL3BankEditor](https://github.com/Wohlstand/OPL3BankEditor) software by Wohlstand -Current library version is 1.5.3 - -To obtain your own OPL2 Audio Board visit the [Tindie store](https://www.tindie.com/products/DhrBaksteen/opl2-audio-board/). +Current library version is 2.0.0 +### OPL2 Audio Board +The OPL2 Audio Board is fun and easy board to get started with an OPL2 synthesizer. It is built around the YM3812 OPL2 chip that gives you 9 channels with 2-operators each to produce the classic OPL2 sound that you may remember from early 90s computer games. For more info visit the [Hackaday project page](https://hackaday.io/project/18995-opl2-audio-board-for-arduino-raspberry-pi). +To obtain your own OPL2 Audio Board visit my [Tindie store](https://www.tindie.com/products/DhrBaksteen/opl2-audio-board/). ![](https://raw.githubusercontent.com/DhrBaksteen/ArduinoOPL2/master/extra/OPL2_board.jpg) -## 1. Assembling the kit -For a step by step guide on how to assemble the kit please read the [Assembly guide](https://github.com/DhrBaksteen/ArduinoOPL2/blob/master/assembling.md). +### OPL3 Duo! Board +The OPL3 Duo! is a more capable version of the OPL2 Audio Board. It has 2 YMF262 OPL3 chips that allow for up to 36 channels of 2-operator sounds or up to 12 4-operator + 12 2-operator sounds. It also has stereo sound and is fully OPL2 compatible. Each OPL3 chip can be controlled individually or the library can control the board as if it were one big OPL3 chip with 36 channels. + +The OPL3 Duo! board is available on my [Tindie store](https://www.tindie.com/products/cheerful/opl3-duo/). +![](https://raw.githubusercontent.com/DhrBaksteen/ArduinoOPL2/master/extra/OPL3Duo_board.jpg) -## 2. Installing the library +## 1. Installing the library #### Arduino / Teensy The easiest way to install the library it do download it through the Arduino Library Manager. Open the Library Manager from your Arduino IDE's Sketch > Include Library > Library Manager menu. A new window will open that allows you to search for a library. Search for 'Arduino OPL2' and it should show this libarary. Select the library, click the install button and you're good to go. @@ -32,29 +36,3 @@ For more information see the [instructions](https://www.arduino.cc/en/Guide/Libr #### Raspberry Pi / Orange Pi and compatibles To install the library onto your Pi clone this repo and run `./build`. The OPL2 library requires [WiringPi](http://wiringpi.com/) to be installed on your Pi. Normally this library is already installed, but if this is not the case then the build script can install it for you. - - -## 3. Connecting the OPL2 Audio Board -You can connect the OPL2 Audio Board directly to a speaker, however for the best results I recommend you connect some active (amplified) speakers. Headphones or line level recording will also work great. See the table below how to connect the OPL2 Audio Board to an Arduino. [Visit the wiki](https://github.com/DhrBaksteen/ArduinoOPL2/wiki/Connecting) to learn how to connect the OPL2 AUdio Board to your favorite development platform. - -#### Arduino -| OPL2 Board | Arduino Pin | -|------------|-------------| -| A0 | 9 | -| Data | 11 | -| Latch | 10 | -| Shift | 13 | -| Reset | 8 | - - -## 4. Using the OPL2 Audio Board -#### Arduino -After installing the library and restarting the Arduino IDE you will find a number of examples under the File > Examples > ArduinoOPL2 menu. These examples can be found in the `examples` folder of the library. - -#### Teensy -Most Arduino examples will also work directly on a Teensy. The examples that require an SD card (PlayDRO, PlayIMG and PlayRAD) are Teensy specific when you use the Teensy's on board SD card slot. Teensy++ 2.0 and later can be configured as MIDI device. An example for this can be found among the Teensy specific examples in the `examples/teensy` folder. - -#### Raspberry Pi / Orange Pi -After building the library you will find a number of examples in the `examples_pi` folder. The examples have been compiled during installation of the library, so you should be ready to dive right in! Try running `sudo ./demotune` for example from the `examples_pi/demotune` folder. - -When compiling your own code using the OPL2 library don't forget to specify the library using the `-lOPL2` argument e.g. `gcc -std=c++11 -Wall -o my_program my_program.cpp -lOPL2 -lwiringPi` diff --git a/examples/Drums/Drums.ino b/examples/Drums/Drums.ino deleted file mode 100644 index ebf6814..0000000 --- a/examples/Drums/Drums.ino +++ /dev/null @@ -1,74 +0,0 @@ -/** - * This is a simple demo sketch for the OPL2 library. It plays a drum loop using instrument settings form the Adlib - * standard instrument library. Note that channel 6 is used by the base drum, 7 is used by snare and hi-hat and 8 is - * used by tom tom and cymbal. - * - * OPL2 board is connected as follows: - * Pin 8 - Reset - * Pin 9 - A0 - * Pin 10 - Latch - * Pin 11 - Data - * Pin 13 - Shift - * - * Refer to the wiki at https://github.com/DhrBaksteen/ArduinoOPL2/wiki/Connecting to learn how to connect your platform - * of choice! - * - * Code by Maarten Janssen (maarten@cheerful.nl) 2017-04-13 - * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 - */ - - -#include -#include -#include - - -OPL2 opl2; -int i = 0; - - -void setup() { - opl2.init(); - - // Set percussion mode and load instruments. - Instrument bass = opl2.loadInstrument(INSTRUMENT_BDRUM1); - Instrument snare = opl2.loadInstrument(INSTRUMENT_RKSNARE1); - Instrument tom = opl2.loadInstrument(INSTRUMENT_TOM2); - Instrument cymbal = opl2.loadInstrument(INSTRUMENT_CYMBAL1); - Instrument hihat = opl2.loadInstrument(INSTRUMENT_HIHAT2); - - opl2.setPercussion(true); - opl2.setDrumInstrument(bass); - opl2.setDrumInstrument(snare); - opl2.setDrumInstrument(tom); - opl2.setDrumInstrument(cymbal); - opl2.setDrumInstrument(hihat); - - // Set octave and frequency for bass drum. - opl2.setBlock(6, 4); - opl2.setFNumber(6, opl2.getNoteFNumber(NOTE_C)); - - // Set octave and frequency for snare drum and hi-hat. - opl2.setBlock(7, 3); - opl2.setFNumber(7, opl2.getNoteFNumber(NOTE_C)); - // Set low volume on hi-hat - opl2.setVolume(7, OPERATOR1, 16); - - // Set octave and frequency for tom tom and cymbal. - opl2.setBlock(8, 3); - opl2.setFNumber(8, opl2.getNoteFNumber(NOTE_A)); -} - - -void loop() { - bool bass = i % 4 == 0; // Bass drum every 1st tick - bool snare = i % 4 == 2; // Snare drum every 3rd tick - bool tom = false; // No tom tom - bool cymbal = i % 32 == 0; // Cymbal every 32nd tick - bool hiHat = true; // Hi-hat every tick - - opl2.setDrums(bass, snare, tom, cymbal, hiHat); - - i ++; - delay(200); -} diff --git a/examples/DemoTune/DemoTune.ino b/examples/OPL2AudioBoard/DemoTune/DemoTune.ino similarity index 99% rename from examples/DemoTune/DemoTune.ino rename to examples/OPL2AudioBoard/DemoTune/DemoTune.ino index a91a225..487777a 100644 --- a/examples/DemoTune/DemoTune.ino +++ b/examples/OPL2AudioBoard/DemoTune/DemoTune.ino @@ -72,7 +72,7 @@ void setup() { music[i] = channel; } - opl2.init(); + opl2.begin(); // Setup channels 0, 1 and 2. Instrument piano = opl2.loadInstrument(INSTRUMENT_PIANO1); diff --git a/examples/OPL2AudioBoard/Drums/Drums.ino b/examples/OPL2AudioBoard/Drums/Drums.ino new file mode 100644 index 0000000..6f5ddcf --- /dev/null +++ b/examples/OPL2AudioBoard/Drums/Drums.ino @@ -0,0 +1,74 @@ +/** + * This is a simple demo sketch for the OPL2 library. It plays a drum loop using instrument settings form the Adlib + * standard instrument library. Note that channel 6 is used by the base drum, 7 is used by snare and hi-hat and 8 is + * used by tom tom and cymbal. + * + * OPL2 board is connected as follows: + * Pin 8 - Reset + * Pin 9 - A0 + * Pin 10 - Latch + * Pin 11 - Data + * Pin 13 - Shift + * + * Refer to the wiki at https://github.com/DhrBaksteen/ArduinoOPL2/wiki/Connecting to learn how to connect your platform + * of choice! + * + * Code by Maarten Janssen (maarten@cheerful.nl) 2017-04-13 + * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 + */ + + +#include +#include +#include + + +OPL2 opl2; +int i = 0; + + +void setup() { + opl2.begin(); + + // Set percussion mode and load instruments. + Instrument bass = opl2.loadInstrument(INSTRUMENT_BDRUM2); + Instrument snare = opl2.loadInstrument(INSTRUMENT_RKSNARE1); + Instrument tom = opl2.loadInstrument(INSTRUMENT_TOM2); + Instrument cymbal = opl2.loadInstrument(INSTRUMENT_CYMBAL1); + Instrument hihat = opl2.loadInstrument(INSTRUMENT_HIHAT2); + + opl2.setPercussion(true); + opl2.setDrumInstrument(bass); + opl2.setDrumInstrument(snare); + opl2.setDrumInstrument(tom); + opl2.setDrumInstrument(cymbal); + opl2.setDrumInstrument(hihat); + + // Set octave and frequency for bass drum. + opl2.setBlock(6, 4); + opl2.setFNumber(6, opl2.getNoteFNumber(NOTE_C)); + + // Set octave and frequency for snare drum and hi-hat. + opl2.setBlock(7, 3); + opl2.setFNumber(7, opl2.getNoteFNumber(NOTE_C)); + // Set low volume on hi-hat + opl2.setVolume(7, OPERATOR1, 16); + + // Set octave and frequency for tom tom and cymbal. + opl2.setBlock(8, 3); + opl2.setFNumber(8, opl2.getNoteFNumber(NOTE_A)); +} + + +void loop() { + bool bass = i % 4 == 0; // Bass drum every 1st tick + bool snare = i % 4 == 2; // Snare drum every 3rd tick + bool tom = i % 8 > 3; // Tom tom + bool cymbal = i % 32 == 0; // Cymbal every 32nd tick + bool hiHat = true; // Hi-hat every tick + + opl2.setDrums(bass, snare, tom, cymbal, hiHat); + + i ++; + delay(200); +} diff --git a/examples/FrequencySweep/FrequencySweep.ino b/examples/OPL2AudioBoard/FrequencySweep/FrequencySweep.ino similarity index 66% rename from examples/FrequencySweep/FrequencySweep.ino rename to examples/OPL2AudioBoard/FrequencySweep/FrequencySweep.ino index 5824c69..ace1093 100644 --- a/examples/FrequencySweep/FrequencySweep.ino +++ b/examples/OPL2AudioBoard/FrequencySweep/FrequencySweep.ino @@ -26,23 +26,24 @@ float t = 0.0; void setup() { - opl2.init(); + opl2.begin(); - // Setup channel 0 carrier. - opl2.setMaintainSustain(0, CARRIER, true); - opl2.setMultiplier(0, CARRIER, 0x04); - opl2.setAttack (0, CARRIER, 0x0A); - opl2.setSustain (0, CARRIER, 0x04); + // Setup channel 0 carrier. + opl2.setMaintainSustain(0, CARRIER, true); + opl2.setMultiplier(0, CARRIER, 0x01); + opl2.setAttack (0, CARRIER, 0x0A); + opl2.setSustain (0, CARRIER, 0x04); + opl2.setVolume (0, CARRIER, 0x00); - // Start tone. - opl2.setKeyOn(0, true); + // Start tone. + opl2.setKeyOn(0, true); } void loop() { - float freq = sin(t) * 250 + 500; - opl2.setFrequency(0, freq); + float freq = sin(t) * 250 + 500; + opl2.setFrequency(0, freq); - t += .01; - delay(10); + t += .01; + delay(10); } diff --git a/examples/PianoBoard/PianoBoard.ino b/examples/OPL2AudioBoard/PianoBoard/PianoBoard.ino similarity index 99% rename from examples/PianoBoard/PianoBoard.ino rename to examples/OPL2AudioBoard/PianoBoard/PianoBoard.ino index 7cb9c30..6457db8 100644 --- a/examples/PianoBoard/PianoBoard.ino +++ b/examples/OPL2AudioBoard/PianoBoard/PianoBoard.ino @@ -36,7 +36,7 @@ int keyChannel[9] = {-1, -1, -1, -1, -1, -1, -1, -1, -1}; void setup() { - opl2.init(); + opl2.begin(); // Load an instrument and assign it to all OPL2 channels. Instrument piano = opl2.loadInstrument(INSTRUMENT_CRYSTAL); diff --git a/examples/PianoBoardDrummer/PianoBoardDrummer.ino b/examples/OPL2AudioBoard/PianoBoardDrummer/PianoBoardDrummer.ino similarity index 96% rename from examples/PianoBoardDrummer/PianoBoardDrummer.ino rename to examples/OPL2AudioBoard/PianoBoardDrummer/PianoBoardDrummer.ino index d27a5cb..f6d99b3 100644 --- a/examples/PianoBoardDrummer/PianoBoardDrummer.ino +++ b/examples/OPL2AudioBoard/PianoBoardDrummer/PianoBoardDrummer.ino @@ -36,10 +36,10 @@ byte drums[8] = {DRUM_BASS, NO_DRUM, DRUM_SNARE, NO_DRUM, DRUM_TOM, DRUM_HI_HAT, void setup() { - opl2.init(); + opl2.begin(); // Load drum instruments and set percusive mode. - Instrument bass = opl2.loadInstrument(INSTRUMENT_BDRUM1); + Instrument bass = opl2.loadInstrument(INSTRUMENT_BDRUM2); Instrument snare = opl2.loadInstrument(INSTRUMENT_RKSNARE1); Instrument tom = opl2.loadInstrument(INSTRUMENT_TOM2); Instrument cymbal = opl2.loadInstrument(INSTRUMENT_CYMBAL1); diff --git a/examples/PlayDRO/PlayDRO.ino b/examples/OPL2AudioBoard/PlayDRO/PlayDRO.ino old mode 100755 new mode 100644 similarity index 99% rename from examples/PlayDRO/PlayDRO.ino rename to examples/OPL2AudioBoard/PlayDRO/PlayDRO.ino index 8dd905d..f94291e --- a/examples/PlayDRO/PlayDRO.ino +++ b/examples/OPL2AudioBoard/PlayDRO/PlayDRO.ino @@ -41,7 +41,7 @@ byte registerMap[256]; void setup() { - opl2.init(); + opl2.begin(); SD.begin(7); loadDroSong("phemopop.dro"); diff --git a/examples/PlayDRO/phemopop.dro b/examples/OPL2AudioBoard/PlayDRO/phemopop.dro old mode 100755 new mode 100644 similarity index 100% rename from examples/PlayDRO/phemopop.dro rename to examples/OPL2AudioBoard/PlayDRO/phemopop.dro diff --git a/examples/PlayDRO/strikeforce.dro b/examples/OPL2AudioBoard/PlayDRO/strikeforce.dro similarity index 100% rename from examples/PlayDRO/strikeforce.dro rename to examples/OPL2AudioBoard/PlayDRO/strikeforce.dro diff --git a/examples/PlayIMF/PlayIMF.ino b/examples/OPL2AudioBoard/PlayIMF/PlayIMF.ino old mode 100755 new mode 100644 similarity index 99% rename from examples/PlayIMF/PlayIMF.ino rename to examples/OPL2AudioBoard/PlayIMF/PlayIMF.ino index 10dc14a..d8b3480 --- a/examples/PlayIMF/PlayIMF.ino +++ b/examples/OPL2AudioBoard/PlayIMF/PlayIMF.ino @@ -35,7 +35,7 @@ float imfSpeed; long songLength = 0; void setup() { - opl2.init(); + opl2.begin(); SD.begin(7); imfSpeed = 560.0; diff --git a/examples/PlayIMF/city.imf b/examples/OPL2AudioBoard/PlayIMF/city.imf similarity index 100% rename from examples/PlayIMF/city.imf rename to examples/OPL2AudioBoard/PlayIMF/city.imf diff --git a/examples/PlayIMF/kickbuta.imf b/examples/OPL2AudioBoard/PlayIMF/kickbuta.imf similarity index 100% rename from examples/PlayIMF/kickbuta.imf rename to examples/OPL2AudioBoard/PlayIMF/kickbuta.imf diff --git a/examples/PlayRAD/PlayRAD.ino b/examples/OPL2AudioBoard/PlayRAD/PlayRAD.ino similarity index 99% rename from examples/PlayRAD/PlayRAD.ino rename to examples/OPL2AudioBoard/PlayRAD/PlayRAD.ino index deafd75..e6dd39a 100644 --- a/examples/PlayRAD/PlayRAD.ino +++ b/examples/OPL2AudioBoard/PlayRAD/PlayRAD.ino @@ -301,7 +301,7 @@ void nextOrder(byte startLine = 0) { * Initialize the OPL2 board and load the first line of the first order. */ void initPlayer() { - opl2.init(); + opl2.begin(); opl2.setWaveFormSelect(true); opl2.setPercussion(false); speed = initialSpeed; diff --git a/examples/PlayRAD/action.rad b/examples/OPL2AudioBoard/PlayRAD/action.rad similarity index 100% rename from examples/PlayRAD/action.rad rename to examples/OPL2AudioBoard/PlayRAD/action.rad diff --git a/examples/PlayRAD/adlibsp.rad b/examples/OPL2AudioBoard/PlayRAD/adlibsp.rad similarity index 100% rename from examples/PlayRAD/adlibsp.rad rename to examples/OPL2AudioBoard/PlayRAD/adlibsp.rad diff --git a/examples/PlayRAD/shoot.rad b/examples/OPL2AudioBoard/PlayRAD/shoot.rad similarity index 100% rename from examples/PlayRAD/shoot.rad rename to examples/OPL2AudioBoard/PlayRAD/shoot.rad diff --git a/examples/PlayVGM/PlayVGM.ino b/examples/OPL2AudioBoard/PlayVGM/PlayVGM.ino similarity index 99% rename from examples/PlayVGM/PlayVGM.ino rename to examples/OPL2AudioBoard/PlayVGM/PlayVGM.ino index 8d2c3bb..d303346 100644 --- a/examples/PlayVGM/PlayVGM.ino +++ b/examples/OPL2AudioBoard/PlayVGM/PlayVGM.ino @@ -98,7 +98,7 @@ void error(enum playbackStatus errorcode) { void setup() { Serial.begin(9600); - opl2.init(); + opl2.begin(); if (!SD.begin(7)) { error(PLAYBACK_ERROR_SD_INIT_FAILURE); return; diff --git a/examples/PlayVGM/decompressVgz.bat b/examples/OPL2AudioBoard/PlayVGM/decompressVgz.bat similarity index 100% rename from examples/PlayVGM/decompressVgz.bat rename to examples/OPL2AudioBoard/PlayVGM/decompressVgz.bat diff --git a/examples/PlayVGM/decompressVgz.sh b/examples/OPL2AudioBoard/PlayVGM/decompressVgz.sh similarity index 100% rename from examples/PlayVGM/decompressVgz.sh rename to examples/OPL2AudioBoard/PlayVGM/decompressVgz.sh diff --git a/examples/PlayVGM/stunts01.vgm b/examples/OPL2AudioBoard/PlayVGM/stunts01.vgm similarity index 100% rename from examples/PlayVGM/stunts01.vgm rename to examples/OPL2AudioBoard/PlayVGM/stunts01.vgm diff --git a/examples/PlayVGM/wacky02.vgm b/examples/OPL2AudioBoard/PlayVGM/wacky02.vgm similarity index 100% rename from examples/PlayVGM/wacky02.vgm rename to examples/OPL2AudioBoard/PlayVGM/wacky02.vgm diff --git a/examples/Scale/Scale.ino b/examples/OPL2AudioBoard/Scale/Scale.ino similarity index 98% rename from examples/Scale/Scale.ino rename to examples/OPL2AudioBoard/Scale/Scale.ino index a1a5472..fc37b28 100644 --- a/examples/Scale/Scale.ino +++ b/examples/OPL2AudioBoard/Scale/Scale.ino @@ -24,7 +24,7 @@ OPL2 opl2; void setup() { - opl2.init(); + opl2.begin(); Instrument piano = opl2.loadInstrument(INSTRUMENT_PIANO1); // Load a piano instrument. opl2.setInstrument(0, piano); // Assign the instrument to OPL2 channel 0. diff --git a/examples/SerialPassthrough/SerialPassthrough.ino b/examples/OPL2AudioBoard/SerialPassthrough/SerialPassthrough.ino similarity index 99% rename from examples/SerialPassthrough/SerialPassthrough.ino rename to examples/OPL2AudioBoard/SerialPassthrough/SerialPassthrough.ino index 867322e..1e2b340 100644 --- a/examples/SerialPassthrough/SerialPassthrough.ino +++ b/examples/OPL2AudioBoard/SerialPassthrough/SerialPassthrough.ino @@ -34,7 +34,7 @@ OPL2 opl2; void setup() { Serial.begin(115200); - opl2.init(); + opl2.begin(); } void loop() { diff --git a/examples/SimpleTone/SimpleTone.ino b/examples/OPL2AudioBoard/SimpleTone/SimpleTone.ino old mode 100755 new mode 100644 similarity index 52% rename from examples/SimpleTone/SimpleTone.ino rename to examples/OPL2AudioBoard/SimpleTone/SimpleTone.ino index e5a22da..f0a8e19 --- a/examples/SimpleTone/SimpleTone.ino +++ b/examples/OPL2AudioBoard/SimpleTone/SimpleTone.ino @@ -25,26 +25,27 @@ OPL2 opl2; void setup() { - opl2.init(); - - // Setup channels 0, 1 and 2 to produce a bell sound. - for (byte i = 0; i < 3; i ++) { - opl2.setTremolo (i, CARRIER, true); - opl2.setVibrato (i, CARRIER, true); - opl2.setMultiplier(i, CARRIER, 0x04); - opl2.setAttack (i, CARRIER, 0x0A); - opl2.setDecay (i, CARRIER, 0x04); - opl2.setSustain (i, CARRIER, 0x0F); - opl2.setRelease (i, CARRIER, 0x0F); - } - - // Play notes C-3 through B-4 on alternating channels. - for (byte i = 0; i < 24; i ++) { - byte octave = 3 + (i / 12); - byte note = i % 12; - opl2.playNote(i % 3, octave, note); - delay(300); - } + opl2.begin(); + + // Setup channels 0, 1 and 2 to produce a bell sound. + for (byte i = 0; i < 3; i ++) { + opl2.setTremolo (i, CARRIER, true); + opl2.setVibrato (i, CARRIER, true); + opl2.setMultiplier(i, CARRIER, 0x04); + opl2.setAttack (i, CARRIER, 0x0A); + opl2.setDecay (i, CARRIER, 0x04); + opl2.setSustain (i, CARRIER, 0x0F); + opl2.setRelease (i, CARRIER, 0x0F); + opl2.setVolume (i, CARRIER, 0x00); + } + + // Play notes C-3 through B-4 on alternating channels. + for (byte i = 0; i < 24; i ++) { + byte octave = 3 + (i / 12); + byte note = i % 12; + opl2.playNote(i % 3, octave, note); + delay(300); + } } diff --git a/examples/Teensy/PlayDRO/PlayDRO.ino b/examples/OPL2AudioBoard/Teensy/PlayDRO/PlayDRO.ino similarity index 99% rename from examples/Teensy/PlayDRO/PlayDRO.ino rename to examples/OPL2AudioBoard/Teensy/PlayDRO/PlayDRO.ino index 796f2ff..b84ba6a 100644 --- a/examples/Teensy/PlayDRO/PlayDRO.ino +++ b/examples/OPL2AudioBoard/Teensy/PlayDRO/PlayDRO.ino @@ -39,7 +39,7 @@ byte registerMap[256]; void setup() { - opl2.init(); + opl2.begin(); SD.begin(); loadDroSong("phemopop.dro"); diff --git a/examples/Teensy/PlayDRO/phemopop.dro b/examples/OPL2AudioBoard/Teensy/PlayDRO/phemopop.dro similarity index 100% rename from examples/Teensy/PlayDRO/phemopop.dro rename to examples/OPL2AudioBoard/Teensy/PlayDRO/phemopop.dro diff --git a/examples/Teensy/PlayDRO/strikeforce.dro b/examples/OPL2AudioBoard/Teensy/PlayDRO/strikeforce.dro similarity index 100% rename from examples/Teensy/PlayDRO/strikeforce.dro rename to examples/OPL2AudioBoard/Teensy/PlayDRO/strikeforce.dro diff --git a/examples/Teensy/PlayIMF/PlayIMF.ino b/examples/OPL2AudioBoard/Teensy/PlayIMF/PlayIMF.ino similarity index 99% rename from examples/Teensy/PlayIMF/PlayIMF.ino rename to examples/OPL2AudioBoard/Teensy/PlayIMF/PlayIMF.ino index 49a8599..8dee3ec 100644 --- a/examples/Teensy/PlayIMF/PlayIMF.ino +++ b/examples/OPL2AudioBoard/Teensy/PlayIMF/PlayIMF.ino @@ -33,7 +33,7 @@ float imfSpeed; long songLength = 0; void setup() { - opl2.init(); + opl2.begin(); SD.begin(); imfSpeed = 560.0; diff --git a/examples/Teensy/PlayIMF/city.imf b/examples/OPL2AudioBoard/Teensy/PlayIMF/city.imf similarity index 100% rename from examples/Teensy/PlayIMF/city.imf rename to examples/OPL2AudioBoard/Teensy/PlayIMF/city.imf diff --git a/examples/Teensy/PlayIMF/kickbuta.imf b/examples/OPL2AudioBoard/Teensy/PlayIMF/kickbuta.imf similarity index 100% rename from examples/Teensy/PlayIMF/kickbuta.imf rename to examples/OPL2AudioBoard/Teensy/PlayIMF/kickbuta.imf diff --git a/examples/Teensy/PlayRAD/PlayRAD.ino b/examples/OPL2AudioBoard/Teensy/PlayRAD/PlayRAD.ino similarity index 99% rename from examples/Teensy/PlayRAD/PlayRAD.ino rename to examples/OPL2AudioBoard/Teensy/PlayRAD/PlayRAD.ino index fc28425..b8ed2f5 100644 --- a/examples/Teensy/PlayRAD/PlayRAD.ino +++ b/examples/OPL2AudioBoard/Teensy/PlayRAD/PlayRAD.ino @@ -294,7 +294,7 @@ void nextOrder(byte startLine = 0) { * Initialize the OPL2 board and load the first line of the first order. */ void initPlayer() { - opl2.init(); + opl2.begin(); opl2.setWaveFormSelect(true); opl2.setPercussion(false); speed = initialSpeed; diff --git a/examples/Teensy/PlayRAD/action.rad b/examples/OPL2AudioBoard/Teensy/PlayRAD/action.rad similarity index 100% rename from examples/Teensy/PlayRAD/action.rad rename to examples/OPL2AudioBoard/Teensy/PlayRAD/action.rad diff --git a/examples/Teensy/PlayRAD/adlibsp.rad b/examples/OPL2AudioBoard/Teensy/PlayRAD/adlibsp.rad similarity index 100% rename from examples/Teensy/PlayRAD/adlibsp.rad rename to examples/OPL2AudioBoard/Teensy/PlayRAD/adlibsp.rad diff --git a/examples/Teensy/PlayRAD/shoot.rad b/examples/OPL2AudioBoard/Teensy/PlayRAD/shoot.rad similarity index 100% rename from examples/Teensy/PlayRAD/shoot.rad rename to examples/OPL2AudioBoard/Teensy/PlayRAD/shoot.rad diff --git a/examples/Teensy/TeensyMidi/TeensyMidi.ino b/examples/OPL2AudioBoard/Teensy/TeensyMidi/TeensyMidi.ino similarity index 89% rename from examples/Teensy/TeensyMidi/TeensyMidi.ino rename to examples/OPL2AudioBoard/Teensy/TeensyMidi/TeensyMidi.ino index a27c808..5feba62 100644 --- a/examples/Teensy/TeensyMidi/TeensyMidi.ino +++ b/examples/OPL2AudioBoard/Teensy/TeensyMidi/TeensyMidi.ino @@ -39,7 +39,6 @@ struct Opl2Channel { // Midi channel properties. struct MidiChannel { Instrument instrument; - unsigned char *instrumentDataPtr; byte program; float volume; }; @@ -142,26 +141,18 @@ void onNoteOn(byte midiChannel, byte note, byte velocity) { return; } - // Fetch pointer to the instrument. - unsigned char *instrumentDataPtr = NULL; - if (midiChannel != MIDI_DRUM_CHANNEL) { - instrumentDataPtr = midiInstruments[midiChannelMap[midiChannel].program]; - } else if (note >= DRUM_NOTE_BASE && note < DRUM_NOTE_BASE + NUM_MIDI_DRUMS) { - instrumentDataPtr = midiDrums[note - DRUM_NOTE_BASE]; - } - - if (instrumentDataPtr != NULL) { - // Load new instrument if needed. - if (instrumentDataPtr != midiChannelMap[midiChannel].instrumentDataPtr) { - midiChannelMap[midiChannel].instrument = opl2.loadInstrument(instrumentDataPtr); - } - // Register channel mapping. byte opl2Channel = getFreeChannel(midiChannel); opl2ChannelMap[opl2Channel].midiChannel = midiChannel; opl2ChannelMap[opl2Channel].midiNote = note; opl2ChannelMap[opl2Channel].noteVelocity = log(min((float)velocity, 127.0)) / log(127.0); + // For notes on drum channel the note determines the instrument to load. + if (midiChannel == MIDI_DRUM_CHANNEL && note >= DRUM_NOTE_BASE && note < DRUM_NOTE_BASE + NUM_MIDI_DRUMS) { + const unsigned char *instrumentDataPtr = midiDrums[note - DRUM_NOTE_BASE]; + midiChannelMap[MIDI_DRUM_CHANNEL].instrument = opl2.loadInstrument(instrumentDataPtr); + } + // Calculate octave and note number. byte opl2Octave = 4; byte opl2Note = NOTE_C; @@ -175,7 +166,6 @@ void onNoteOn(byte midiChannel, byte note, byte velocity) { opl2.setInstrument(opl2Channel, midiChannelMap[midiChannel].instrument, opl2ChannelMap[opl2Channel].noteVelocity); opl2.playNote(opl2Channel, opl2Octave, opl2Note); } -} /** @@ -211,10 +201,19 @@ void onNoteOff(byte midiChannel, byte note, byte velocity) { /** - * Handle instrument change on the given MIDI channel. + * Handle instrument change on the given MIDI channel and load the instrument if the MIDI channel is not the drum + * channel where the note determines the instrument. */ void onProgramChange(byte midiChannel, byte program) { - midiChannelMap[midiChannel % 16].program = min(program, 127); + midiChannel = midiChannel % 16; + program = min(program, 127); + midiChannelMap[midiChannel].program = program; + + // Fetch pointer to the instrument and load. + if (midiChannel != MIDI_DRUM_CHANNEL) { + const unsigned char *instrumentDataPtr = midiInstruments[program]; + midiChannelMap[midiChannel].instrument = opl2.loadInstrument(instrumentDataPtr); + } } @@ -279,19 +278,15 @@ void onControlChange(byte midiChannel, byte control, byte value) { * Handle full system reset. */ void onSystemReset() { - opl2.init(); + opl2.begin(); // Default channel volume to 80% float defaultVolume = log(127.0 * 0.8) / log(127.0); - unsigned char *defaultInstrumentPtr = midiInstruments[0]; - Instrument defaultInstrument = opl2.loadInstrument(defaultInstrumentPtr); // Reset default MIDI player parameters. for (byte i = 0; i < MIDI_NUM_CHANNELS; i ++) { - midiChannelMap[i].program = 0; + onProgramChange(i, 0); midiChannelMap[i].volume = defaultVolume; - midiChannelMap[i].instrumentDataPtr = defaultInstrumentPtr; - midiChannelMap[i].instrument = defaultInstrument; } // Silence all channels and set default instrument. diff --git a/examples/Teensy/TeensyMidi/name.c b/examples/OPL2AudioBoard/Teensy/TeensyMidi/name.c similarity index 100% rename from examples/Teensy/TeensyMidi/name.c rename to examples/OPL2AudioBoard/Teensy/TeensyMidi/name.c diff --git a/examples/Teensy/TeensyMidi/usb_names.h b/examples/OPL2AudioBoard/Teensy/TeensyMidi/usb_names.h similarity index 100% rename from examples/Teensy/TeensyMidi/usb_names.h rename to examples/OPL2AudioBoard/Teensy/TeensyMidi/usb_names.h diff --git a/examples/OPL3Duo/4OperatorRandomMusic/4OperatorRandomMusic.ino b/examples/OPL3Duo/4OperatorRandomMusic/4OperatorRandomMusic.ino new file mode 100644 index 0000000..18966f1 --- /dev/null +++ b/examples/OPL3Duo/4OperatorRandomMusic/4OperatorRandomMusic.ino @@ -0,0 +1,54 @@ +/** + * This is a demonstration sketch for the OPL3 Duo! This example demonstrates the use of 4-operator instruments and how + * to play notes on a 4-op channel. It will play random ontes across all 12 4-operator channels. + * + * Code by Maarten Janssen, 2020-07-23 + * WWW.CHEERFUL.NL + * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 + */ + + +#include +#include + + +OPL3Duo opl3Duo; +Instrument4OP instrument; + +int ch4 = 0; // 4-OP channel index. + + +void setup() { + // Initialize the OPL3Duo! and enable OPL3 features (requered to enable 4-OP channel support). + opl3Duo.begin(); + opl3Duo.setOPL3Enabled(true); + + // Load a 4-OP piano instrument. + instrument = opl3Duo.loadInstrument4OP(INSTRUMENT_XYLO); + + // Enable all 4-OP channels and assign the same instrument to each channel. + opl3Duo.setAll4OPChannelsEnabled(true); + for (int i = 0; i < opl3Duo.getNum4OPChannels(); i ++) { + opl3Duo.setInstrument4OP(i, instrument); + } +} + + +void loop() { + // Define a random note on the 4th or 5th octave. + byte noteIndex = random(0, 24); + byte octave = 4 + (noteIndex / 12); + byte note = noteIndex % 12; + + // Get 2-OP channel that serves as the control channel for frequency, block and key-on for the 4-OP channel pair and + // play the random note. + byte controlChannel = opl3Duo.get4OPControlChannel(ch4); + opl3Duo.playNote(controlChannel, octave, note); + + // play the next note on another 4-OP channel. We take the modulo of num4OPChannels here for good measure to keep + // within a valid range. it is not strictly needed as the library will also do this internally when the 4-OP channel + // index exceeds the number of available channels. + ch4 = (ch4 + 1) % opl3Duo.getNum4OPChannels(); + + delay(200); +} diff --git a/examples/OPL3Duo/BackgroundTuneParser/BackgroundTuneParser.ino b/examples/OPL3Duo/BackgroundTuneParser/BackgroundTuneParser.ino new file mode 100644 index 0000000..7b24830 --- /dev/null +++ b/examples/OPL3Duo/BackgroundTuneParser/BackgroundTuneParser.ino @@ -0,0 +1,46 @@ +/** + * This is a demonstration sketch for the OPL3 Duo! It demonstrates how the TuneParser can be used to play music in the + * and loop a piece of music in the background while the Arduino is performing other tasks. + * + * Code by Maarten Janssen, 2020-10-04 + * WWW.CHEERFUL.NL + * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 + */ + + +#include +#include +#include + +const char pattern1[] PROGMEM = "t120i44o3l16 frfrfrfrfrfrfrfr grgrgrgrgrgrgrgr brbrbrbr arararar grgrgrgrgrgrgrfr grgrgrgrgrgrgrgr"; +const char pattern2[] PROGMEM = " i44o3l16 arararararararar brbrbrbrbrbrbrbr >drdrdrdr crcrcrcr +#include +#include + +const char voice1[] PROGMEM = "i96t150o5l8egredgrdcerceraagdefefedr4.regredgrdcerceraagdedcr4.ccea>crcrcdfegredgrdcerceraagdedcr4.cro3c2r2"; +const char voice2[] PROGMEM = "i96o4l8crer
drcrcrcrerdgcrer
drcrcrceger4.rfrafergedrfdcrec
dcdrcrcrcege"; +const char voice3[] PROGMEM = "i2o3l8r4gr4.gr4.er4.err4fr4.gr4.gr4.grr4gr4.er4.er4.frr4gr4>ccr4ccr4dr4.r +#include + + +OPL3Duo opl3Duo; +Instrument testInstrument; +Instrument testInstrument2; + + +void setup() { + delay(1000); + Serial.begin(9600); + opl3Duo.begin(); + testInstrument = opl3Duo.loadInstrument(INSTRUMENT_SYN1); + testInstrument2 = opl3Duo.loadInstrument(INSTRUMENT_FLUTE); + + Serial.println("This sketch tests the basic functions of the OPL3 Duo board."); + Serial.println("The expected test reulst is shown for each test."); + Serial.println("On each test press ENTER to advance to the next test."); + Serial.println(""); + Serial.println("Press ENTER to begin..."); + Serial.println(""); +} + + +void loop() { + while (!wasEnterPressed()); + testSynthUnit1(); + opl3Duo.setOPL3Enabled(true); + testUnit1Panning(); + opl3Duo.setOPL3Enabled(false); + testSynthUnit2(); + opl3Duo.setOPL3Enabled(true); + testUnit2Panning(); + opl3Duo.setOPL3Enabled(false); + testReset(); + Serial.println("Done."); + Serial.println(""); + Serial.println("Press ENTER to repeat the tests..."); + Serial.println(""); +} + + +void testSynthUnit1() { + Serial.println("TEST 1: Synth unit 1..."); + Serial.println("- You should hear a steady tone and a continuous scale through both speakers."); + Serial.println(""); + + // Play a 250 Hz tone on channel 0 of synth unit 2. + playTone(18); + + // Play a scale on all channels of synth unit 1. + byte channel = 0; + byte note = 0; + while (!wasEnterPressed()) { + opl3Duo.setInstrument(channel, testInstrument); + opl3Duo.playNote(channel, 5, note); + delay(200); + opl3Duo.setKeyOn(channel, false); + + channel = (channel + 1) % 18; + note = (note + 1) % 12; + } + + // Stop background tone. + opl3Duo.setKeyOn(18, false); + delay(500); +} + + +void testUnit1Panning() { + Serial.println("TEST 2: Synth unit 1 left channel..."); + Serial.println("- You should hear a steady tone through the left speaker only."); + Serial.println(""); + + opl3Duo.setInstrument(0, testInstrument2); + opl3Duo.setPanning(0, true, false); + opl3Duo.playNote(0, 4, NOTE_C); + while (!wasEnterPressed()); + opl3Duo.setKeyOn(0, false); + + delay(500); + + Serial.println("Test 3: Synth unit 1 right channel..."); + Serial.println("- You should hear a steady tone through the right speaker only."); + Serial.println(""); + + opl3Duo.setPanning(0, false, true); + opl3Duo.playNote(0, 4, NOTE_C); + while (!wasEnterPressed()); + opl3Duo.setKeyOn(0, false); + + opl3Duo.setPanning(0, true, true); + delay(500); +} + + +void testSynthUnit2() { + Serial.println("TEST 4: Synth unit 2..."); + Serial.println("- You should hear a steady tone and a continuous scale through both speakers."); + Serial.println(""); + + // Play a 250 Hz tone on channel 0 of synth unit 1. + playTone(0); + + // Play a scale on all channels of synth unit 2. + byte channel = 0; + byte note = 0; + while (!wasEnterPressed()) { + opl3Duo.setInstrument(18 + channel, testInstrument); + opl3Duo.playNote(18 + channel, 5, note); + delay(200); + opl3Duo.setKeyOn(18 + channel, false); + + channel = (channel + 1) % 18; + note = (note + 1) % 12; + } + + // Stop background tone. + opl3Duo.setKeyOn(0, false); + delay(500); +} + + +void testUnit2Panning() { + Serial.println("TEST 5: Synth unit 2 left channel..."); + Serial.println("- You should hear a steady tone through the left speaker only."); + Serial.println(""); + + opl3Duo.setInstrument(18, testInstrument2); + opl3Duo.setPanning(18, true, false); + opl3Duo.playNote(18, 4, NOTE_C); + while (!wasEnterPressed()); + opl3Duo.setKeyOn(18, false); + + delay(500); + Serial.println("Test 6: Synth unit 2 right channel..."); + Serial.println("- You should hear a steady tone through the right speaker only."); + Serial.println(""); + + opl3Duo.setPanning(18, false, true); + opl3Duo.playNote(18, 4, NOTE_C); + while (!wasEnterPressed()); + opl3Duo.setKeyOn(18, false); + + opl3Duo.setPanning(18, true, true); + delay(500); +} + + +void testReset() { + Serial.println("TEST 7: OPL3 Duo reset..."); + Serial.println("- There should be no sound."); + Serial.println(""); + + playTone(0); + playTone(18); + opl3Duo.reset(); + + while (!wasEnterPressed()); + delay(500); +} + + +/** + * Play a tone of 250 Hz on the given channel. + */ +void playTone(byte channel) { + opl3Duo.setInstrument(channel, testInstrument2); + opl3Duo.playNote(channel, 4, NOTE_C); +} + + +bool wasEnterPressed() { + if (Serial.available() > 0) { + char key = Serial.read(); + return key == 0x0A; + } + + return false; +} diff --git a/examples/OPL3Duo/Panning/Panning.ino b/examples/OPL3Duo/Panning/Panning.ino new file mode 100644 index 0000000..1fe7090 --- /dev/null +++ b/examples/OPL3Duo/Panning/Panning.ino @@ -0,0 +1,61 @@ +/** + * This is a demonstration sketch for the OPL3 Duo! This example shows how the panning bits of the OPL3 can be used. It + * will play a simple ping sound on the left, right and on both speakers in order. + * + * Code by Maarten Janssen, 2020-08-23 + * WWW.CHEERFUL.NL + * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 + */ + + +#include + + +OPL3Duo opl3Duo; + +void setup() { + // Initialize the OPL3Duo! and enable OPL3 features (requered to enable panning support). + opl3Duo.begin(); + opl3Duo.setOPL3Enabled(true); + + // Define a simple ping sound on channel 0. + for (byte i = 0; i < 2; i ++) { + opl3Duo.setAttack(0, i, 8); + opl3Duo.setDecay(0, i, 1); + opl3Duo.setSustain(0, i, 0); + opl3Duo.setRelease(0, i, 4); + opl3Duo.setMaintainSustain(0, i, true); + opl3Duo.setEnvelopeScaling(0, i, true); + opl3Duo.setMultiplier(0, i, 1); + opl3Duo.setScalingLevel(0, i, 1); + opl3Duo.setVolume(0, i, 0); + } + opl3Duo.setSynthMode(0, true); +} + + +void loop() { + // Left speaker. + opl3Duo.setPanning(0, true, false); + opl3Duo.playNote(0, 5, NOTE_A); + delay(200); + opl3Duo.setKeyOn(0, false); + + delay(300); + + // Right speaker. + opl3Duo.setPanning(0, false, true); + opl3Duo.playNote(0, 5, NOTE_A); + delay(200); + opl3Duo.setKeyOn(0, false); + + delay(300); + + // Both speakers. + opl3Duo.setPanning(0, true, true); + opl3Duo.playNote(0, 5, NOTE_A); + delay(200); + opl3Duo.setKeyOn(0, false); + + delay(800); +} \ No newline at end of file diff --git a/examples/OPL3Duo/Panning_Gradual/Panning_Gradual.ino b/examples/OPL3Duo/Panning_Gradual/Panning_Gradual.ino new file mode 100644 index 0000000..a7b3d03 --- /dev/null +++ b/examples/OPL3Duo/Panning_Gradual/Panning_Gradual.ino @@ -0,0 +1,58 @@ +/** + * This is a demonstration sketch for the OPL3 Duo! it shows a more elegant panning technique. + * + * Though the OPL3 can produce stereo sound, it's panning capabilities are only limited. You can eather play the sound + * of a channel on the left speaker only, the right speaker only or on both. Gradual panning between the left and right + * speaker is not possible. This demonstration shows how gradual panning can still be achieved using two channels. + * Channel 0 will output to the left speaker and channel 1 will output to the right speaker. By inverting the volume of + * channel 0 on channel 1 we can achieve 63 steps of panning as this demo will show with a ping sound that drifts + * between the left and the right speaker. + * + * Code by Maarten Janssen, 2020-08-23 + * WWW.CHEERFUL.NL + * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 + */ + + +#include + + +OPL3Duo opl3Duo; +int t = 0; + + +void setup() { + // Initialize the OPL3Duo! and enable OPL3 features (requered to enable panning support). + opl3Duo.begin(); + opl3Duo.setOPL3Enabled(true); + + // Define a simple continuous sound for channels 0 and 1. + for (byte i = 0; i < 2; i++) { + opl3Duo.setAttack(i, CARRIER, 8); + opl3Duo.setSustain(i, CARRIER, 4); + opl3Duo.setMaintainSustain(i, CARRIER, true); + opl3Duo.setMultiplier(i, CARRIER, 1); + opl3Duo.setVolume(i, CARRIER, 0); + } + + // Set panning for channels 0 (left) and 1 (right). + opl3Duo.setPanning(0, true, false); + opl3Duo.setPanning(1, false, true); + + // Start playing the tone on both channels. + opl3Duo.playNote(0, 5, NOTE_A); + opl3Duo.playNote(1, 5, NOTE_A); +} + + +void loop() { + // Define channel volume as a sine wave so it will gradually increase and decrease. + byte volume = (sin((float)t / 50) * 31) + 31; + + // Apply volume to both channels. + opl3Duo.setChannelVolume(0, volume); + opl3Duo.setChannelVolume(1, 63 - volume); + + delay(10); + t ++; +} diff --git a/examples/OPL3Duo/TeensyMidi/TeensyMidi.c b/examples/OPL3Duo/TeensyMidi/TeensyMidi.c new file mode 100644 index 0000000..72c938c --- /dev/null +++ b/examples/OPL3Duo/TeensyMidi/TeensyMidi.c @@ -0,0 +1,10 @@ +#include "usb_names.h" + +#define MIDI_NAME { 'O','P','L','3','D','u','o',' ','M','I','D','I' } +#define MIDI_NAME_LEN 12 + +struct usb_string_descriptor_struct usb_string_product_name = { + 2 + MIDI_NAME_LEN * 2, + 3, + MIDI_NAME +}; diff --git a/examples/OPL3Duo/TeensyMidi/TeensyMidi.h b/examples/OPL3Duo/TeensyMidi/TeensyMidi.h new file mode 100644 index 0000000..60ca59a --- /dev/null +++ b/examples/OPL3Duo/TeensyMidi/TeensyMidi.h @@ -0,0 +1,58 @@ +#include + +#define NUM_MIDI_CHANNELS 16 +#define NUM_MELODIC_CHANNELS 12 +#define NUM_DRUM_CHANNELS 12 + +#define MIDI_DRUM_CHANNEL 10 +#define VALUE_UNDEFINED 255 + +// MIDI note number of the first drum sound. +#define DRUM_NOTE_BASE 27 +#define NUM_MIDI_DRUMS 60 + + +struct MidiChannel { + Instrument4OP instrument; // Current instrument. + byte program; // Program number currenly associated witht this MIDI channel. + float volume; // Channel volume. +}; + + +struct OPLChannel { + unsigned long eventIndex; // Midi event index to determine oldest channel to reuse. + byte midiChannel; // Midi channel associated with the event. + byte program; // Program number of the instrument loaded on the OPL channel. + byte note; // Note number playing on the channel (0xFF when channel is free). + float noteVelocity; // Velocity of the note on event. +}; + + +// Note FNumbers per octave +/- 2 semitones for pitch bend. +const unsigned int notePitches[16] = { + 0x132, 0x144, + 0x156, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, + 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, + 0x2AC, 0x2D6 +}; + +// OPL channels used for drums. +const byte drumChannelsOPL[12] = { + 6, 7, 8, 15, 16, 17, + 24, 25, 26, 33, 34, 35 +}; + + +void setup(); +void loop(); +byte getFreeMelodicChannel(); +byte getFreeDrumChannel(); +void playDrum(byte note, byte velocity); +void playMelodic(byte midiChannel, byte note, byte velocity); +void setOplChannelVolume(byte channel4OP, byte midiChannel); +void onNoteOff(byte midiChannel, byte note, byte velocity); +void onNoteOn(byte midiChannel, byte note, byte velocity); +void onProgramChange(byte midiChannel, byte program); +void onControlChange(byte midiChannel, byte control, byte value); +void onPitchChange(byte midiChannel, int pitch); +void onSystemReset(); diff --git a/examples/OPL3Duo/TeensyMidi/TeensyMidi.ino b/examples/OPL3Duo/TeensyMidi/TeensyMidi.ino new file mode 100644 index 0000000..4bcf7f8 --- /dev/null +++ b/examples/OPL3Duo/TeensyMidi/TeensyMidi.ino @@ -0,0 +1,430 @@ +/** + * This example can be used together with a Teensy 2.0 or later to use the OPL3Duo as a MIDI device. To configure the + * Teensy as a MIDI device set USB Type to MIDI in the IDE using Tools > USB Type > MIDI. Once connected the board + * should appear in the device list as 'OPL3Duo MIDI'. You can now use test the board with, for example, MIDI-OX, your + * favorite music creation software or DosBox! + * + * Code by Maarten Janssen, 2020-06-20 + * WWW.CHEERFUL.NL + * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 + */ + +#include +#include +#include +#include +#include "TeensyMidi.h" + + +#define CONTROL_VOLUME 7 +#define CONTROL_ALL_SOUND_OFF 120 +#define CONTROL_RESET_ALL 121 +#define CONTROL_ALL_NOTES_OFF 123 + + + +OPL3Duo opl3; + +MidiChannel midiChannels[NUM_MIDI_CHANNELS]; +OPLChannel melodicChannels[NUM_MELODIC_CHANNELS]; +OPLChannel drumChannels[NUM_DRUM_CHANNELS]; +unsigned long midiEventIndex = 0; + + +/** + * Register MIDI event handlers and initialize. + */ +void setup() { + usbMIDI.setHandleNoteOn(onNoteOn); + usbMIDI.setHandleNoteOff(onNoteOff); + usbMIDI.setHandleProgramChange(onProgramChange); + usbMIDI.setHandleControlChange(onControlChange); + usbMIDI.setHandlePitchChange(onPitchChange); + usbMIDI.setHandleSystemReset(onSystemReset); + onSystemReset(); +} + + +/** + * Read and handle MIDI events. + */ +void loop() { + usbMIDI.read(); +} + + +void playMelodic(byte midiChannel, byte note, byte velocity) { + midiChannel = midiChannel % NUM_MIDI_CHANNELS; + + byte program = midiChannels[midiChannel].program; + byte oplChannelIndex = VALUE_UNDEFINED; + + // Look for the oldest free melodic channel with the same program. There should be at least 2 free channels with the + // same program so we're not clubbering the release portion of an older note. + unsigned long oldest = -1; + byte sameProgramCount = 0; + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].program == program && melodicChannels[i].note == VALUE_UNDEFINED) { + sameProgramCount ++; + if (melodicChannels[i].eventIndex < oldest) { + oldest = melodicChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + // If there is no free channel or less than 2 with the smae program then look for any free channel. + if (oplChannelIndex == VALUE_UNDEFINED || sameProgramCount < 2) { + oldest = -1; + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].note == VALUE_UNDEFINED && melodicChannels[i].eventIndex < oldest) { + oldest = melodicChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + // No free channels, recycle the oldest channel with the same program. + if (oplChannelIndex == VALUE_UNDEFINED) { + oldest = -1; + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].program == program && melodicChannels[i].eventIndex < oldest) { + oldest = melodicChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + // Still no channel, simply recycle the oldest. + if (oplChannelIndex == VALUE_UNDEFINED) { + oldest = -1; + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].eventIndex < oldest) { + oldest = melodicChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + if (oplChannelIndex != VALUE_UNDEFINED) { + opl3.setKeyOn(opl3.get4OPControlChannel(oplChannelIndex), false); + + midiEventIndex ++; + melodicChannels[oplChannelIndex].eventIndex = midiEventIndex; + melodicChannels[oplChannelIndex].midiChannel = midiChannel; + melodicChannels[oplChannelIndex].note = note; + melodicChannels[oplChannelIndex].noteVelocity = log(min((float)velocity, 127.0)) / log(127.0); + + // If the program loaded on the OPL channel is differs from the MIDI channel, then first send new instrument + // parameters to the OPL. + if (melodicChannels[oplChannelIndex].program != program) { + melodicChannels[oplChannelIndex].program = program; + opl3.setFNumber(opl3.get4OPControlChannel(oplChannelIndex), 0); + opl3.setInstrument4OP( + oplChannelIndex, + midiChannels[midiChannel].instrument, + 0.0 + ); + } + setOplChannelVolume(oplChannelIndex, midiChannel); + + note = max(24, min(note, 119)); + byte octave = 1 + (note - 24) / 12; + note = note % 12; + opl3.playNote( + opl3.get4OPControlChannel(oplChannelIndex), + octave, + note + ); + } +} + + +void playDrum(byte note, byte velocity) { + byte program; + if (note >= DRUM_NOTE_BASE && note < DRUM_NOTE_BASE + NUM_MIDI_DRUMS) { + program = note - DRUM_NOTE_BASE; + } else { + return; + } + + byte oplChannelIndex = VALUE_UNDEFINED; + unsigned long oldest = -1; + + // Look for the oldest free drum channel with the same program. + oldest = -1; + for (byte i = 0; i < NUM_DRUM_CHANNELS; i ++) { + if (drumChannels[i].program == program && drumChannels[i].note == VALUE_UNDEFINED && drumChannels[i].eventIndex < oldest) { + oldest = drumChannels[i].eventIndex; + oplChannelIndex = i; + } + } + + // Look for any free drum channel. + if (oplChannelIndex == VALUE_UNDEFINED) { + oldest = -1; + for (byte i = 0; i < NUM_DRUM_CHANNELS; i ++) { + if (drumChannels[i].note == VALUE_UNDEFINED && drumChannels[i].eventIndex < oldest) { + oldest = drumChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + // Look for the oldest drum channel with the same instrument. + if (oplChannelIndex == VALUE_UNDEFINED) { + oldest = -1; + for (byte i = 0; i < NUM_DRUM_CHANNELS; i ++) { + if (drumChannels[i].program == program && drumChannels[i].eventIndex < oldest) { + oldest = drumChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + // Recycle the oldest drum channel if still all channels are occupied. + if (oplChannelIndex == VALUE_UNDEFINED) { + oldest = -1; + for (byte i = 0; i < NUM_DRUM_CHANNELS; i ++) { + if (drumChannels[i].eventIndex < oldest) { + oldest = drumChannels[i].eventIndex; + oplChannelIndex = i; + } + } + } + + if (oplChannelIndex != VALUE_UNDEFINED) { + opl3.setKeyOn(drumChannelsOPL[oplChannelIndex], false); + + midiEventIndex ++; + drumChannels[oplChannelIndex].eventIndex = midiEventIndex; + drumChannels[oplChannelIndex].note = note; + drumChannels[oplChannelIndex].noteVelocity = log(min((float)velocity, 127.0)) / log(127.0); + + // If the program loaded on the OPL channel is differs from the MIDI channel, then first send new instrument + // parameters to the OPL. + if (drumChannels[oplChannelIndex].program != program) { + drumChannels[oplChannelIndex].program = program; + Instrument drumInstrument = opl3.loadInstrument(midiDrums[program]); + opl3.setInstrument( + drumChannelsOPL[oplChannelIndex], + drumInstrument, + log(min((float)velocity, 127.0)) / log(127.0) + ); + } else { + // setOplChannelVolume(oplChannelIndex, MIDI_DRUM_CHANNEL); + } + + opl3.playNote(drumChannelsOPL[oplChannelIndex], 4, NOTE_C); + } +} + + +/** + * Set the volume of operators 1 and 2 of the given OPL2 channel according to the settings of the given MIDI channel. + */ +void setOplChannelVolume(byte channel4OP, byte midiChannel) { + if (midiChannel == MIDI_DRUM_CHANNEL) { + return; + } + + Instrument4OP instrument = midiChannels[midiChannel].instrument; + float volume = melodicChannels[channel4OP].noteVelocity * midiChannels[midiChannel].volume; + for (byte i = 0; i < 2; i ++) { + float op1Level = (float)(63 - instrument.subInstrument[i].operators[OPERATOR1].outputLevel) / 63.0; + float op2Level = (float)(63 - instrument.subInstrument[i].operators[OPERATOR2].outputLevel) / 63.0; + byte volumeOp1 = round(op1Level * volume * 63.0); + byte volumeOp2 = round(op2Level * volume * 63.0); + opl3.setVolume(opl3.get4OPControlChannel(channel4OP, i), OPERATOR1, 63 - volumeOp1); + opl3.setVolume(opl3.get4OPControlChannel(channel4OP, i), OPERATOR2, 63 - volumeOp2); + } +} + + +/** + * Handle a note off MIDI event to stop playing a note. + */ +void onNoteOff(byte midiChannel, byte note, byte velocity) { + midiChannel = midiChannel % NUM_MIDI_CHANNELS; + + if (midiChannel == MIDI_DRUM_CHANNEL) { + for (byte i = 0; i < NUM_DRUM_CHANNELS; i ++) { + if (drumChannels[i].note == note) { + opl3.setKeyOn(drumChannelsOPL[i], false); + drumChannels[i].note = VALUE_UNDEFINED; + } + } + } else { + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].midiChannel == midiChannel && melodicChannels[i].note == note) { + opl3.setKeyOn(opl3.get4OPControlChannel(i), false); + melodicChannels[i].note = VALUE_UNDEFINED; + } + } + } +} + + +/** + * Handle a note on MIDI event to play a note. + */ +void onNoteOn(byte midiChannel, byte note, byte velocity) { + midiChannel = midiChannel % NUM_MIDI_CHANNELS; + + // Treat notes with a velocity of 0 as note off. + if (velocity == 0) { + onNoteOff(midiChannel, note, velocity); + } else { + if (midiChannel == MIDI_DRUM_CHANNEL) { + playDrum(note, velocity); + } else { + playMelodic(midiChannel, note, velocity); + } + } +} + + +/** + * Handle program changes. If the progranm change occurs on a melodic channel then load the instrument and store it with + * the MIDI channel. + */ +void onProgramChange(byte midiChannel, byte program) { + midiChannel = midiChannel % NUM_MIDI_CHANNELS; + + if (midiChannel != MIDI_DRUM_CHANNEL) { + program = program % 128; + const unsigned char *instrumentDataPtr = midiInstruments[program]; + Instrument4OP instrument = opl3.loadInstrument4OP(instrumentDataPtr); + + midiChannels[midiChannel].program = program; + midiChannels[midiChannel].instrument = instrument; + } +} + + +/** + * Handle MIDI control changes on the given channel. + */ +void onControlChange(byte midiChannel, byte control, byte value) { + midiChannel = midiChannel % NUM_MIDI_CHANNELS; + + switch (control) { + + // Change volume of a MIDI channel. If volume is changed on a melodic channel then the change is applied + // immediately. + case CONTROL_VOLUME: { + midiChannels[midiChannel].volume = log(min((float)value, 127.0)) / log(127.0); + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].midiChannel == midiChannel && melodicChannels[i].note != VALUE_UNDEFINED) { + setOplChannelVolume(i, midiChannel); + } + } + break; + } + + // Reset all controller values. + case CONTROL_RESET_ALL: + for (byte i = 0; i < NUM_MIDI_CHANNELS; i ++) { + midiChannels[i].volume = log(127.0 * 0.8) / log(127.0); + } + break; + + // Immediately silence all channels immedialtey, ignores release part of envelope. + // Intentionally cascade into CONTROL_ALL_NOTES_OFF! + case CONTROL_ALL_SOUND_OFF: + for (byte i = 0; i < opl3.getNumChannels(); i ++) { + opl3.setRelease(i, OPERATOR1, 0); + opl3.setRelease(i, OPERATOR2, 0); + opl3.setKeyOn(i, false); + } + + // Silence all MIDI channels, but still allow for note release to sound. + case CONTROL_ALL_NOTES_OFF: { + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + // if (oplDrumChannel[i].midiNote != 0x00) { + // onNoteOff(MIDI_DRUM_CHANNEL, oplDrumChannel[i].midiNote, 0); + // } + if (melodicChannels[i].note != VALUE_UNDEFINED) { + onNoteOff(melodicChannels[i].midiChannel, melodicChannels[i].note, 0); + } + } + break; + } + + // Ignore any other MIDI controls. + default: + break; + } +} + + +/** + * Apply a pitch bend to all notes currently playing on the given MIDI channel. + * + * Note: Pitch bend is not applied to OPL channels that have a note in release, because when notes of different + * frequencies are released changing their frequency may cause audible jitter. + */ +void onPitchChange(byte midiChannel, int pitch) { + midiChannel = midiChannel % NUM_MIDI_CHANNELS; + float pitchBend = abs(pitch) / 8192.0; + + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + if (melodicChannels[i].midiChannel == midiChannel) { + byte controlChannel = opl3.get4OPControlChannel(i); + byte baseNote = (melodicChannels[i].note % 12) + 2; + + if (pitch < 0) { + byte fDelta = (notePitches[baseNote] - notePitches[baseNote - 2]) * pitchBend; + opl3.setFNumber(controlChannel, notePitches[baseNote] - fDelta); + } else if (pitch > 0) { + byte fDelta = (notePitches[baseNote + 2] - notePitches[baseNote]) * pitchBend; + opl3.setFNumber(controlChannel, notePitches[baseNote] + fDelta); + } else { + opl3.setFNumber(controlChannel, notePitches[baseNote]); + } + } + } +} + + +/** + * Handle full system reset. + */ +void onSystemReset() { + opl3.begin(); + opl3.setDeepVibrato(true); + opl3.setDeepTremolo(true); + opl3.setOPL3Enabled(true); + opl3.setAll4OPChannelsEnabled(true); + + // Default channel volume to 80% + float defaultVolume = log(127.0 * 0.8) / log(127.0); + + // Reset default MIDI player parameters. + for (byte i = 0; i < NUM_MIDI_CHANNELS; i ++) { + onProgramChange(i, 0); + midiChannels[i].volume = defaultVolume; + } + + // Initialize melodic channels. + for (byte i = 0; i < NUM_MELODIC_CHANNELS; i ++) { + melodicChannels[i].eventIndex = 0; + melodicChannels[i].midiChannel = 0; + melodicChannels[i].program = VALUE_UNDEFINED; + melodicChannels[i].note = VALUE_UNDEFINED; + melodicChannels[i].noteVelocity = 0.0; + } + + // Initialize drum channels. + for (byte i = 0; i < NUM_DRUM_CHANNELS; i ++) { + drumChannels[i].eventIndex = 0; + drumChannels[i].midiChannel = MIDI_DRUM_CHANNEL; + drumChannels[i].program = VALUE_UNDEFINED; + drumChannels[i].note = VALUE_UNDEFINED; + drumChannels[i].noteVelocity = 0.0; + } + + midiEventIndex = 0; +} + + diff --git a/examples/OPL3Duo/TeensyMidi/usb_names.h b/examples/OPL3Duo/TeensyMidi/usb_names.h new file mode 100644 index 0000000..1cd5fda --- /dev/null +++ b/examples/OPL3Duo/TeensyMidi/usb_names.h @@ -0,0 +1,57 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2017 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _usb_names_h_ +#define _usb_names_h_ + +// These definitions are intended to allow users to override the default +// USB manufacturer, product and serial number strings. + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct usb_string_descriptor_struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wString[]; +}; + +extern struct usb_string_descriptor_struct usb_string_manufacturer_name; +extern struct usb_string_descriptor_struct usb_string_product_name; +extern struct usb_string_descriptor_struct usb_string_serial_number; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extra/OPL2_board.jpg b/extra/OPL2_board.jpg index 083b739..08e32b0 100644 Binary files a/extra/OPL2_board.jpg and b/extra/OPL2_board.jpg differ diff --git a/extra/OPL2_board_schematic_RevC.png b/extra/OPL2_board_schematic_RevC.png deleted file mode 100644 index 7889e89..0000000 Binary files a/extra/OPL2_board_schematic_RevC.png and /dev/null differ diff --git a/extra/OPL2_board_schematic_RevD.png b/extra/OPL2_board_schematic_RevD.png deleted file mode 100644 index 478d368..0000000 Binary files a/extra/OPL2_board_schematic_RevD.png and /dev/null differ diff --git a/extra/OPL3Duo_board.jpg b/extra/OPL3Duo_board.jpg new file mode 100644 index 0000000..719dd2a Binary files /dev/null and b/extra/OPL3Duo_board.jpg differ diff --git a/keywords.txt b/keywords.txt index 1cb82ce..780208f 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,22 +7,50 @@ ####################################### OPL2 KEYWORD1 +OPL3 KEYWORD1 +OPL3Duo KEYWORD1 Operator KEYWORD1 Instrument KEYWORD1 +Instrument4OP KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### -init KEYWORD2 +begin KEYWORD2 reset KEYWORD2 -write KEYWORD2 +createShadowRegisters KEYWORD2 +init KEYWORD2 +getChipRegister KEYWORD2 +getChannelRegister KEYWORD2 +getOperatorRegister KEYWORD2 getRegisterOffset KEYWORD2 +setChipRegister KEYWORD2 +setChannelRegister KEYWORD2 +setOperatorRegister KEYWORD2 +getChipRegisterOffset KEYWORD2 +getChannelRegisterOffset KEYWORD2 +getOperatorRegisterOffset KEYWORD2 +write KEYWORD2 +getNumChannels KEYWORD2 +getNum4OPChannels KEYWORD2 +get4OPControlChannel KEYWORD2 getFrequencyBlock KEYWORD2 getFrequencyFNumber KEYWORD2 getNoteFNumber KEYWORD2 getFrequencyStep KEYWORD2 -getRegister KEYWORD2 +playNote KEYWORD2 +playDrum KEYWORD2 +createInstrument KEYWORD2 +loadInstrument KEYWORD2 +getInstrument KEYWORD2 +getDrumInstrument KEYWORD2 +setInstrument KEYWORD2 +setDrumInstrument KEYWORD2 +createInstrument4OP KEYWORD2 +loadInstrument4OP KEYWORD2 +getInstrument4OP KEYWORD2 +setInstrument4OP KEYWORD2 getWaveFormSelect KEYWORD2 getTremolo KEYWORD2 getVibrato KEYWORD2 @@ -31,6 +59,7 @@ getEnvelopeScaling KEYWORD2 getMultiplier KEYWORD2 getScalingLevel KEYWORD2 getVolume KEYWORD2 +getChannelVolume KEYWORD2 getAttack KEYWORD2 getDecay KEYWORD2 getSustain KEYWORD2 @@ -38,6 +67,7 @@ getRelease KEYWORD2 getFNumber KEYWORD2 getFrequency KEYWORD2 getBlock KEYWORD2 +getNoteSelect KEYWORD2 getKeyOn KEYWORD2 getFeedback KEYWORD2 getSynthMode KEYWORD2 @@ -46,15 +76,6 @@ getDeepVibrato KEYWORD2 getPercussion KEYWORD2 getDrums KEYWORD2 getWaveForm KEYWORD2 -createInstrument KEYWORD2 -loadInstrument KEYWORD2 -getInstrument KEYWORD2 -setInstrument KEYWORD2 -getDrumInstrument KEYWORD2 -setDrumInstrument KEYWORD2 -playNote KEYWORD2 -playDrum KEYWORD2 -setRegister KEYWORD2 setWaveFormSelect KEYWORD2 setTremolo KEYWORD2 setVibrato KEYWORD2 @@ -63,6 +84,7 @@ setEnvelopeScaling KEYWORD2 setMultiplier KEYWORD2 setScalingLevel KEYWORD2 setVolume KEYWORD2 +setChannelVolume KEYWORD2 setAttack KEYWORD2 setDecay KEYWORD2 setSustain KEYWORD2 @@ -70,6 +92,7 @@ setRelease KEYWORD2 setFNumber KEYWORD2 setFrequency KEYWORD2 setBlock KEYWORD2 +setNoteSelect KEYWORD2 setKeyOn KEYWORD2 setFeedback KEYWORD2 setSynthMode KEYWORD2 @@ -77,7 +100,20 @@ setDeepTremolo KEYWORD2 setDeepVibrato KEYWORD2 setPercussion KEYWORD2 setDrums KEYWORD2 +setDrums KEYWORD2 setWaveForm KEYWORD2 +isOPL3Enabled KEYWORD2 +setOPL3Enabled KEYWORD2 +is4OPChannelEnabled KEYWORD2 +set4OPChannelEnabled KEYWORD2 +setAll4OPChannelsEnabled KEYWORD2 +isPannedLeft KEYWORD2 +isPannedRight KEYWORD2 +setPanning KEYWORD2 +get4OPSynthMode KEYWORD2 +set4OPSynthMode KEYWORD2 +get4OPChannelVolume KEYWORD2 +set4OPChannelVolume KEYWORD2 ####################################### # Instances (KEYWORD2) @@ -90,17 +126,33 @@ setWaveForm KEYWORD2 PIN_LATCH LITERAL1 PIN_ADDR LITERAL1 PIN_RESET LITERAL1 +OPL2_NUM_CHANNELS LITERAL1 +OPL3_NUM_2OP_CHANNELS LITERAL1 +OPL3_NUM_4OP_CHANNELS LITERAL1 +OPL3DUO_NUM_2OP_CHANNELS LITERAL1 +OPL3DUO_NUM_4OP_CHANNELS LITERAL1 +NUM_4OP_CHANNELS_PER_UNIT LITERAL1 +CHANNELS_PER_BANK LITERAL1 OPERATOR1 LITERAL1 OPERATOR2 LITERAL1 MODULATOR LITERAL1 -CARRIER LITERAL1 -FREQ_MODULATION LITERAL1 -ADDITIVE_SYNTH LITERAL1 +CARRIER LITERAL1 LITERAL1 +SYNTH_MODE_FM LITERAL1 +SYNTH_MODE_AM LITERAL1 +SYNTH_MODE_FM_FM LITERAL1 +SYNTH_MODE_FM_AM LITERAL1 +SYNTH_MODE_AM_FM LITERAL1 +SYNTH_MODE_AM_AM LITERAL1 DRUM_BASS LITERAL1 DRUM_SNARE LITERAL1 DRUM_TOM LITERAL1 DRUM_CYMBAL LITERAL1 DRUM_HI_HAT LITERAL1 +DRUM_BITS_BASS LITERAL1 +DRUM_BITS_SNARE LITERAL1 +DRUM_BITS_TOM LITERAL1 +DRUM_BITS_CYMBAL LITERAL1 +DRUM_BITS_HI_HAT LITERAL1 NOTE_C LITERAL1 NOTE_CS LITERAL1 NOTE_D LITERAL1 @@ -113,6 +165,14 @@ NOTE_GS LITERAL1 NOTE_A LITERAL1 NOTE_AS LITERAL1 NOTE_B LITERAL1 +NUM_OCTAVES LITERAL1 +NUM_NOTES LITERAL1 +NUM_DRUM_SOUNDS LITERAL1 INSTRUMENT_DATA_PROGMEM LITERAL1 INSTRUMENT_DATA_SRAM LITERAL1 -MELODIC_INSTRUMENT LITERAL1 +INSTRUMENT_TYPE_MELODIC LITERAL1 +INSTRUMENT_TYPE_BASS LITERAL1 +INSTRUMENT_TYPE_SNARE LITERAL1 +INSTRUMENT_TYPE_TOM LITERAL1 +INSTRUMENT_TYPE_CYMBAL LITERAL1 +INSTRUMENT_TYPE_HI_HAT LITERAL1 diff --git a/library.properties b/library.properties index 6f9c96f..1c9612a 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=Arduino OPL2 -version=1.5.3 +version=2.0.0 author=Maarten Janssen maintainer=Maarten Janssen -sentence=Use this library to control the OPL2 Audio Board -paragraph=This library works with the OPL2 Audio Board found on Tindie to play music and sounds through the YM3812 synthesizer chip or to use the board as a reald Adlib for DosBox. +sentence=Use this library to control the OPL2 Audio Board or OPL3 Duo! +paragraph=This library works with the OPL2 Audio Board and OPL3 Duo! board found on Tindie. You can use it to compose and play music and sounds through the YM3812 or YMF262 synthesizer chips. category=Device Control url=https://github.com/DhrBaksteen/ArduinoOPL2/ architectures=* diff --git a/src/OPL2.cpp b/src/OPL2.cpp index 01a3d49..cccbc24 100644 --- a/src/OPL2.cpp +++ b/src/OPL2.cpp @@ -16,8 +16,9 @@ * \____|__ /__| \____ |____/|__|___| /\____/ \_____\ \ |____| |__| * \/ \/ \/ \/ * - * YM3812 OPL2 Audio Library for Arduino, Raspberry Pi and Orange Pi v1.5.3 + * YM3812 OPL2 Audio Library for Arduino, Raspberry Pi and Orange Pi v2.0.0 * Code by Maarten Janssen (maarten@cheerful.nl) 2016-12-18 + * WWW.CHEERFUL.NL * * Look for example code on how to use this library in the examples folder. * @@ -35,12 +36,13 @@ * IMPORTANT: Make sure you set the correct BOARD_TYPE in OPL2.h. Default is set to Arduino. * * - * Last updated 2020-04-11 + * Last updated 2020-10-31 * Most recent version of the library can be found at my GitHub: https://github.com/DhrBaksteen/ArduinoOPL2 - * Details about the YM3812 and OPL chips can be found at http://www.shikadi.net/moddingwiki/OPL_chip + * Details about the YM3812 and YMF262 chips can be found at http://www.shikadi.net/moddingwiki/OPL_chip * * This library is open source and provided as is under the MIT software license, a copy of which is provided as part of * the project's repository. This library makes use of Gordon Henderson's Wiring Pi. + * WWW.CHEERFUL.NL */ @@ -63,7 +65,12 @@ OPL2::OPL2() { /** - * Instantiate the OPL2 library with custom pin setup. + * Instantiate the OPL2 library with custom pin setup. This constructor is left for legacy support. Preferably custom + * pins are specifies when calling begin(). + * + * @param reset - Pin number to use for RESET. + * @param address - Pin number to use for A0. + * @param latch - Pin number to use for LATCH. */ OPL2::OPL2(byte reset, byte address, byte latch) { pinReset = reset; @@ -75,9 +82,10 @@ OPL2::OPL2(byte reset, byte address, byte latch) { /** * Initialize the YM3812. */ -void OPL2::init() { +void OPL2::begin() { #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO SPI.begin(); + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); #else wiringPiSetup(); wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED); @@ -91,29 +99,231 @@ void OPL2::init() { digitalWrite(pinReset, HIGH); digitalWrite(pinAddress, LOW); + createShadowRegisters(); reset(); } /** - * Hard reset the OPL2 chip. This should be done before sending any register data to the chip. + * Initialize the YM3812. This function is deprecated and should be replaced with OPL2.begin(). + */ +void OPL2::init() { + begin(); +} + + +/** + * Create shadow registers to hold the values written to the OPL2 chip for later access. Only those registers that are + * are valid on the YM3812 are created to be as memory friendly as possible for platforms with limited RAM such as the + * Arduino Uno / Nano. Registers consume 120 bytes. + */ +void OPL2::createShadowRegisters() { + chipRegisters = new byte[3]; // 3 + channelRegisters = new byte[3 * numChannels]; // 27 + operatorRegisters = new byte[10 * numChannels]; // 90 +} + + +/** + * Hard reset the OPL2 chip and initialize all registers to 0x00. This should be called before sending any data to the + * chip. */ void OPL2::reset() { + // Hard reset the OPL2. digitalWrite(pinReset, LOW); delay(1); digitalWrite(pinReset, HIGH); - for(int i = 0; i < 256; i ++) { - oplRegisters[i] = 0x00; - write(i, 0x00); + // Initialize chip registers. + setChipRegister(0x00, 0x00); + setChipRegister(0x08, 0x40); + setChipRegister(0xBD, 0x00); + + // Initialize all channel and operator registers. + for (byte i = 0; i < getNumChannels(); i ++) { + setChannelRegister(0xA0, i, 0x00); + setChannelRegister(0xB0, i, 0x00); + setChannelRegister(0xC0, i, 0x00); + + for (byte j = OPERATOR1; j <= OPERATOR2; j ++) { + setOperatorRegister(0x20, i, j, 0x00); + setOperatorRegister(0x40, i, j, 0x3F); + setOperatorRegister(0x60, i, j, 0x00); + setOperatorRegister(0x80, i, j, 0x00); + setOperatorRegister(0xE0, i, j, 0x00); + } } } /** - * Send the given byte of data to the given register of the OPL2 chip. + * Get the current value of a chip wide register from the shadow registers. + * + * @param reg - The 9-bit address of the register. + * @return The value of the register from shadow registers. + */ +byte OPL2::getChipRegister(short reg) { + return chipRegisters[getChipRegisterOffset(reg)]; +} + + +/** + * Write a given value to a chip wide register. + * + * @param reg - The 9-bit register to write to. + * @param value - The value to write to the register. + */ +void OPL2::setChipRegister(short reg, byte value) { + chipRegisters[getChipRegisterOffset(reg)] = value; + write(reg & 0xFF, value); +} + + +/** + * Get the internal register offset for a chip wide register. + * + * @param reg - The 9-bit register for which we want to know the internal offset. + * @return The offset to the internal shadow register or 0 if an illegal chip register was requested. + */ +byte OPL2::getChipRegisterOffset(short reg) { + switch (reg & 0xFF) { + case 0x08: + return 1; + case 0xBD: + return 2; + case 0x01: + default: + return 0; + } +} + + +/** + * Get the value of a channel register. + * + * @param baseAddress - The base address of the register. + * @param channel - The channel for which to get the register value [0, 8]. + * @return The current value of the from the shadow register. + */ +byte OPL2::getChannelRegister(byte baseRegister, byte channel) { + return channelRegisters[getChannelRegisterOffset(baseRegister, channel)]; +} + + +/** + * Write a given value to a channel based register. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel to address [0, 8]. + * @param value - The value to write to the register. + */ +void OPL2::setChannelRegister(byte baseRegister, byte channel, byte value) { + channelRegisters[getChannelRegisterOffset(baseRegister, channel)] = value; + byte reg = baseRegister + (channel % CHANNELS_PER_BANK); + write(reg, value); +} + + +/** + * Get the internal offset of a channel register. + * + * @param baseRegister - The base register where we want to know the offset of. + * @param channel - The channel [0, numChannels] for which we want to know the offset. + * @return The internal offset of the channel register or 0 if the baseRegister is invalid. + */ +byte OPL2::getChannelRegisterOffset(byte baseRegister, byte channel) { + channel = channel % getNumChannels(); + byte offset = channel * 3; + + switch (baseRegister) { + case 0xB0: + return offset + 1; + case 0xC0: + return offset + 2; + case 0xA0: + default: + return offset; + } +} + + +/** + * Get the current value of an operator register of a channel from the shadow registers. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel of the operatpr [0, 17]. + * @param op - The operator [0, 1]. + * @return The operator register value from shadow registers. + */ +byte OPL2::getOperatorRegister(byte baseRegister, byte channel, byte operatorNum) { + return operatorRegisters[getOperatorRegisterOffset(baseRegister, channel, operatorNum)]; +} + + +/** + * Write a given value to an operator register for a channel. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel of the operator [0, 8] + * @param operatorNum - The operator to change [0, 1]. + * @param value - The value to write to the operator's register. + */ +void OPL2::setOperatorRegister(byte baseRegister, byte channel, byte operatorNum, byte value) { + operatorRegisters[getOperatorRegisterOffset(baseRegister, channel, operatorNum)] = value; + byte reg = baseRegister + getRegisterOffset(channel, operatorNum); + write(reg, value); +} + + +/** + * Get the internal offset of an operator register. + * + * @param baseRegister - The base register where we want to know the offset of. + * @param channel - The channel [0, numChannels] to get the offset to. + * @param operatorNum - The operator [0, 1] to get the offset to. + * @return The internal offset of the operator register or 0 if the baseRegister is invalid. + */ +short OPL2::getOperatorRegisterOffset(byte baseRegister, byte channel, byte operatorNum) { + channel = channel % getNumChannels(); + operatorNum = operatorNum & 0x01; + short offset = (channel * 10) + (operatorNum * 5); + + switch (baseRegister) { + case 0x40: + return offset + 1; + case 0x60: + return offset + 2; + case 0x80: + return offset + 3; + case 0xE0: + return offset + 4; + case 0x20: + default: + return offset; + } +} + + +/** + * Get the offset from a base register to a channel operator register. + * + * @param channel - The channel for which to get the offset [0, 8]. + * @param operatorNum - The operator for which to get the offset [0, 1]. + * @return The offset from the base register to the operator register. + */ +byte OPL2::getRegisterOffset(byte channel, byte operatorNum) { + return registerOffsets[operatorNum % 2][channel % CHANNELS_PER_BANK]; +} + + +/** + * Write the given value to an OPL2 register. This does not update the internal shadow register! + * + * @param reg - The register to change. + * @param value - The value to write to the register. */ -void OPL2::write(byte reg, byte data) { +void OPL2::write(byte reg, byte value) { + // Write OPL2 address. digitalWrite(pinAddress, LOW); #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO SPI.transfer(reg); @@ -121,48 +331,29 @@ void OPL2::write(byte reg, byte data) { wiringPiSPIDataRW(SPI_CHANNEL, ®, 1); #endif digitalWrite(pinLatch, LOW); - delayMicroseconds(1); + delayMicroseconds(16); digitalWrite(pinLatch, HIGH); - delayMicroseconds(4); + delayMicroseconds(16); + // Write OPL2 data. digitalWrite(pinAddress, HIGH); #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO - SPI.transfer(data); + SPI.transfer(value); #else - wiringPiSPIDataRW(SPI_CHANNEL, &data, 1); + wiringPiSPIDataRW(SPI_CHANNEL, &value, 1); #endif digitalWrite(pinLatch, LOW); - delayMicroseconds(1); + delayMicroseconds(4); digitalWrite(pinLatch, HIGH); - delayMicroseconds(23); -} - - -/** - * Get the current value of the given register. - */ -byte OPL2::getRegister(byte reg) { - return oplRegisters[reg]; + delayMicroseconds(92); } /** - * Sets the given register to the given value. + * Return the number of channels for this OPL2. */ -byte OPL2::setRegister(byte reg, byte value) { - oplRegisters[reg] = value; - write(reg, value); - return reg; -} - - -/** - * Calculate register offet based on channel and operator. - */ -byte OPL2::getRegisterOffset(byte channel, byte operatorNum) { - channel = max(ZERO, min(channel, CHANNEL_MAX)); - operatorNum = max(ZERO, min(operatorNum, ONE)); - return registerOffsets[operatorNum][channel]; +byte OPL2::getNumChannels() { + return numChannels; } @@ -172,7 +363,7 @@ byte OPL2::getRegisterOffset(byte channel, byte operatorNum) { */ short OPL2::getFrequencyFNumber(byte channel, float frequency) { float fInterval = getFrequencyStep(channel); - return max(F_NUM_MIN, min((short)(frequency / fInterval), F_NUM_MAX)); + return max((short)0, min((short)(frequency / fInterval), (short)1023)); } @@ -180,7 +371,7 @@ short OPL2::getFrequencyFNumber(byte channel, float frequency) { * Get the F-Number for the given note. In this case the block is assumed to be the octave. */ short OPL2::getNoteFNumber(byte note) { - return noteFNumbers[max(ZERO, min(note, NOTE_MAX))]; + return noteFNumbers[note % NUM_NOTES]; } /** @@ -225,6 +416,7 @@ Instrument OPL2::createInstrument() { instrument.operators[op].waveForm = 0; } + instrument.transpose = 0; instrument.feedback = 0; instrument.isAdditiveSynth = false; instrument.type = INSTRUMENT_TYPE_MELODIC; @@ -268,9 +460,10 @@ Instrument OPL2::createInstrument() { instrument.operators[op].decay = data[op * 6 + 3] & 0x0F; instrument.operators[op].sustain = (data[op * 6 + 4] & 0xF0) >> 4; instrument.operators[op].release = data[op * 6 + 4] & 0x0F; - instrument.operators[op].waveForm = data[op * 6 + 5] & 0x03; + instrument.operators[op].waveForm = data[op * 6 + 5] & 0x07; } + instrument.transpose = 0; instrument.feedback = (data[6] & 0x0E) >> 1; instrument.isAdditiveSynth = data[6] & 0x01 ? true : false; instrument.type = data[0]; @@ -300,8 +493,9 @@ Instrument OPL2::getInstrument(byte channel) { instrument.operators[op].waveForm = getWaveForm(channel, op); } + instrument.transpose = 0; instrument.feedback = getFeedback(channel); - instrument.isAdditiveSynth = getSynthMode(channel); + instrument.isAdditiveSynth = getSynthMode(channel) == SYNTH_MODE_AM; instrument.type = INSTRUMENT_TYPE_MELODIC; return instrument; @@ -333,8 +527,9 @@ Instrument OPL2::getDrumInstrument(byte drumType) { } } + instrument.transpose = 0; instrument.feedback = getFeedback(channel); - instrument.isAdditiveSynth = getSynthMode(channel); + instrument.isAdditiveSynth = getSynthMode(channel) == SYNTH_MODE_AM; instrument.type = drumType; return instrument; @@ -346,34 +541,34 @@ Instrument OPL2::getDrumInstrument(byte drumType) { * operators. */ void OPL2::setInstrument(byte channel, Instrument instrument, float volume) { - channel = max(ZERO, min(channel, CHANNEL_MAX)); - volume = max(VOLUME_MIN, min(volume, VOLUME_MAX)); + volume = max((float)0.0, min(volume, (float)1.0)); setWaveFormSelect(true); for (byte op = OPERATOR1; op <= OPERATOR2; op ++) { byte outputLevel = 63 - (byte)((63.0 - (float)instrument.operators[op].outputLevel) * volume); - byte registerOffset = registerOffsets[op][channel]; - write(0x20 + registerOffset, + setOperatorRegister(0x20, channel, op, (instrument.operators[op].hasTremolo ? 0x80 : 0x00) + (instrument.operators[op].hasVibrato ? 0x40 : 0x00) + (instrument.operators[op].hasSustain ? 0x20 : 0x00) + (instrument.operators[op].hasEnvelopeScaling ? 0x10 : 0x00) + (instrument.operators[op].frequencyMultiplier & 0x0F)); - write(0x40 + registerOffset, + setOperatorRegister(0x40, channel, op, ((instrument.operators[op].keyScaleLevel & 0x03) << 6) + (outputLevel & 0x3F)); - write(0x60 + registerOffset, + setOperatorRegister(0x60, channel, op, ((instrument.operators[op].attack & 0x0F) << 4) + (instrument.operators[op].decay & 0x0F)); - write(0x80 + registerOffset, + setOperatorRegister(0x80, channel, op, ((instrument.operators[op].sustain & 0x0F) << 4) + (instrument.operators[op].release & 0x0F)); - write(0xE0 + registerOffset, - (instrument.operators[op].waveForm & 0x03)); + setOperatorRegister(0xE0, channel, op, + (instrument.operators[op].waveForm & 0x07)); } - write(0xC0 + channel, + byte value = getChannelRegister(0xC0, channel) & 0xF0; + setChannelRegister(0xC0, channel, + value + ((instrument.feedback & 0x07) << 1) + (instrument.isAdditiveSynth ? 0x01 : 0x00)); } @@ -385,7 +580,8 @@ void OPL2::setInstrument(byte channel, Instrument instrument, float volume) { * proper output levels for the operator(s). */ void OPL2::setDrumInstrument(Instrument instrument, float volume) { - volume = max(VOLUME_MIN, min(volume, VOLUME_MAX)); + volume = max((float)0.0, min(volume, (float)1.0)); + byte channel = drumChannels[instrument.type - INSTRUMENT_TYPE_BASS]; setWaveFormSelect(true); for (byte op = OPERATOR1; op <= OPERATOR2; op ++) { @@ -393,119 +589,41 @@ void OPL2::setDrumInstrument(Instrument instrument, float volume) { byte registerOffset = drumRegisterOffsets[op][instrument.type - INSTRUMENT_TYPE_BASS]; if (registerOffset != 0xFF) { - write(0x20 + registerOffset, + setOperatorRegister(0x20, channel, op, (instrument.operators[op].hasTremolo ? 0x80 : 0x00) + (instrument.operators[op].hasVibrato ? 0x40 : 0x00) + (instrument.operators[op].hasSustain ? 0x20 : 0x00) + (instrument.operators[op].hasEnvelopeScaling ? 0x10 : 0x00) + (instrument.operators[op].frequencyMultiplier & 0x0F)); - write(0x40 + registerOffset, + setOperatorRegister(0x40, channel, op, ((instrument.operators[op].keyScaleLevel & 0x03) << 6) + (outputLevel & 0x3F)); - write(0x60 + registerOffset, + setOperatorRegister(0x60, channel, op, ((instrument.operators[op].attack & 0x0F) << 4) + (instrument.operators[op].decay & 0x0F)); - write(0x80 + registerOffset, + setOperatorRegister(0x80, channel, op, ((instrument.operators[op].sustain & 0x0F) << 4) + (instrument.operators[op].release & 0x0F)); - write(0xE0 + registerOffset, + setOperatorRegister(0xE0, channel, op, (instrument.operators[op].waveForm & 0x03)); } } - write(0xC0 + drumChannels[instrument.type - INSTRUMENT_TYPE_BASS], + byte value = getChannelRegister(0xC0, channel) & 0xF0; + setChannelRegister(0xC0, channel, + value + ((instrument.feedback & 0x07) << 1) + (instrument.isAdditiveSynth ? 0x01 : 0x00)); } -/** - * WARNING! - * As of v1.5.0 of the OPL2 library this function is deprecated and will be removed in v1.6.0. Please use the newly - * provided instrument object and createInstrument / loadInstrument / setInstrument functions. - * - * Load an instrument and apply it to the given channel. If the instrument to be loaded is a percussive instrument then - * the channel will depend on the type of drum and the channel parameter will be ignored. - * See instruments.h for instrument definition format. - */ -void OPL2::setInstrument(byte channel, const unsigned char *instrument) { - #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO - unsigned char percussionChannel = pgm_read_byte_near(instrument); - #else - unsigned char percussionChannel = instrument[0]; - #endif - - setWaveFormSelect(true); - switch (percussionChannel) { - case 6: // Base drum... - for (byte i = 0; i < 5; i ++) { - setRegister( - instrumentBaseRegs[i] + drumOffsets[0], - #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO - pgm_read_byte_near(instrument + i + 1) - #else - instrument[i + 1] - #endif - ); - setRegister( - instrumentBaseRegs[i] + drumOffsets[1], - #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO - pgm_read_byte_near(instrument + i + 1) - #else - instrument[i + 1] - #endif - ); - } - break; - - case 7: // Snare drum... - case 8: // Tom tom... - case 9: // Top cymbal... - case 10: // Hi hat... - for (byte i = 0; i < 5; i ++) { - setRegister( - instrumentBaseRegs[i] + drumOffsets[percussionChannel - 5], - #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO - pgm_read_byte_near(instrument + i + 1) - #else - instrument[i + 1] - #endif - ); - } - break; - - default: // Melodic instruments... - for (byte i = 0; i < 11; i ++) { - byte reg; - if (i == 5) { - //Channel parameters C0..C8 - reg = 0xC0 + max(ZERO, min(channel, CHANNEL_MAX)); - } else { - //Operator parameters 20..35, 40..55, 60..75, 80..95, E0..F5 - reg = instrumentBaseRegs[i % 6] + getRegisterOffset(channel, i > 5); - } - - setRegister( - reg, - #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO - pgm_read_byte_near(instrument + i + 1) - #else - instrument[i + 1] - #endif - ); - } - break; - } -} - - /** * Play a note of a certain octave on the given channel. */ void OPL2::playNote(byte channel, byte octave, byte note) { setKeyOn(channel, false); - setBlock(channel, max(ZERO, min(octave, OCTAVE_MAX))); - setFNumber(channel, noteFNumbers[max(ZERO, min(note, NOTE_MAX))]); + setBlock(channel, min(octave, (byte)NUM_OCTAVES)); + setFNumber(channel, noteFNumbers[note % 12]); setKeyOn(channel, true); } @@ -517,13 +635,13 @@ void OPL2::playNote(byte channel, byte octave, byte note) { * single operator (Snare + Hi-hat and Tom + Cymbal). */ void OPL2::playDrum(byte drum, byte octave, byte note) { - drum = drum % DRUM_SOUND_MAX; + drum = drum % NUM_DRUM_SOUNDS; byte drumState = getDrums(); setDrums(drumState & ~drumBits[drum]); - byte drumChannel = drumChannels[drum % DRUM_SOUND_MAX]; - setBlock(drumChannel, max(ZERO, min(octave, OCTAVE_MAX))); - setFNumber(drumChannel, noteFNumbers[max(ZERO, min(note, NOTE_MAX))]); + byte drumChannel = drumChannels[drum]; + setBlock(drumChannel, min(octave, (byte)NUM_OCTAVES)); + setFNumber(drumChannel, noteFNumbers[note % NUM_NOTES]); setDrums(drumState | drumBits[drum]); } @@ -532,18 +650,18 @@ void OPL2::playDrum(byte drum, byte octave, byte note) { * Is wave form selection currently enabled. */ bool OPL2::getWaveFormSelect() { - return oplRegisters[0x01] & 0x20; + return getChipRegister(0x01) & 0x20; } /** * Enable wave form selection for each operator. */ -byte OPL2::setWaveFormSelect(bool enable) { +void OPL2::setWaveFormSelect(bool enable) { if (enable) { - return setRegister(0x01, oplRegisters[0x01] | 0x20); + setChipRegister(0x01, getChipRegister(0x01) | 0x20); } else { - return setRegister(0x01, oplRegisters[0x01] & 0xDF); + setChipRegister(0x01, getChipRegister(0x01) & 0xDF); } } @@ -552,7 +670,7 @@ byte OPL2::setWaveFormSelect(bool enable) { * Is amplitude modulation enabled for the given operator? */ bool OPL2::getTremolo(byte channel, byte operatorNum) { - return oplRegisters[0x20 + getRegisterOffset(channel, operatorNum)] & 0x80; + return getOperatorRegister(0x20, channel, operatorNum) & 0x80; } @@ -560,13 +678,9 @@ bool OPL2::getTremolo(byte channel, byte operatorNum) { * Apply amplitude modulation when set to true. Modulation depth is controlled globaly by the AM-depth flag in the 0xBD * register. */ -byte OPL2::setTremolo(byte channel, byte operatorNum, bool enable) { - byte reg = 0x20 + getRegisterOffset(channel, operatorNum); - if (enable) { - return setRegister(reg, oplRegisters[reg] | 0x80); - } else { - return setRegister(reg, oplRegisters[reg] & 0x7F); - } +void OPL2::setTremolo(byte channel, byte operatorNum, bool enable) { + byte value = getOperatorRegister(0x20, channel, operatorNum) & 0x7F; + setOperatorRegister(0x20, channel, operatorNum, value + (enable ? 0x80 : 0x00)); } @@ -574,20 +688,16 @@ byte OPL2::setTremolo(byte channel, byte operatorNum, bool enable) { * Is vibrator enabled for the given channel? */ bool OPL2::getVibrato(byte channel, byte operatorNum) { - return oplRegisters[0x20 + getRegisterOffset(channel, operatorNum)] & 0x40; + return getOperatorRegister(0x20, channel, operatorNum) & 0x40; } /** * Apply vibrato when set to true. Vibrato depth is controlled globally by the VIB-depth flag in the 0xBD register. */ -byte OPL2::setVibrato(byte channel, byte operatorNum, bool enable) { - byte reg = 0x20 + getRegisterOffset(channel, operatorNum); - if (enable) { - return setRegister(reg, oplRegisters[reg] | 0x40); - } else { - return setRegister(reg, oplRegisters[reg] & 0xBF); - } +void OPL2::setVibrato(byte channel, byte operatorNum, bool enable) { + byte value = getOperatorRegister(0x20, channel, operatorNum) & 0xBF; + setOperatorRegister(0x20, channel, operatorNum, value + (enable ? 0x40 : 0x00)); } @@ -595,7 +705,7 @@ byte OPL2::setVibrato(byte channel, byte operatorNum, bool enable) { * Is sustain being maintained for the given channel? */ bool OPL2::getMaintainSustain(byte channel, byte operatorNum) { - return oplRegisters[0x20 + getRegisterOffset(channel, operatorNum)] & 0x20; + return getOperatorRegister(0x20, channel, operatorNum) & 0x20; } @@ -603,13 +713,9 @@ bool OPL2::getMaintainSustain(byte channel, byte operatorNum) { * When set to true the sustain level of the voice is maintained until released. When false the sound begins to decay * immediately after hitting the sustain phase. */ -byte OPL2::setMaintainSustain(byte channel, byte operatorNum, bool enable) { - byte reg = 0x20 + getRegisterOffset(channel, operatorNum); - if (enable) { - return setRegister(reg, oplRegisters[reg] | 0x20); - } else { - return setRegister(reg, oplRegisters[reg] & 0xDF); - } +void OPL2::setMaintainSustain(byte channel, byte operatorNum, bool enable) { + byte value = getOperatorRegister(0x20, channel, operatorNum) & 0xDF; + setOperatorRegister(0x20, channel, operatorNum, value + (enable ? 0x20 : 0x00)); } @@ -617,21 +723,16 @@ byte OPL2::setMaintainSustain(byte channel, byte operatorNum, bool enable) { * Is envelope scaling being applied to the given channel? */ bool OPL2::getEnvelopeScaling(byte channel, byte operatorNum) { - return oplRegisters[0x20 + getRegisterOffset(channel, operatorNum)] & 0x10; + return getOperatorRegister(0x20, channel, operatorNum) & 0x10; } /** * Enable or disable envelope scaling. When set to true higher notes will be shorter than lower ones. */ -byte OPL2::setEnvelopeScaling(byte channel, byte operatorNum, bool enable) { - byte reg = 0x20 + getRegisterOffset(channel, operatorNum); - if (enable) { - return setRegister(reg, oplRegisters[reg] | 0x10); - } else { - return setRegister(reg, oplRegisters[reg] & 0xEF); - } - return reg; +void OPL2::setEnvelopeScaling(byte channel, byte operatorNum, bool enable) { + byte value = getOperatorRegister(0x20, channel, operatorNum) & 0xEF; + setOperatorRegister(0x20, channel, operatorNum, value + (enable ? 0x10 : 0x00)); } @@ -639,16 +740,16 @@ byte OPL2::setEnvelopeScaling(byte channel, byte operatorNum, bool enable) { * Get the frequency multiplier for the given channel. */ byte OPL2::getMultiplier(byte channel, byte operatorNum) { - return oplRegisters[0x20 + getRegisterOffset(channel, operatorNum)] & 0x0F; + return getOperatorRegister(0x20, channel, operatorNum) & 0x0F; } /** * Set frequency multiplier for the given channel. Note that a multiplier of 0 will apply a 0.5 multiplication. */ -byte OPL2::setMultiplier(byte channel, byte operatorNum, byte multiplier) { - byte reg = 0x20 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0xF0) | (multiplier & 0x0F)); +void OPL2::setMultiplier(byte channel, byte operatorNum, byte multiplier) { + byte value = getOperatorRegister(0x20, channel, operatorNum) & 0xF0; + setOperatorRegister(0x20, channel, operatorNum, value + (multiplier & 0x0F)); } @@ -656,7 +757,7 @@ byte OPL2::setMultiplier(byte channel, byte operatorNum, byte multiplier) { * Get the scaling level for the given channel. */ byte OPL2::getScalingLevel(byte channel, byte operatorNum) { - return (oplRegisters[0x40 + getRegisterOffset(channel, operatorNum)] & 0xC0) >> 6; + return (getOperatorRegister(0x40, channel, operatorNum) & 0xC0) >> 6; } @@ -667,27 +768,47 @@ byte OPL2::getScalingLevel(byte channel, byte operatorNum) { * 10 - 3.0 dB/oct * 11 - 6.0 dB/oct */ -byte OPL2::setScalingLevel(byte channel, byte operatorNum, byte scaling) { - byte reg = 0x40 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0x3F) | ((scaling & 0x03) << 6)); +void OPL2::setScalingLevel(byte channel, byte operatorNum, byte scaling) { + byte value = getOperatorRegister(0x40, channel, operatorNum) & 0x3F; + setOperatorRegister(0x40, channel, operatorNum, value + ((scaling & 0x03) << 6)); } /** - * Get the volume of the given channel. 0x00 is laudest, 0x3F is softest. + * Get the volume of the given channel operator. 0x00 is laudest, 0x3F is softest. */ byte OPL2::getVolume(byte channel, byte operatorNum) { - return oplRegisters[0x40 + getRegisterOffset(channel, operatorNum)] & 0x3F; + return getOperatorRegister(0x40, channel, operatorNum) & 0x3F; } /** - * Set the volume of the channel. + * Set the volume of the channel operator. * Note that the scale is inverted! 0x00 for loudest, 0x3F for softest. */ -byte OPL2::setVolume(byte channel, byte operatorNum, byte volume) { - byte reg = 0x40 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0xC0) | (volume & 0x3F)); +void OPL2::setVolume(byte channel, byte operatorNum, byte volume) { + byte value = getOperatorRegister(0x40, channel, operatorNum) & 0xC0; + setOperatorRegister(0x40, channel, operatorNum, value + (volume & 0x3F)); +} + + +/** + * Get the volume of the given channel. + */ +byte OPL2::getChannelVolume(byte channel) { + return getVolume(channel, OPERATOR2); +} + + +/** + * Set the volume for the given channel. Depending on the current synthesis mode this will affect both operators (AM) or + * only operator 2 (FM). + */ +void OPL2::setChannelVolume(byte channel, byte volume) { + if (getSynthMode(channel)) { + setVolume(channel, OPERATOR1, volume); + } + setVolume(channel, OPERATOR2, volume); } @@ -695,16 +816,16 @@ byte OPL2::setVolume(byte channel, byte operatorNum, byte volume) { * Get the attack rate of the given channel. */ byte OPL2::getAttack(byte channel, byte operatorNum) { - return (oplRegisters[0x60 + getRegisterOffset(channel, operatorNum)] & 0xF0) >> 4; + return (getOperatorRegister(0x60, channel, operatorNum) & 0xF0) >> 4; } /** * Attack rate. 0x00 is slowest, 0x0F is fastest. */ -byte OPL2::setAttack(byte channel, byte operatorNum, byte attack) { - byte reg = 0x60 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0x0F) | ((attack & 0x0F) << 4)); +void OPL2::setAttack(byte channel, byte operatorNum, byte attack) { + byte value = getOperatorRegister(0x60, channel, operatorNum) & 0x0F; + setOperatorRegister(0x60, channel, operatorNum, value + ((attack & 0x0F) << 4)); } @@ -712,16 +833,16 @@ byte OPL2::setAttack(byte channel, byte operatorNum, byte attack) { * Get the decay rate of the given channel. */ byte OPL2::getDecay(byte channel, byte operatorNum) { - return oplRegisters[0x60 + getRegisterOffset(channel, operatorNum)] & 0x0F; + return getOperatorRegister(0x60, channel, operatorNum) & 0x0F; } /** * Decay rate. 0x00 is slowest, 0x0F is fastest. */ -byte OPL2::setDecay(byte channel, byte operatorNum, byte decay) { - byte reg = 0x60 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0xF0) | (decay & 0x0F)); +void OPL2::setDecay(byte channel, byte operatorNum, byte decay) { + byte value = getOperatorRegister(0x60, channel, operatorNum) & 0xF0; + setOperatorRegister(0x60, channel, operatorNum, value + (decay & 0x0F)); } @@ -729,16 +850,16 @@ byte OPL2::setDecay(byte channel, byte operatorNum, byte decay) { * Get the sustain level of the given channel. 0x00 is laudest, 0x0F is softest. */ byte OPL2::getSustain(byte channel, byte operatorNum) { - return (oplRegisters[0x80 + getRegisterOffset(channel, operatorNum)] & 0xF0) >> 4; + return (getOperatorRegister(0x80, channel, operatorNum) & 0xF0) >> 4; } /** * Sustain level. 0x00 is laudest, 0x0F is softest. */ -byte OPL2::setSustain(byte channel, byte operatorNum, byte sustain) { - byte reg = 0x80 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0x0F) | ((sustain & 0x0F) << 4)); +void OPL2::setSustain(byte channel, byte operatorNum, byte sustain) { + byte value = getOperatorRegister(0x80, channel, operatorNum) & 0x0F; + setOperatorRegister(0x80, channel, operatorNum, value + ((sustain & 0x0F) << 4)); } @@ -746,16 +867,16 @@ byte OPL2::setSustain(byte channel, byte operatorNum, byte sustain) { * Get the release rate of the given channel. */ byte OPL2::getRelease(byte channel, byte operatorNum) { - return oplRegisters[0x80 + getRegisterOffset(channel, operatorNum)] & 0x0F; + return getOperatorRegister(0x80, channel, operatorNum) & 0x0F; } /** * Release rate. 0x00 is flowest, 0x0F is fastest. */ -byte OPL2::setRelease(byte channel, byte operatorNum, byte release) { - byte reg = 0x80 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0xF0) | (release & 0x0F)); +void OPL2::setRelease(byte channel, byte operatorNum, byte release) { + byte value = getOperatorRegister(0x80, channel, operatorNum) & 0xF0; + setOperatorRegister(0x80, channel, operatorNum, value + (release & 0x0F)); } @@ -763,19 +884,19 @@ byte OPL2::setRelease(byte channel, byte operatorNum, byte release) { * Get the frequenct F-number of the given channel. */ short OPL2::getFNumber(byte channel) { - byte offset = max(ZERO, min(channel, CHANNEL_MAX)); - return ((oplRegisters[0xB0 + offset] & 0x03) << 8) + oplRegisters[0xA0 + offset]; + short value = (getChannelRegister(0xB0, channel) & 0x03) << 8; + value += getChannelRegister(0xA0, channel); + return value; } /** * Set frequency F-number [0, 1023] for the given channel. */ -byte OPL2::setFNumber(byte channel, short fNumber) { - byte reg = 0xA0 + max(ZERO, min(channel, CHANNEL_MAX)); - setRegister(reg, fNumber & 0x00FF); - setRegister(reg + 0x10, (oplRegisters[reg + 0x10] & 0xFC) | ((fNumber & 0x0300) >> 8)); - return reg; +void OPL2::setFNumber(byte channel, short fNumber) { + byte value = getChannelRegister(0xB0, channel) & 0xFC; + setChannelRegister(0xB0, channel, value + ((fNumber & 0x0300) >> 8)); + setChannelRegister(0xA0, channel, fNumber & 0xFF); } @@ -791,13 +912,13 @@ float OPL2::getFrequency(byte channel) { /** * Set the frequenct of the given channel and if needed switch to a different block. */ -byte OPL2::setFrequency(byte channel, float frequency) { +void OPL2::setFrequency(byte channel, float frequency) { unsigned char block = getFrequencyBlock(frequency); if (getBlock(channel) != block) { setBlock(channel, block); } short fNumber = getFrequencyFNumber(channel, frequency); - return setFNumber(channel, fNumber); + setFNumber(channel, fNumber); } @@ -805,8 +926,7 @@ byte OPL2::setFrequency(byte channel, float frequency) { * Get the frequency block of the given channel. */ byte OPL2::getBlock(byte channel) { - byte offset = max(ZERO, min(channel, CHANNEL_MAX)); - return (oplRegisters[0xB0 + offset] & 0x1C) >> 2; + return (getChannelRegister(0xB0, channel) & 0x1C) >> 2; } @@ -821,9 +941,28 @@ byte OPL2::getBlock(byte channel) { * 6 - 3.034 Hz, Range: 3.034 Hz -> 3104.215 Hz * 7 - 6.069 Hz, Range: 6.068 Hz -> 6208.431 Hz */ -byte OPL2::setBlock(byte channel, byte block) { - byte reg = 0xB0 + max(ZERO, min(channel, CHANNEL_MAX)); - return setRegister(reg, (oplRegisters[reg] & 0xE3) | ((block & 0x07) << 2)); +void OPL2::setBlock(byte channel, byte block) { + byte value = getChannelRegister(0xB0, channel) & 0xE3; + setChannelRegister(0xB0, channel, value + ((block & 0x07) << 2)); +} + + +/** + * Get the octave split bit. + */ +bool OPL2::getNoteSelect() { + return getChipRegister(0x08) & 0x40; +} + + +/** + * Set the octave split bit. This sets how the chip interprets F-numbers to determine where an octave is split. For note + * F-numbers used by the OPL2 library this bit should be set. + * + * @param enable - Sets the note select bit when true, otherwise reset it. + */ +void OPL2::setNoteSelect(bool enable) { + setChipRegister(0x08, enable ? 0x40 : 0x00); } @@ -831,21 +970,16 @@ byte OPL2::setBlock(byte channel, byte block) { * Is the voice of the given channel currently enabled? */ bool OPL2::getKeyOn(byte channel) { - byte offset = max(ZERO, min(channel, CHANNEL_MAX)); - return oplRegisters[0xB0 + offset] & 0x20; + return getChannelRegister(0xB0, channel) & 0x20; } /** * Enable voice on channel. */ -byte OPL2::setKeyOn(byte channel, bool keyOn) { - byte reg = 0xB0 + max(ZERO, min(channel, CHANNEL_MAX)); - if (keyOn) { - return setRegister(reg, oplRegisters[reg] | 0x20); - } else { - return setRegister(reg, oplRegisters[reg] & 0xDF); - } +void OPL2::setKeyOn(byte channel, bool keyOn) { + byte value = getChannelRegister(0xB0, channel) & 0xDF; + setChannelRegister(0xB0, channel, value + (keyOn ? 0x20 : 0x00)); } @@ -853,40 +987,33 @@ byte OPL2::setKeyOn(byte channel, bool keyOn) { * Get the feedback strength of the given channel. */ byte OPL2::getFeedback(byte channel) { - byte offset = max(ZERO, min(channel, CHANNEL_MAX)); - return (oplRegisters[0xC0 + offset] & 0xE0) >> 1; + return (getChannelRegister(0xC0, channel) & 0x0E) >> 1; } /** * Set feedback strength. 0x00 is no feedback, 0x07 is strongest. */ -byte OPL2::setFeedback(byte channel, byte feedback) { - byte reg = 0xC0 + max(ZERO, min(channel, CHANNEL_MAX)); - return setRegister(reg, (oplRegisters[reg] & 0x01) | ((feedback & 0x07) << 1)); +void OPL2::setFeedback(byte channel, byte feedback) { + byte value = getChannelRegister(0xC0, channel) & 0xF1; + setChannelRegister(0xC0, channel, value + ((feedback & 0x07) << 1)); } /** - * Is the decay algorythm enabled for the given channel? + * Get the synth model that is used for the given channel. */ -bool OPL2::getSynthMode(byte channel) { - byte offset = max(ZERO, min(channel, CHANNEL_MAX)); - return oplRegisters[0xC0 + offset] & 0x01; +byte OPL2::getSynthMode(byte channel) { + return getChannelRegister(0xC0, channel) & 0x01; } /** - * Set decay algorithm. When false operator 1 modulates operator 2 (operator 2 is the only one to produce sounde). If - * set to true both operator 1 and operator 2 will produce sound. + * Set the synthesizer mode of the given channel. */ -byte OPL2::setSynthMode(byte channel, bool isAdditive) { - byte reg = 0xC0 + max(ZERO, min(channel, CHANNEL_MAX)); - if (isAdditive) { - return setRegister(reg, oplRegisters[reg] | 0x01); - } else { - return setRegister(reg, oplRegisters[reg] & 0xFE); - } +void OPL2::setSynthMode(byte channel, byte synthMode) { + byte value = getChannelRegister(0xC0, channel) & 0xFE; + setChannelRegister(0xC0, channel, value + (synthMode & 0x01)); } @@ -894,19 +1021,16 @@ byte OPL2::setSynthMode(byte channel, bool isAdditive) { * Is deeper amplitude modulation enabled? */ bool OPL2::getDeepTremolo() { - return oplRegisters[0xBD] & 0x80; + return getChipRegister(0xBD) & 0x80; } /** * Set deeper aplitude modulation depth. When false modulation depth is 1.0 dB, when true modulation depth is 4.8 dB. */ -byte OPL2::setDeepTremolo(bool enable) { - if (enable) { - return setRegister(0xBD, oplRegisters[0xBD] | 0x80); - } else { - return setRegister(0xBD, oplRegisters[0xBD] & 0x7F); - } +void OPL2::setDeepTremolo(bool enable) { + byte value = getChipRegister(0xBD) & 0x7F; + setChipRegister(0xBD, value + (enable ? 0x80 : 0x00)); } @@ -914,19 +1038,16 @@ byte OPL2::setDeepTremolo(bool enable) { * Is deeper vibrato depth enabled? */ bool OPL2::getDeepVibrato() { - return oplRegisters[0xBD] & 0x40; + return getChipRegister(0xBD) & 0x40; } /** * Set deeper vibrato depth. When false vibrato depth is 7/100 semi tone, when true vibrato depth is 14/100. */ -byte OPL2::setDeepVibrato(bool enable) { - if (enable) { - return setRegister(0xBD, oplRegisters[0xBD] | 0x40); - } else { - return setRegister(0xBD, oplRegisters[0xBD] & 0xBF); - } +void OPL2::setDeepVibrato(bool enable) { + byte value = getChipRegister(0xBD) & 0xBF; + setChipRegister(0xBD, value + (enable ? 0x40 : 0x00)); } @@ -934,7 +1055,7 @@ byte OPL2::setDeepVibrato(bool enable) { * Is percussion mode currently enabled? */ bool OPL2::getPercussion() { - return oplRegisters[0xBD] & 0x20; + return getChipRegister(0xBD) & 0x20; } @@ -942,12 +1063,9 @@ bool OPL2::getPercussion() { * Enable or disable percussion mode. When set to false there are 9 melodic voices, when true there are 6 melodic * voices and channels 6 through 8 are used for drum sounds. KeyOn for these channels must be off. */ -byte OPL2::setPercussion(bool enable) { - if (enable) { - return setRegister(0xBD, oplRegisters[0xBD] | 0x20); - } else { - return setRegister(0xBD, oplRegisters[0xBD] & 0xDF); - } +void OPL2::setPercussion(bool enable) { + byte value = getChipRegister(0xBD) & 0xDF; + setChipRegister(0xBD, value + (enable ? 0x20 : 0x00)); } @@ -955,15 +1073,17 @@ byte OPL2::setPercussion(bool enable) { * Return which drum sounds are enabled. */ byte OPL2::getDrums() { - return oplRegisters[0xBD] & 0x1F; + return getChipRegister(0xBD) & 0x1F; } /** * Set the OPL2 drum registers all at once. */ -byte OPL2::setDrums(byte drums) { - return setRegister(0xBD, (oplRegisters[0xBD] & 0xE0) | (drums & 0x1F)); +void OPL2::setDrums(byte drums) { + byte value = getChipRegister(0xBD) & 0xE0; + setChipRegister(0xBD, value); + setChipRegister(0xBD, value + (drums & 0x1F)); } @@ -971,15 +1091,14 @@ byte OPL2::setDrums(byte drums) { * Enable or disable various drum sounds. * Note that keyOn for channels 6, 7 and 8 must be false in order to use rhythms. */ -byte OPL2::setDrums(bool bass, bool snare, bool tom, bool cymbal, bool hihat) { +void OPL2::setDrums(bool bass, bool snare, bool tom, bool cymbal, bool hihat) { byte drums = 0; drums += bass ? DRUM_BITS_BASS : 0x00; drums += snare ? DRUM_BITS_SNARE : 0x00; drums += tom ? DRUM_BITS_TOM : 0x00; drums += cymbal ? DRUM_BITS_CYMBAL : 0x00; drums += hihat ? DRUM_BITS_HI_HAT : 0x00; - setRegister(0xBD, oplRegisters[0xBD] & ~drums); - return setRegister(0xBD, oplRegisters[0xBD] | drums); + setDrums(drums); } @@ -987,14 +1106,14 @@ byte OPL2::setDrums(bool bass, bool snare, bool tom, bool cymbal, bool hihat) { * Get the wave form currently set for the given channel. */ byte OPL2::getWaveForm(byte channel, byte operatorNum) { - return oplRegisters[0xE0 + getRegisterOffset(channel, operatorNum)] & 0x03; + return getOperatorRegister(0xE0, channel, operatorNum) & 0x03; } /** * Select the wave form to use. */ -byte OPL2::setWaveForm(byte channel, byte operatorNum, byte waveForm) { - byte reg = 0xE0 + getRegisterOffset(channel, operatorNum); - return setRegister(reg, (oplRegisters[reg] & 0xFC) | (waveForm & 0x03)); +void OPL2::setWaveForm(byte channel, byte operatorNum, byte waveForm) { + byte value = getOperatorRegister(0xE0, channel, operatorNum) & 0xFC; + setOperatorRegister(0xE0, channel, operatorNum, value + (waveForm & 0x03)); } diff --git a/src/OPL2.h b/src/OPL2.h index 017d9aa..5be9b9e 100644 --- a/src/OPL2.h +++ b/src/OPL2.h @@ -37,8 +37,9 @@ #define SPI_CHANNEL 0 #endif - // General OPL2 definitions. + // Generic OPL2 definitions. #define OPL2_NUM_CHANNELS 9 + #define CHANNELS_PER_BANK 9 // Operator definitions. #define OPERATOR1 0 @@ -47,8 +48,8 @@ #define CARRIER 1 // Synthesis type definitions. - #define FREQ_MODULATION false - #define ADDITIVE_SYNTH true + #define SYNTH_MODE_FM 0 + #define SYNTH_MODE_AM 1 // Drum sounds. #define DRUM_BASS 0 @@ -78,6 +79,11 @@ #define NOTE_AS 10 #define NOTE_B 11 + // Tune specific declarations. + #define NUM_OCTAVES 7 + #define NUM_NOTES 12 + #define NUM_DRUM_SOUNDS 5 + // Instrument data sources (Arduino only). #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO #define INSTRUMENT_DATA_PROGMEM true @@ -124,6 +130,7 @@ byte feedback; bool isAdditiveSynth; byte type; + byte transpose; }; @@ -131,15 +138,31 @@ public: OPL2(); OPL2(byte reset, byte address, byte latch); + virtual void begin(); + virtual void reset(); + virtual void createShadowRegisters(); void init(); - void reset(); - void write(byte reg, byte data); - byte getRegisterOffset(byte channel, byte operatorNum); + + virtual byte getChipRegister(short reg); + virtual byte getChannelRegister(byte baseRegister, byte channel); + virtual byte getOperatorRegister(byte baseRegister, byte channel, byte op); + virtual byte getRegisterOffset(byte channel, byte operatorNum); + virtual void setChipRegister(short reg, byte value); + virtual void setChannelRegister(byte baseRegister, byte channel, byte value); + virtual void setOperatorRegister(byte baseRegister, byte channel, byte op, byte value); + virtual byte getChipRegisterOffset(short reg); + virtual byte getChannelRegisterOffset(byte baseRegister, byte channel); + virtual short getOperatorRegisterOffset(byte baseRegister, byte channel, byte operatorNum); + virtual void write(byte reg, byte data); + + virtual byte getNumChannels(); byte getFrequencyBlock(float frequency); short getFrequencyFNumber(byte channel, float frequency); short getNoteFNumber(byte note); float getFrequencyStep(byte channel); + void playNote(byte channel, byte octave, byte note); + void playDrum(byte drum, byte octave, byte note); Instrument createInstrument(); #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO @@ -151,10 +174,8 @@ Instrument getDrumInstrument(byte drumType); void setInstrument(byte channel, Instrument instrument, float volume = 1.0); void setDrumInstrument(Instrument instrument, float volume = 1.0); - void setInstrument(byte channel, const unsigned char *instrument); - byte getRegister(byte reg); - bool getWaveFormSelect(); + virtual bool getWaveFormSelect(); bool getTremolo(byte channel, byte operatorNum); bool getVibrato(byte channel, byte operatorNum); bool getMaintainSustain(byte channel, byte operatorNum); @@ -162,6 +183,7 @@ byte getMultiplier(byte channel, byte operatorNum); byte getScalingLevel(byte channel, byte operatorNum); byte getVolume(byte channel, byte operatorNum); + byte getChannelVolume(byte channel); byte getAttack(byte channel, byte operatorNum); byte getDecay(byte channel, byte operatorNum); byte getSustain(byte channel, byte operatorNum); @@ -169,48 +191,54 @@ short getFNumber(byte channel); float getFrequency(byte channel); byte getBlock(byte channel); + bool getNoteSelect(); bool getKeyOn(byte channel); byte getFeedback(byte channel); - bool getSynthMode(byte channel); + byte getSynthMode(byte channel); bool getDeepTremolo(); bool getDeepVibrato(); bool getPercussion(); byte getDrums(); byte getWaveForm(byte channel, byte operatorNum); - void playNote(byte channel, byte octave, byte note); - void playDrum(byte drum, byte octave, byte note); - byte setRegister(byte reg, byte value); - byte setWaveFormSelect(bool enable); - byte setTremolo(byte channel, byte operatorNum, bool enable); - byte setVibrato(byte channel, byte operatorNum, bool enable); - byte setMaintainSustain(byte channel, byte operatorNum, bool enable); - byte setEnvelopeScaling(byte channel, byte operatorNum, bool enable); - byte setMultiplier(byte channel, byte operatorNum, byte multiplier); - byte setScalingLevel(byte channel, byte operatorNum, byte scaling); - byte setVolume(byte channel, byte operatorNum, byte volume); - byte setAttack(byte channel, byte operatorNum, byte attack); - byte setDecay(byte channel, byte operatorNum, byte decay); - byte setSustain(byte channel, byte operatorNum, byte sustain); - byte setRelease(byte channel, byte operatorNum, byte release); - byte setFNumber(byte channel, short fNumber); - byte setFrequency(byte channel, float frequency); - byte setBlock(byte channel, byte block); - byte setKeyOn(byte channel, bool keyOn); - byte setFeedback(byte channel, byte feedback); - byte setSynthMode(byte channel, bool isAdditive); - byte setDeepTremolo(bool enable); - byte setDeepVibrato(bool enable); - byte setPercussion(bool enable); - byte setDrums(byte drums); - byte setDrums(bool bass, bool snare, bool tom, bool cymbal, bool hihat); - byte setWaveForm(byte channel, byte operatorNum, byte waveForm); - - private: + virtual void setWaveFormSelect(bool enable); + void setTremolo(byte channel, byte operatorNum, bool enable); + void setVibrato(byte channel, byte operatorNum, bool enable); + void setMaintainSustain(byte channel, byte operatorNum, bool enable); + void setEnvelopeScaling(byte channel, byte operatorNum, bool enable); + void setMultiplier(byte channel, byte operatorNum, byte multiplier); + void setScalingLevel(byte channel, byte operatorNum, byte scaling); + void setVolume(byte channel, byte operatorNum, byte volume); + void setChannelVolume(byte channel, byte volume); + void setAttack(byte channel, byte operatorNum, byte attack); + void setDecay(byte channel, byte operatorNum, byte decay); + void setSustain(byte channel, byte operatorNum, byte sustain); + void setRelease(byte channel, byte operatorNum, byte release); + void setFNumber(byte channel, short fNumber); + void setFrequency(byte channel, float frequency); + void setBlock(byte channel, byte block); + void setNoteSelect(bool enable); + void setKeyOn(byte channel, bool keyOn); + void setFeedback(byte channel, byte feedback); + void setSynthMode(byte channel, byte synthMode); + void setDeepTremolo(bool enable); + void setDeepVibrato(bool enable); + void setPercussion(bool enable); + void setDrums(byte drums); + void setDrums(bool bass, bool snare, bool tom, bool cymbal, bool hihat); + void setWaveForm(byte channel, byte operatorNum, byte waveForm); + + protected: byte pinReset = PIN_RESET; byte pinAddress = PIN_ADDR; byte pinLatch = PIN_LATCH; + byte* chipRegisters; + byte* channelRegisters; + byte* operatorRegisters; + + byte numChannels = OPL2_NUM_CHANNELS; + const float fIntervals[8] = { 0.048, 0.095, 0.190, 0.379, 0.759, 1.517, 3.034, 6.069 }; @@ -230,30 +258,12 @@ { 0x10, 0xFF, 0x12, 0xFF, 0x11 }, { 0x13, 0x14, 0xFF, 0x15, 0xFF } }; - const byte drumOffsets[6] = { - 0x10, 0x13, 0x14, 0x12, 0x15, 0x11 - }; const byte drumChannels[5] = { 6, 7, 8, 8, 7 }; const byte drumBits[5] = { DRUM_BITS_BASS, DRUM_BITS_SNARE, DRUM_BITS_TOM, DRUM_BITS_CYMBAL, DRUM_BITS_HI_HAT }; - const byte instrumentBaseRegs[6] = { - 0x20, 0x40, 0x60, 0x80, 0xE0, 0xC0 - }; - byte oplRegisters[256]; - - const byte ZERO = 0; - const byte ONE = 1; - const byte CHANNEL_MAX = 8; - const byte OCTAVE_MAX = 7; - const byte NOTE_MAX = 11; - const byte DRUM_SOUND_MAX = 5; - const short F_NUM_MIN = 0; - const short F_NUM_MAX = 1023; - const float VOLUME_MIN = 0.0; - const float VOLUME_MAX = 1.0; }; #endif diff --git a/src/OPL3.cpp b/src/OPL3.cpp new file mode 100644 index 0000000..a62eafc --- /dev/null +++ b/src/OPL3.cpp @@ -0,0 +1,505 @@ +/** + * ________ __________.____ ________ _____ .___.__ .____ ._____. + * \_____ \\______ \ | \_____ \ / _ \ __ __ __| _/|__| ____ | | |__\_ |__ + * / | \| ___/ | / ____/ / /_\ \| | \/ __ | | |/ _ \ | | | || __ \ + * / | \ | | |___/ \ / | \ | / /_/ | | ( <_> ) | |___| || \_\ \ + * \_______ /____| |_______ \_______ \ \____|__ /____/\____ | |__|\____/ |_______ \__||___ / + * \/ \/ \/ \/ \/ \/ \/ + * ___________ __ .__ _____ + * \_ _____/__ ____/ |_ ____ ____ _____|__| ____ ____ ______ _/ ____\___________ + * | __)_\ \/ /\ __\/ __ \ / \ / ___/ |/ _ \ / \ / ___/ \ __\/ _ \_ __ \ + * | \> < | | \ ___/| | \\___ \| ( <_> ) | \\___ \ | | ( <_> ) | \/ + * /_______ /__/\_ \ |__| \___ >___| /____ >__|\____/|___| /____ > |__| \____/|__| + * \/ \/ \/ \/ \/ \/ \/ + * ________ __________.____ ________ ________ ._. + * \_____ \\______ \ | \_____ \ \______ \ __ __ ____| | + * / | \| ___/ | _(__ < | | \| | \/ _ \ | + * / | \ | | |___ / \ | ` \ | ( <_> )| + * \_______ /____| |_______ \/______ / /_______ /____/ \____/__ + * \/ \/ \/ \/ \/ + * + * Extensions to the OPL2 Audio Library for Arduino and compatibles to support the OPL3 Duo! board. + * This file contains the generic YMF262 OPL3 implementation. + * Code by Maarten janssen (maarten@cheerful.nl) 2020-10-12 + * WWW.CHEERFUL.NL + */ + + +#include "OPL3.h" + +#if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO + #include + #include +#else + #include + #include +#endif + + +/** + * Create a new OPL3 instance with default pins. + * + * A1 = D7 + * A0 = D8 + * /IC = D9 + * /WR = D10 + */ +OPL3::OPL3() : OPL2(9, 8, 10) { +} + + +/** + * Create an OPL3 instance with custom pins. + * + * @param a1 - Pin number to use for A1. + * @param a0 - Pin number to use for A0. + * @param latch - Pin number to use for LATCH. + * @param reset - Pin number to use for RESET. + */ +OPL3::OPL3(byte a1, byte a0, byte latch, byte reset) : OPL2(reset, a0, latch) { + pinBank = a1; +} + + +/** + * Initialize the OPL3 library and reset the chip. + */ +void OPL3::begin() { + pinMode(pinBank, OUTPUT); + digitalWrite(pinBank, LOW); + OPL2::begin(); +} + + +/** + * Create shadow registers to hold the values written to the OPL3 chip for later access. Only those registers that are + * are valid on the YMF262 are created to be as memory friendly as possible for platforms with limited RAM such as the + * Arduino Uno / Nano. Registers consume 239 bytes. + */ +void OPL3::createShadowRegisters() { + chipRegisters = new byte[5]; // 5 + channelRegisters = new byte[3 * numChannels]; // 54 + operatorRegisters = new byte[10 * numChannels]; // 180 +} + + +/** + * Hard reset the YMF262 chip and initialize all registers to 0x00. This should be called before sending any data to the + * chip. + */ +void OPL3::reset() { + digitalWrite(pinReset, LOW); + delay(1); + digitalWrite(pinReset, HIGH); + + // Initialize chip registers. + setChipRegister(0x00, 0x00); + setChipRegister(0x08, 0x40); + setChipRegister(0xBD, 0x00); + setChipRegister(0x104, 0x00); + setChipRegister(0x105, 0x00); + + // Initialize all channel and operator registers. + for (byte i = 0; i < getNumChannels(); i ++) { + setChannelRegister(0xA0, i, 0x00); + setChannelRegister(0xB0, i, 0x00); + setChannelRegister(0xC0, i, 0x00); + + for (byte j = OPERATOR1; j <= OPERATOR2; j ++) { + setOperatorRegister(0x20, i, j, 0x00); + setOperatorRegister(0x40, i, j, 0x3F); + setOperatorRegister(0x60, i, j, 0x00); + setOperatorRegister(0x80, i, j, 0x00); + setOperatorRegister(0xE0, i, j, 0x00); + } + } +} + + +/** + * Get the internal register offset for a chip wide register. + * + * @param reg - The 9-bit register for which we wnat to know the internal offset. + * @return The offset to the internal shadow register or 0 if an illegal chip register was requested. + */ +byte OPL3::getChipRegisterOffset(short reg) { + switch (reg & 0xFF) { + case 0x04: + return 1; + case 0x05: + return 2; + case 0x08: + return 3; + case 0xBD: + return 4; + case 0x01: + default: + return 0; + } +} + + +/** + * Write a given value to a channel based register. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel to address [0, 17] + * @param value - The value to write to the register. + */ +void OPL3::setChannelRegister(byte baseRegister, byte channel, byte value) { + channelRegisters[getChannelRegisterOffset(baseRegister, channel)] = value; + + byte bank = (channel >> 8) & 0x01; + byte reg = baseRegister + (channel % CHANNELS_PER_BANK); + write(bank, reg, value); +} + + +/** + * Write a given value to an operator register for a channel. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel of the operator [0, 17] + * @param operatorNum - The operator to change [0, 1]. + * @param value - The value to write to the operator's register. + */ +void OPL3::setOperatorRegister(byte baseRegister, byte channel, byte operatorNum, byte value) { + operatorRegisters[getOperatorRegisterOffset(baseRegister, channel, operatorNum)] = value; + + byte bank = (channel >> 8) & 0x01; + byte reg = baseRegister + getRegisterOffset(channel % CHANNELS_PER_BANK, operatorNum); + write(bank, reg, value); +} + + +/** + * Write a given value to a register of the OPL3 chip. + * + * @param bank - The bank (A1) of the register [0, 1]. + * @param reg - The register to be changed. + * @param value - The value to write to the register. + */ +void OPL3::write(byte bank, byte reg, byte value) { + digitalWrite(pinAddress, LOW); + digitalWrite(pinBank, (bank & 0x01) ? HIGH : LOW); + #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO + SPI.transfer(reg); + #else + wiringPiSPIDataRW(SPI_CHANNEL, ®, 1); + #endif + digitalWrite(pinLatch, LOW); + delayMicroseconds(8); + + digitalWrite(pinLatch, HIGH); + delayMicroseconds(8); + + digitalWrite(pinAddress, HIGH); + #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO + SPI.transfer(value); + #else + wiringPiSPIDataRW(SPI_CHANNEL, &value, 1); + #endif + digitalWrite(pinLatch, LOW); + delayMicroseconds(8); + digitalWrite(pinLatch, HIGH); + delayMicroseconds(8); +} + + +/** + * Get the number of 2OP channels for this implementation. + * + * @return The number of 2OP channels. + */ +byte OPL3::getNumChannels() { + return numChannels; +} + + +/** + * Get the number of 4OP channels for this implementation. + * + * @return The number of 4OP channels. + */ +byte OPL3::getNum4OPChannels() { + return num4OPChannels; +} + + +/** + * Get the 2-OP channel that is associated with the given 4 operator channel. + * + * @param channel4OP - The 4 operator channel [0, 5] for wich we want to get the associated OPL channel. + * @param index2OP - Then 2 operator channel index [0, 1], defaults to 0 for control channel. + * @return The OPL3 channel number that controls the 4 operator channel. + */ +byte OPL3::get4OPControlChannel(byte channel4OP, byte index2OP) { + return channelPairs4OP[channel4OP % getNum4OPChannels()][index2OP % 2]; +} + + +/** + * Create a new and empty 4-OP instrument. By default the new 4-OP instrument will be an OPL2 compatible pair of 2-OP + * Instruments. + * + * @return A new, empty 4-OP instrument. + */ +Instrument4OP OPL3::createInstrument4OP() { + Instrument4OP instrument4OP; + instrument4OP.subInstrument[0] = createInstrument(); + instrument4OP.subInstrument[1] = createInstrument(); + return instrument4OP; +} + + +#if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO + /** + * Create a 4-OP instrument and load it with instrument parameters from the given data pointer. Instrument data must + * be 24 bytes of contiguous instrument data to define the two sub instruments. + * + * @param instrumentData - Pointer to the offset of instrument data. + * @param fromProgmem - On Arduino defines to load instrument data from PROGMEM (when true (default)) or SRAM. + * @return The 4-OP instrument defined by the parameters at the given location in memory. + */ + Instrument4OP OPL3::loadInstrument4OP(const unsigned char *instrumentData, bool fromProgmem) { + Instrument4OP instrument4OP = createInstrument4OP(); + + instrument4OP.subInstrument[0] = loadInstrument(instrumentData, fromProgmem); + instrument4OP.subInstrument[1] = loadInstrument(instrumentData + 12, fromProgmem); + + return instrument4OP; + } +#else + /** + * Create a 4-OP instrument and load it with instrument parameters from the given data pointer. Instrument data must + * be 24 bytes of contiguous instrument data to define the two sub instruments. + * + * @param instrumentData - Pointer to the offset of instrument data. + * @return The 4-OP instrument defined by the parameters at the given location in memory. + */ + Instrument4OP OPL3::loadInstrument4OP(const unsigned char *instrumentData) { + Instrument4OP instrument4OP = createInstrument4OP(); + + instrument4OP.subInstrument[0] = loadInstrument(instrumentData); + instrument4OP.subInstrument[1] = loadInstrument(instrumentData + 12); + + return instrument4OP; + } +#endif + + +/** + * Create a new 4-operator instrument from the current settings of the four operators of the given 4-op channel. + * + * @param channel4OP - The 4-OP channel [0, 5] from which to create the instrument. + * @return The Instrument4OP containing the current 4-OP channel operator settings. + */ +Instrument4OP OPL3::getInstrument4OP(byte channel4OP) { + channel4OP = channel4OP % getNum4OPChannels(); + + Instrument4OP instrument; + instrument.subInstrument[0] = getInstrument(get4OPControlChannel(channel4OP, 0)); + instrument.subInstrument[1] = getInstrument(get4OPControlChannel(channel4OP, 1)); + + return instrument; +} + + +/** + * Assign the given 4-operator instrument to a 4-OP channel. An optional volume may be provided. + * + * @param channel4OP - The 4-op channel [0, 5] to assign the instrument to. + * @param instrument - The Instrument4OP to assign to the channel. + * @param volume - Optional volume [0.0, 1.0] that will be assigned to the operators. If omitted volume is set to 1.0. + */ +void OPL3::setInstrument4OP(byte channel4OP, Instrument4OP instrument, float volume) { + channel4OP = channel4OP % getNum4OPChannels(); + setInstrument(get4OPControlChannel(channel4OP, 0), instrument.subInstrument[0], volume); + setInstrument(get4OPControlChannel(channel4OP, 1), instrument.subInstrument[1], volume); +} + + +/** + * Enable or disable OPL3 mode. This function must be called in order to use any of the OPL3 functions. It will also + * set panning for all channels to enable both left and right speakers when OPL3 mode is enabled. + * + * @param enable - When set to true enables OPL3 mode. + */ +void OPL3::setOPL3Enabled(bool enable) { + setChipRegister(0x105, enable ? 0x01 : 0x00); + + // For ease of use enable both the left and the right speaker on all channels when going into OPL3 mode. + for (byte i = 0; i < getNumChannels(); i ++) { + setPanning(i, enable, enable); + } +} + + +/** + * Returns whether OPL3 mode is currently enabled or not. + * + * @return True if OPL3 mode is enabled. + */ +bool OPL3::isOPL3Enabled() { + return getChipRegister(0x105) & 0x01; +} + + +/** + * Set the panning of the givven channel. + * + * @param channel - The channel for which to set panning [0, 17]. + * @param left - When true the left speaker will output audio. + * @param right - When true the right speaker will output audio. + */ +void OPL3::setPanning(byte channel, bool left, bool right) { + byte value = getChannelRegister(0xC0, channel) & 0xCF; + value += left ? 0x10 : 0x00; + value += right ? 0x20 : 0x00; + + setChannelRegister(0xC0, channel, value); +} + + +/** + * Does audio output of the given channel go to the left speaker? + * + * @return True if audio output on the left speaker is enabled. + */ +bool OPL3::isPannedLeft (byte channel) { + return getChannelRegister(0xC0, channel) & 0x10; +} + + +/** + * Does audio output of the given channel go to the right speaker? + * + * @return True if audio output on the right speaker is enabled. + */ +bool OPL3::isPannedRight(byte channel) { + return getChannelRegister(0xC0, channel) & 0x20; +} + + +/** + * OPL3 always has waveform selection enabled. This will override the OPL2 function. + * + * @return Always true + */ +bool OPL3::getWaveFormSelect() { + return true; +} + + +/** + * Enabling or disabling waveform select is not implemented on OPL3. Waveform selection is always enabled and the WSE + * bit must remain disabled! Calling this function will simply clear chip register 0x01. + * + * @param enable - Dummy parameter vor OPL2 compatibility that may be ignored. + */ +void OPL3::setWaveFormSelect(bool enable) { + setChipRegister(0x01, 0x00); +} + + +/** + * Is the given 4-OP channel enabled? + * + * @param channel4OP -The 4-OP cahnnel [0, 5] for which we want to know if 4-operator mode is enabled. + * @return True if the given 4-OP channel is in 4-operator mode. + */ +bool OPL3::is4OPChannelEnabled(byte channel4OP) { + byte channelMask = 0x01 << (channel4OP % getNum4OPChannels()); + return getChipRegister(0x0104) & channelMask; +} + + +/** + * Enable or disable 4-operator mode on the given 4-OP channel. + * + * @param channel4OP - The 4-OP channel [0, 5] for which to enable or disbale 4-operator mode. + * @param enable - Enables or disable 4 operator mode. + */ +void OPL3::set4OPChannelEnabled(byte channel4OP, bool enable) { + byte channelMask = 0x01 << (channel4OP % getNum4OPChannels()); + byte value = getChipRegister(0x0104) & ~channelMask; + setChipRegister(0x0104, value + (enable ? channelMask : 0)); +} + + +/** + * Enables or disables all 4-OP channels. + * + * @param enable - Enables 4-OP channels when true. + */ +void OPL3::setAll4OPChannelsEnabled(bool enable) { + for (byte i = 0; i < getNum4OPChannels(); i ++) { + set4OPChannelEnabled(i, enable); + } +} + + +/** + * Get the synthesizer mode of the given 4-OP channel. + * + * @param channel4OP - The 4-OP channel [0, 5] for which to get the synthesis mode. + * @return The synthesis mode of the 4-OP channel. + */ +byte OPL3::get4OPSynthMode(byte channel4OP) { + channel4OP = channel4OP % getNum4OPChannels(); + byte synthMode = getSynthMode(get4OPControlChannel(channel4OP, 0)) ? 0x02 : 0x00; + synthMode += getSynthMode(get4OPControlChannel(channel4OP, 1)) ? 0x01 : 0x00; + return synthMode; +} + + +/** + * Set synthesizer mode for the given 4-OP channel. + * + * @param channel4OP - The 4-OP channel [0, 5] for which to set synth mode. + * @param synthMode - Synthesis mode to set. + */ +void OPL3::set4OPSynthMode(byte channel4OP, byte synthMode) { + channel4OP = channel4OP % getNum4OPChannels(); + setSynthMode(get4OPControlChannel(channel4OP, 0), synthMode & 0x02 >> 1); + setSynthMode(get4OPControlChannel(channel4OP, 1), synthMode & 0x01); +} + + +/** + * Get the volume of a 4-OP channel. Assume that the volume was set according to the current synth mode. + * + * @return The volume [0, 63] of the 4-OP channel. + */ +byte OPL3::get4OPChannelVolume(byte channel4OP) { + channel4OP = channel4OP % getNum4OPChannels(); + return getVolume(get4OPControlChannel(channel4OP, 1), OPERATOR2); +} + + +/** + * Set the volume of a 4-OP channel. Depending of the synth mode of the 4-OP channel the output level of different + * operators will be set. + * + * @param channel4OP - The 4-OP channel [0, 5] for which to set the volume. + * @param volume - The output level [0, 63] to set where 0 is loudest and 63 is softest. + */ +void OPL3::set4OPChannelVolume(byte channel4OP, byte volume) { + channel4OP = channel4OP % getNum4OPChannels(); + switch (get4OPSynthMode(channel4OP)) { + case SYNTH_MODE_AM_FM: + setVolume(get4OPControlChannel(channel4OP, 0), OPERATOR1, volume); + break; + case SYNTH_MODE_FM_AM: + setVolume(get4OPControlChannel(channel4OP, 0), OPERATOR2, volume); + break; + case SYNTH_MODE_AM_AM: + setVolume(get4OPControlChannel(channel4OP, 0), OPERATOR1, volume); + setVolume(get4OPControlChannel(channel4OP, 1), OPERATOR1, volume); + break; + default: + break; + } + + setVolume(get4OPControlChannel(channel4OP, 1), OPERATOR2, volume); +} diff --git a/src/OPL3.h b/src/OPL3.h new file mode 100644 index 0000000..a5cd7c2 --- /dev/null +++ b/src/OPL3.h @@ -0,0 +1,76 @@ +#include "OPL2.h" + +#ifndef OPL3_LIB_H_ + #define OPL3_LIB_H_ + + #define OPL3_NUM_2OP_CHANNELS 18 + #define OPL3_NUM_4OP_CHANNELS 6 + #define CHANNELS_PER_BANK 9 + + #define SYNTH_MODE_FM_FM 0 + #define SYNTH_MODE_FM_AM 1 + #define SYNTH_MODE_AM_FM 2 + #define SYNTH_MODE_AM_AM 3 + + + struct Instrument4OP { + Instrument subInstrument[2]; // Definition of the 2 sub instruments for each channel. + }; + + + class OPL3: public OPL2 { + public: + OPL3(); + OPL3(byte a1, byte a0, byte latch, byte reset); + virtual void begin(); + virtual void reset(); + virtual void createShadowRegisters(); + + virtual void setChannelRegister(byte baseRegister, byte channel, byte value); + virtual void setOperatorRegister(byte baseRegister, byte channel, byte operatorNum, byte value); + virtual byte getChipRegisterOffset(short reg); + virtual void write(byte bank, byte reg, byte value); + + virtual byte getNumChannels(); + virtual byte getNum4OPChannels(); + virtual byte get4OPControlChannel(byte channel4OP, byte index2OP = 0); + + Instrument4OP createInstrument4OP(); + #if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO + Instrument4OP loadInstrument4OP(const unsigned char *instrument, bool fromProgmem = INSTRUMENT_DATA_PROGMEM); + #else + Instrument4OP loadInstrument4OP(const unsigned char *instrument); + #endif + Instrument4OP getInstrument4OP(byte channel4OP); + void setInstrument4OP(byte channel4OP, Instrument4OP instrument, float volume = 1.0); + + virtual bool getWaveFormSelect(); + virtual void setWaveFormSelect(bool enable = false); + + virtual bool isOPL3Enabled(); + virtual void setOPL3Enabled(bool enable); + virtual bool is4OPChannelEnabled(byte channel4OP); + virtual void set4OPChannelEnabled(byte channel4OP, bool enable); + void setAll4OPChannelsEnabled(bool enable); + + bool isPannedLeft (byte channel); + bool isPannedRight(byte channel); + void setPanning(byte channel, bool left, bool right); + byte get4OPSynthMode(byte channel4OP); + void set4OPSynthMode(byte channel4OP, byte synthMode); + byte get4OPChannelVolume(byte channel4OP); + void set4OPChannelVolume(byte channel4OP, byte volume); + + + protected: + byte pinBank = 7; + + byte numChannels = OPL3_NUM_2OP_CHANNELS; + byte num4OPChannels = OPL3_NUM_4OP_CHANNELS; + + byte channelPairs4OP[6][2] = { + { 0, 3 }, { 1, 4 }, { 2, 5 }, + { 9, 12 }, { 10, 13 }, { 11, 14 } + }; + }; +#endif diff --git a/src/OPL3Duo.cpp b/src/OPL3Duo.cpp new file mode 100644 index 0000000..62313e8 --- /dev/null +++ b/src/OPL3Duo.cpp @@ -0,0 +1,323 @@ +/** + * ________ __________.____ ________ _____ .___.__ .____ ._____. + * \_____ \\______ \ | \_____ \ / _ \ __ __ __| _/|__| ____ | | |__\_ |__ + * / | \| ___/ | / ____/ / /_\ \| | \/ __ | | |/ _ \ | | | || __ \ + * / | \ | | |___/ \ / | \ | / /_/ | | ( <_> ) | |___| || \_\ \ + * \_______ /____| |_______ \_______ \ \____|__ /____/\____ | |__|\____/ |_______ \__||___ / + * \/ \/ \/ \/ \/ \/ \/ + * ___________ __ .__ _____ + * \_ _____/__ ____/ |_ ____ ____ _____|__| ____ ____ ______ _/ ____\___________ + * | __)_\ \/ /\ __\/ __ \ / \ / ___/ |/ _ \ / \ / ___/ \ __\/ _ \_ __ \ + * | \> < | | \ ___/| | \\___ \| ( <_> ) | \\___ \ | | ( <_> ) | \/ + * /_______ /__/\_ \ |__| \___ >___| /____ >__|\____/|___| /____ > |__| \____/|__| + * \/ \/ \/ \/ \/ \/ \/ + * ________ __________.____ ________ ________ ._. + * \_____ \\______ \ | \_____ \ \______ \ __ __ ____| | + * / | \| ___/ | _(__ < | | \| | \/ _ \ | + * / | \ | | |___ / \ | ` \ | ( <_> )| + * \_______ /____| |_______ \/______ / /_______ /____/ \____/__ + * \/ \/ \/ \/ \/ + * + * Extensions to the OPL2 Audio Library for Arduino and compatibles to support the OPL3 Duo! board. + * This file contains the extensions required for dual YMF262. + * Code by Maarten janssen (maarten@cheerful.nl) 2020-10-12 + * WWW.CHEERFUL.NL + */ + + +#include "OPL3Duo.h" + +// TODO: Change BOARD_TYPE to PLATFORM +#if BOARD_TYPE == OPL2_BOARD_TYPE_ARDUINO + #include + #include +#else + #include + #include +#endif + + +/** + * Create a new OPL3Duo instance with default pins. + * + * A2 = D6 + * A1 = D7 + * A0 = D8 + * /IC = D9 + * /WR = D10 + */ +OPL3Duo::OPL3Duo() : OPL3() { +} + + +/** + * Create a new OPL3Duo instance with custom pins. + * + * @param a2 - Pin number to use for A2. + * @param a1 - Pin number to use for A1. + * @param a0 - Pin number to use for A0. + * @param latch - Pin number to use for LATCH. + * @param reset - Pin number to use for RESET. + */ +OPL3Duo::OPL3Duo(byte a2, byte a1, byte a0, byte latch, byte reset) : OPL3(a1, a0, latch, reset) { + pinUnit = a2; +} + + +/** + * Initialize the OPL3Duo and reset the chips. + */ +void OPL3Duo::begin() { + pinMode(pinUnit, OUTPUT); + digitalWrite(pinUnit, LOW); + OPL3::begin(); +} + + +/** + * Create shadow registers to hold the values written to the OPL3 chips for later access. Only those registers that are + * are valid on the YMF262 are created to be as memory friendly as possible for platforms with limited RAM such as the + * Arduino Uno / Nano. Registers consume 478 bytes. + */ +void OPL3Duo::createShadowRegisters() { + chipRegisters = new byte[5 * 2]; // 10 + channelRegisters = new byte[3 * numChannels]; // 108 + operatorRegisters = new byte[10 * numChannels]; // 360 +} + + +/** + * Hard reset the OPL3 chip. All registers will be reset to 0x00, This should be done before sending any register data + * to the chip. + */ +void OPL3Duo::reset() { + // Hard reset both OPL3 chips. + for (byte unit = 0; unit < 2; unit ++) { + digitalWrite(pinUnit, unit == 1); + digitalWrite(pinReset, LOW); + delay(1); + digitalWrite(pinReset, HIGH); + } + + // Initialize chip registers on both synth units. + for (byte i = 0; i < 2; i ++) { + setChipRegister(i, 0x01, 0x00); + setChipRegister(i, 0x04, 0x00); + setChipRegister(i, 0x05, 0x00); + setChipRegister(i, 0x08, 0x40); + setChipRegister(i, 0xBD, 0x00); + } + + // Initialize all channel and operator registers. + for (byte i = 0; i < getNumChannels(); i ++) { + setChannelRegister(0xA0, i, 0x00); + setChannelRegister(0xB0, i, 0x00); + setChannelRegister(0xC0, i, 0x00); + + for (byte j = OPERATOR1; j <= OPERATOR2; j ++) { + setOperatorRegister(0x20, i, j, 0x00); + setOperatorRegister(0x40, i, j, 0x3F); + setOperatorRegister(0x60, i, j, 0x00); + setOperatorRegister(0x80, i, j, 0x00); + setOperatorRegister(0xE0, i, j, 0x00); + } + } + + digitalWrite(pinUnit, LOW); +} + + +/** + * Get the current value of a chip wide register from the shadow registers. + * + * @param synthUnit - The chip to address [0, 1] + * @param reg - The 9-bit address of the register. + * @return The value of the register from shadow registers. + */ +byte OPL3Duo::getChipRegister(byte synthUnit, short reg) { + synthUnit = synthUnit & 0x01; + return chipRegisters[(synthUnit * 5) + getChipRegisterOffset(reg)]; +} + + +/** + * Write a given value to a chip wide register. + * + * @param synthUnit - The chip to address [0, 1] + * @param reg - The 9-bit register to write to. + * @param value - The value to write to the register. + */ +void OPL3Duo::setChipRegister(byte synthUnit, short reg, byte value) { + synthUnit = synthUnit & 0x01; + chipRegisters[(synthUnit * 5) + getChipRegisterOffset(reg)] = value; + + byte bank = ((reg >> 8) & 0x01) | (synthUnit << 1); + write(bank, reg & 0xFF, value); +} + + +/** + * Write a given value to a channel based register. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel to address [0, 17] + * @param value - The value to write to the register. + */ +void OPL3Duo::setChannelRegister(byte baseRegister, byte channel, byte value) { + channelRegisters[getChannelRegisterOffset(baseRegister, channel)] = value; + + byte bank = (channel / CHANNELS_PER_BANK) & 0x03; + byte reg = baseRegister + (channel % CHANNELS_PER_BANK); + write(bank, reg, value); +} + + +/** + * Write a given value to an operator register for a channel. + * + * @param baseRegister - The base address of the register. + * @param channel - The channel of the operator [0, 17] + * @param op - The operator to change [0, 1]. + * @param value - The value to write to the operator's register. + */ +void OPL3Duo::setOperatorRegister(byte baseRegister, byte channel, byte operatorNum, byte value) { + operatorRegisters[getOperatorRegisterOffset(baseRegister, channel, operatorNum)] = value; + + byte bank = (channel / CHANNELS_PER_BANK) & 0x03; + byte reg = baseRegister + getRegisterOffset(channel % CHANNELS_PER_BANK, operatorNum); + write(bank, reg, value); +} + + +/** + * Write a given value to a register of the OPL3 chip. + * + * @param bank - The bank + unit (A1 + A2) of the register [0, 3]. + * @param reg - The register to be changed. + * @param value - The value to write to the register. + */ +void OPL3Duo::write(byte bank, byte reg, byte value) { + digitalWrite(pinUnit, (bank & 0x02) ? HIGH : LOW); + OPL3::write(bank, reg, value); +} + + +/** + * Get the number of 2OP channels for this implementation. + * + * @return The number of 2OP channels. + */ +byte OPL3Duo::getNumChannels() { + return numChannels; +} + + +/** + * Get the number of 4OP channels for this implementation. + * + * @return The number of 4OP channels. + */ +byte OPL3Duo::getNum4OPChannels() { + return num4OPChannels; +} + + +/** + * Get the 2-OP channel that is associated with the given 4 operator channel. + * + * @param channel4OP - The 4 operator channel [0, 11] for wich we want to get the associated OPL channel. + * @param index2OP - Then 2 operator channel index [0, 1], defaults to 0 for control channel. + * @return The OPL3 channel number that controls the 4 operator channel. + */ +byte OPL3Duo::get4OPControlChannel(byte channel4OP, byte index2OP) { + return channelPairs4OP[channel4OP % getNum4OPChannels()][index2OP % 2]; +} + + +/** + * Returns whether OPL3 mode is currently enabled on both synth units. + * + * @return True if OPL3 mode is enabled. + */ +bool OPL3Duo::isOPL3Enabled(byte synthUnit) { + return getChipRegister(synthUnit & 0x01, 0x105) & 0x01; +} + + +/** + * Returns whether OPL3 mode is currently enabled on both synth units. + * + * @return True if OPL3 mode is enabled on both chips. + */ +bool OPL3Duo::isOPL3Enabled() { + return (getChipRegister(0, 0x105) & 0x01) == 0x01 && + (getChipRegister(1, 0x105) & 0x01) == 0x01; +} + + +/** + * Enable or disable OPL3 mode on both synth units. This function must be called in order to use any of the OPL3 + * functions. It will also set panning for all channels to enable both left and right speakers when OPL3 mode is + * enabled. + * + * @param enable - When set to true enables OPL3 mode. + */ +void OPL3Duo::setOPL3Enabled(bool enable) { + setChipRegister(0, 0x105, enable ? 0x01 : 0x00); + setChipRegister(1, 0x105, enable ? 0x01 : 0x00); + + // For ease of use enable both the left and the right speaker on all channels when going into OPL3 mode. + for (byte i = 0; i < getNumChannels(); i ++) { + setPanning(i, enable, enable); + } +} + + +/** + * Enable or disable OPL3 mode for a single synth unit only. This function must be called in order to use any of the + * OPL3 functions. It will also set panning for all channels to enable both left and right speakers when OPL3 mode is + * enabled. + * + * @param synthUnit - Synth unit [0, 1] for which to change OPL3 mode. + * @param enable - When set to true enables OPL3 mode. + */ +void OPL3Duo::setOPL3Enabled(byte synthUnit, bool enable) { + synthUnit = synthUnit & 0x01; + setChipRegister(synthUnit, 0x105, enable ? 0x01 : 0x00); + + // For ease of use enable both the left and the right speaker on all channels when going into OPL3 mode. + byte firstChannel = synthUnit == 0 ? 0 : getNumChannels() / 2; + byte lastChannel = synthUnit == 0 ? getNumChannels() / 2 : getNumChannels(); + for (byte i = firstChannel; i < lastChannel; i ++) { + setPanning(i, enable, enable); + } +} + + +/** + * Is the given 4-OP channel enabled? + * + * @param channel4OP -The 4-OP cahnnel [0, 11] for which we want to know if 4-operator mode is enabled. + * @return True if the given 4-OP channel is in 4-operator mode. + */ +bool OPL3Duo::is4OPChannelEnabled(byte channel4OP) { + channel4OP = channel4OP % getNum4OPChannels(); + byte synthUnit = channel4OP >= NUM_4OP_CHANNELS_PER_UNIT ? 1 : 0; + byte channelMask = 0x01 << (channel4OP % NUM_4OP_CHANNELS_PER_UNIT); + return getChipRegister(synthUnit, 0x0104) & channelMask; +} + + +/** + * Enable or disable 4-operator mode on the given 4-OP channel. + * + * @param channel4OP - The 4-OP channel [0, 11] for which to enable or disbale 4-operator mode. + * @param enable - Enables or disable 4 operator mode. + */ +void OPL3Duo::set4OPChannelEnabled(byte channel4OP, bool enable) { + channel4OP = channel4OP % getNum4OPChannels(); + byte synthUnit = channel4OP >= NUM_4OP_CHANNELS_PER_UNIT ? 1 : 0; + byte channelMask = 0x01 << (channel4OP % NUM_4OP_CHANNELS_PER_UNIT); + byte value = getChipRegister(synthUnit, 0x0104) & ~channelMask; + setChipRegister(synthUnit, 0x0104, value + (enable ? channelMask : 0)); +} diff --git a/src/OPL3Duo.h b/src/OPL3Duo.h new file mode 100644 index 0000000..da568db --- /dev/null +++ b/src/OPL3Duo.h @@ -0,0 +1,47 @@ +#include "OPL3.h" + +#ifndef OPL3DUO_LIB_H_ + #define OPL3DUO_LIB_H_ + + #define NUM_4OP_CHANNELS_PER_UNIT 6 + #define OPL3DUO_NUM_2OP_CHANNELS 36 + #define OPL3DUO_NUM_4OP_CHANNELS 12 + + class OPL3Duo: public OPL3 { + public: + OPL3Duo(); + OPL3Duo(byte a2, byte a1, byte a0, byte latch, byte reset); + virtual void begin(); + virtual void reset(); + virtual void createShadowRegisters(); + + virtual byte getChipRegister(byte synthUnit, short reg); + virtual void setChipRegister(byte synthUnit, short reg, byte value); + virtual void setChannelRegister(byte baseRegister, byte channel, byte value); + virtual void setOperatorRegister(byte baseRegister, byte channel, byte op, byte value); + virtual void write(byte bank, byte reg, byte value); + + virtual byte getNumChannels(); + virtual byte getNum4OPChannels(); + virtual byte get4OPControlChannel(byte channel4OP, byte index2OP = 0); + + virtual bool isOPL3Enabled(); + virtual bool isOPL3Enabled(byte synthUnit); + virtual void setOPL3Enabled(bool enable); + virtual void setOPL3Enabled(byte synthUnit, bool enable); + virtual bool is4OPChannelEnabled(byte channel4OP); + virtual void set4OPChannelEnabled(byte channel4OP, bool enable); + protected: + byte pinUnit = 6; + + byte numChannels = OPL3DUO_NUM_2OP_CHANNELS; + byte num4OPChannels = OPL3DUO_NUM_4OP_CHANNELS; + + byte channelPairs4OP[12][2] = { + { 0, 3 }, { 1, 4 }, { 2, 5 }, + { 9, 12 }, { 10, 13 }, { 11, 14 }, + { 18, 21 }, { 19, 22 }, { 20, 23 }, + { 27, 30 }, { 28, 31 }, { 29, 32 } + }; + }; +#endif diff --git a/src/TuneParser.cpp b/src/TuneParser.cpp new file mode 100644 index 0000000..f564d3a --- /dev/null +++ b/src/TuneParser.cpp @@ -0,0 +1,547 @@ +#include "TuneParser.h" + + +/** + * TuneParser constructor. + * + * @param opl3Ref - Reference to the OPL3Duo instance used for playback. + */ +TuneParser::TuneParser(OPL3Duo* opl3Ref) { + opl3 = opl3Ref; +} + + +/** + * Initialize the TuneParser. + */ +void TuneParser::begin() { + opl3->begin(); + opl3->setOPL3Enabled(true); + opl3->setAll4OPChannelsEnabled(true); +} + + +/** + * Play the given tune with a 1 voice command string. + * + * @param voice0 - Command string for voice 0. + */ +void TuneParser::play(const char* voice0) { + const char* voices[6] = { voice0, NULL, NULL, NULL, NULL, NULL }; + Tune tune = createTune(voices, 1); + playTune(tune); +} + + +/** + * Play the given tune with 2 voices from command strings. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + */ +void TuneParser::play(const char* voice0, const char* voice1) { + const char* voices[6] = { voice0, voice1, NULL, NULL, NULL, NULL }; + Tune tune = createTune(voices, 2); + playTune(tune); +} + + +/** + * Play the given tune with 3 voices from command strings. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + */ +void TuneParser::play(const char* voice0, const char* voice1, const char* voice2) { + const char* voices[6] = { voice0, voice1, voice2, NULL, NULL, NULL }; + Tune tune = createTune(voices, 3); + playTune(tune); +} + + +/** + * Play the given tune with 4 voices from command strings. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @param voice3 - Command string for voice 3. + */ +void TuneParser::play(const char* voice0, const char* voice1, const char* voice2, const char* voice3) { + const char* voices[6] = { voice0, voice1, voice2, voice3, NULL, NULL }; + Tune tune = createTune(voices, 4); + playTune(tune); +} + + +/** + * Play the given tune with 5 voices from command strings. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @param voice3 - Command string for voice 3. + * @param voice4 - Command string for voice 4. + */ +void TuneParser::play(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4) { + const char* voices[6] = { voice0, voice1, voice2, voice3, voice4, NULL }; + Tune tune = createTune(voices, 5); + playTune(tune); +} + + +/** + * Play the given tune with 6 voices from command strings. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @param voice3 - Command string for voice 3. + * @param voice4 - Command string for voice 4. + * @param voice5 - Command string for voice 5. + */ +void TuneParser::play(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4, const char* voice5) { + const char* voices[6] = { voice0, voice1, voice2, voice3, voice4, voice5 }; + Tune tune = createTune(voices, 6); + playTune(tune); +} + + +/** + * Initialize the given tune with 1 voice for playing in the background. + * + * @param voice0 - Command string for voice 0. + * @return The tune ready to be played by calling update. + */ +Tune TuneParser::playBackground(const char* voice0) { + const char* voices[6] = { voice0, NULL, NULL, NULL, NULL, NULL }; + return createTune(voices, 1); +} + + +/** + * Initialize the given tune with 2 voices for playing in the background. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @return The tune ready to be played by calling update. + */ +Tune TuneParser::playBackground(const char* voice0, const char* voice1) { + const char* voices[6] = { voice0, voice1, NULL, NULL, NULL, NULL }; + return createTune(voices, 2); +} + + +/** + * Initialize the given tune with 3 voices for playing in the background. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @return The tune ready to be played by calling update. + */ +Tune TuneParser::playBackground(const char* voice0, const char* voice1, const char* voice2) { + const char* voices[6] = { voice0, voice1, voice2, NULL, NULL, NULL }; + return createTune(voices, 3); +} + + +/** + * Initialize the given tune with 4 voices for playing in the background. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @param voice3 - Command string for voice 3. + * @return The tune ready to be played by calling update. + */ +Tune TuneParser::playBackground(const char* voice0, const char* voice1, const char* voice2, const char* voice3) { + const char* voices[6] = { voice0, voice1, voice2, voice3, NULL, NULL }; + return createTune(voices, 4); +} + + +/** + * Initialize the given tune with 5 voices for playing in the background. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @param voice3 - Command string for voice 3. + * @param voice4 - Command string for voice 4. + * @return The tune ready to be played by calling update. + */ +Tune TuneParser::playBackground(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4) { + const char* voices[6] = { voice0, voice1, voice2, voice3, voice4, NULL }; + return createTune(voices, 5); +} + + +/** + * Initialize the given tune with 6 voices for playing in the background. + * + * @param voice0 - Command string for voice 0. + * @param voice1 - Command string for voice 1. + * @param voice2 - Command string for voice 2. + * @param voice3 - Command string for voice 3. + * @param voice4 - Command string for voice 4. + * @param voice5 - Command string for voice 5. + * @return The tune ready to be played by calling update. + */ +Tune TuneParser::playBackground(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4, const char* voice5) { + const char* voices[6] = { voice0, voice1, voice2, voice3, voice4, voice5 }; + return createTune(voices, 6); +} + + +/** + * Create a Tune structure from the given array of command strings. + * + * @param voices - Array of command strings for each voice. + * @param numVoices - The number of voices that is in use. + */ +Tune TuneParser::createTune(const char* voices[6], int numVoices) { + Tune tune; + + tune.numVoices = min(numVoices, 6); + for (byte i = 0; i < tune.numVoices; i ++) { + tune.voice[i].pattern = voices[i]; + } + + restartTune(tune); + + return tune; +} + + +/** + * Restart the given background tune. + * + * @param tune - The tune to restart. + */ +void TuneParser::restartTune(Tune& tune) { + tune.numEnded = 0; + tune.tickDuration = 60000 / (100 * 16); // duration of a 64th note @ 100 bmp. + tune.nextTick = millis(); + + for (byte i = 0; i < tune.numVoices; i ++) { + tune.voice[i].ended = false; + tune.voice[i].position = 0; + tune.voice[i].ticks = 1; + tune.voice[i].octave = 4; + tune.voice[i].volume = 0.8; + tune.voice[i].instrument = opl3->loadInstrument4OP(midiInstruments[0]); + tune.voice[i].defaultNoteLength = 16; + tune.voice[i].channel = tune.numVoices; + } +} + + +/** + * Has the given tune finished playing? + * + * @retrun True if the tune has finished playing. + */ +bool TuneParser::tuneEnded(Tune& tune) { + return tune.numVoices == tune.numEnded; +} + + +/** + * Play the given tune. + * + * @param tune - The tun to be played. + */ +void TuneParser::playTune(Tune& tune) { + while(!tuneEnded(tune)) { + unsigned long wait = update(tune); + delay(wait); + } +} + + +/** + * Update the tune parser to play the given tune in the background and return the number of milliseconds until it's time + * to process the next tick. If it not yet time to process the next tick then this function will exit immediately and + * return the number of milliseconds remaining until the next tick can be processed. + * + * @param tune - The tune to update. + * @return The number of ms to wait until the next tick. + */ +unsigned long TuneParser::update(Tune& tune) { + // Return immediately if it's not yet time to process the next tick. + if (millis() < tune.nextTick) { + return tune.nextTick - millis(); + } + + tune.nextTick = millis(); + unsigned long t = millis(); + + for (byte i = 0; i < tune.numVoices; i ++) { + if (!tune.voice[i].ended) { + tune.voice[i].ticks --; + + if (tune.voice[i].ticks == 0) { + opl3->setKeyOn(opl3->get4OPControlChannel(tune.voice[i].channel), false); + channelInUse[tune.voice[i].channel] = false; + + // Parse commands until we find a note, a rest or the end of the tune for this voice. + bool playingNote = false; + while (!playingNote) { + playingNote = parseTuneCommand(tune, i); + } + + if (tune.voice[i].ended) { + tune.numEnded ++; + } + } + } + } + + // Calculate time of next tick. + unsigned long wait = tune.tickDuration - (millis() - t); + tune.nextTick += wait; + + return wait; +} + + +/** + * Parse the next command in the command string of the given tune and voice index and leave the data pointer at the next + * command. + * + * @param tune - The tune that's being played. + * @param voiceIndex - The index of the voice that is being parsed/ + */ +bool TuneParser::parseTuneCommand(Tune& tune, byte voiceIndex) { + bool isPlaying = false; + Voice& voice = tune.voice[voiceIndex]; + + // Get command character and convert to upper case. + char command = pgm_read_byte_near(voice.pattern + voice.position); + if (command >= 'a') { + command -= 32; + } + + switch (command) { + // Handle end of tune for this voice. + case TUNE_CMD_END: { + voice.ended = true; + isPlaying = true; + break; + } + + // Parse note and cascade into handling rest for note delay. + case TUNE_CMD_NOTE_A ... TUNE_CMD_NOTE_G: { + parseNote(voice); + } + + // Handle a rest or pause in the tune. + case TUNE_CMD_REST: + case TUNE_CMD_PAUSE: { + parseRest(voice); + isPlaying = true; + break; + } + + // Handle 'On' to change octave. + case TUNE_CMD_OCTAVE: { + byte octave = parseNumber(voice, 0, 7); + if (octave != TP_NAN) { + voice.octave = octave; + } + break; + } + + // Handle '>' to increment octave. + case TUNE_CMD_OCTAVE_UP: { + if (voice.octave < 7) { + voice.octave ++; + } + break; + } + + // Handle '<' to decrement octave. + case TUNE_CMD_OCTAVE_DOWN: { + if (voice.octave > 0) { + voice.octave --; + } + break; + } + + // Handle 'Tnnn' to change sone temop. + case TUNE_CMD_TEMPO: { + byte tempo = parseNumber(voice, 40, 250); + if (tempo != TP_NAN) { + tune.tickDuration = 60000 / (tempo * 16); + } + break; + } + + // Handle 'Lnn' to change the default note length. + case TUNE_CMD_NOTE_LENGTH: { + voice.defaultNoteLength = parseNoteLength(voice); + break; + } + + // Handle 'Innn' to change the current instrument. + case TUNE_CMD_INSTRUMENT: { + byte instrumentIndex = parseNumber(voice, 0, 127); + if (instrumentIndex != TP_NAN) { + voice.instrument = opl3->loadInstrument4OP(midiInstruments[instrumentIndex]); + } + break; + } + + // Handle 'Vnn' to change volume. + case TUNE_CMD_VOLUME: { + byte volume = parseNumber(voice, 0, 15); + if (volume != TP_NAN) { + voice.volume = (float)volume / 15.0; + } + break; + } + + // ignore anything else. + default: + break; + } + + voice.position ++; + return isPlaying; +} + + +/** + * Parse the note found at the current command string position of the given voice and play the note. The duration of the + * note will be stored with the voice. + * + * @param voice - The voice from which to extract the note. + */ +void TuneParser::parseNote(Voice& voice) { + byte noteIndex = pgm_read_byte_near(voice.pattern + voice.position); + if (noteIndex >= 'a' && noteIndex <= 'g') { + noteIndex = noteIndex - 'a'; + } else if (noteIndex >= 'A' && noteIndex <= 'G') { + noteIndex = noteIndex - 'A'; + } else { + return; + } + + byte octave = voice.octave; + byte note = notes[0][noteIndex]; + + // Handle sharp and flat notes. + char sharpFlat = pgm_read_byte_near(voice.pattern + voice.position + 1); + if (sharpFlat == TUNE_CMD_NOTE_FLAT) { + voice.position ++; + note = notes[1][noteIndex]; + if (note == NOTE_B) { + octave = max(octave - 1, 0); + } + } else if (sharpFlat == TUNE_CMD_NOTE_SHARP || sharpFlat == TUNE_CMD_NOTE_SHARP2) { + voice.position ++; + note = notes[2][noteIndex]; + if (note == NOTE_C) { + octave = min(octave + 1, 7); + } + } + + // Find the next free channel to play the note on. + for (byte i = 1; i <= TP_NUM_CHANNELS; i ++) { + oplChannel4OP = (oplChannel4OP + i) % TP_NUM_CHANNELS; + if (!channelInUse[oplChannel4OP]) { + break; + } + } + + // Do some administartion and play the note! + channelInUse[oplChannel4OP] = true; + voice.channel = oplChannel4OP; + opl3->setInstrument4OP(oplChannel4OP, voice.instrument); + opl3->set4OPChannelVolume(oplChannel4OP, (1.0 - voice.volume) * 63); + opl3->playNote(opl3->get4OPControlChannel(oplChannel4OP), octave, note); +} + + +/** + * Determine the number of ticks until the next command should be parsed. This is uesed for both rests and notes to + * determine their length. The number of ticks to wait is sotred with the given voice. + * + * @param voice - The voice for which we want to know the duration of the note or rest. + */ +void TuneParser::parseRest(Voice& voice) { + byte ticks = parseNoteLength(voice); + + // Step through pattern data until we no longer find a digit. + char digit; + do { + voice.position ++; + digit = pgm_read_byte_near(voice.pattern + voice.position); + } while (digit >= '0' && digit <= '9'); + + // If note has a dot then add half of its duration. + if (pgm_read_byte_near(voice.pattern + voice.position) == TUNE_CMD_NOTE_DOUBLE) { + ticks += ticks / 2; + } + + // Move position back one byte to not skip next command. + voice.position --; + + // Set the number of ticks to hold the note. + voice.ticks = ticks; +} + + +/** + * Extract the note length at the current position of the command string for the given voice. If there is no number at + * at the current position then return the default note lengt that ser set with the L command. Note the the '.' is not + * taken into account in this function! + * + * @param voice - the voice from which to extract the note length. + * @return The length of the note in ticks. + */ +byte TuneParser::parseNoteLength(Voice voice) { + byte length = parseNumber(voice, 1, 64); + + if (length == TP_NAN) { + return voice.defaultNoteLength; + } + + // Reverse the bit order, so if duration is 16th note return 4 ticks. + for (byte i = 6; i >= 0; i --) { + if (length & 1 << i) { + return 1 << (6 - i); + } + } + + return 16; +} + + +/** + * Extract the number at the current command position of the given voice. The number is bounded by nMain and nMax. If + * there is no number at the current command string position then TP_NAN is returned. + * + * @param voice - The voice where the number needs to be extracted from. + * @param nMin - Minimum value of the number. + * @param nMax - Maximum value of the number. + * @return The number at the current command position in the voice or TP_NAN. + */ +byte TuneParser::parseNumber(Voice voice, byte nMin, byte nMax) { + char nextDigit = pgm_read_byte_near(voice.pattern + voice.position + 1); + if (nextDigit < '0' || nextDigit > '9') { + return TP_NAN; + } + + int number = 0; + while(nextDigit >= '0' && nextDigit <= '9') { + number *= 10; + voice.position ++; + number = number + pgm_read_byte_near(voice.pattern + voice.position) - '0'; + nextDigit = pgm_read_byte_near(voice.pattern + voice.position + 1); + } + + return (byte)max(nMin, min(number, nMax)); +} diff --git a/src/TuneParser.h b/src/TuneParser.h new file mode 100644 index 0000000..2fd58d9 --- /dev/null +++ b/src/TuneParser.h @@ -0,0 +1,88 @@ +#include + +#define TUNE_CMD_END '\0' +#define TUNE_CMD_INSTRUMENT 'I' +#define TUNE_CMD_NOTE_A 'A' +#define TUNE_CMD_NOTE_G 'G' +#define TUNE_CMD_NOTE_DOUBLE '.' +#define TUNE_CMD_NOTE_FLAT '-' +#define TUNE_CMD_NOTE_LENGTH 'L' +#define TUNE_CMD_NOTE_SHARP '#' +#define TUNE_CMD_NOTE_SHARP2 '+' +#define TUNE_CMD_OCTAVE 'O' +#define TUNE_CMD_OCTAVE_DOWN '<' +#define TUNE_CMD_OCTAVE_UP '>' +#define TUNE_CMD_PAUSE 'P' +#define TUNE_CMD_REST 'R' +#define TUNE_CMD_TEMPO 'T' +#define TUNE_CMD_VOLUME 'V' + + +#define TP_NUM_CHANNELS 12 +#define TP_NAN 255 + + +struct Voice { + const char* pattern; // String of commands to be played. + unsigned long position; // Position within the pattern string. + byte ticks; // Number of ticks left until the next command. + Instrument4OP instrument; // Current instrument for this voice. + float volume; // Current volume of this voice. + byte octave; // Current octave of this voice. + byte defaultNoteLength; // Current default not length for this voice. + bool ended; // Indicates that the voice has processed all commands. + byte channel; // OPL channel used by this voice. +}; + + +struct Tune { + byte numVoices; // Number of voices in use. + byte numEnded; // Number of voices that has ended. + unsigned long tickDuration; // Duration of each tick in ms (tempo) + unsigned long nextTick; // Time in ms of the next tick. + Voice voice[6]; // Data of each voice. +}; + + +extern const unsigned char *midiInstruments[]; +const byte notes[3][7] = {{ NOTE_A, NOTE_B, NOTE_C, NOTE_D, NOTE_E, NOTE_F, NOTE_G }, + { NOTE_GS, NOTE_AS, NOTE_B, NOTE_CS, NOTE_DS, NOTE_E, NOTE_FS }, + { NOTE_AS, NOTE_C, NOTE_CS, NOTE_DS, NOTE_F, NOTE_FS, NOTE_GS }}; + + +class TuneParser { + public: + TuneParser(OPL3Duo* opl3Ref); + TuneParser(OPL2* opl2Ref); + void begin(); + void play(const char* voice0); + void play(const char* voice0, const char* voice1); + void play(const char* voice0, const char* voice1, const char* voice2); + void play(const char* voice0, const char* voice1, const char* voice2, const char* voice3); + void play(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4); + void play(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4, const char* voice5); + Tune playBackground(const char* voice0); + Tune playBackground(const char* voice0, const char* voice1); + Tune playBackground(const char* voice0, const char* voice1, const char* voice2); + Tune playBackground(const char* voice0, const char* voice1, const char* voice2, const char* voice3); + Tune playBackground(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4); + Tune playBackground(const char* voice0, const char* voice1, const char* voice2, const char* voice3, const char* voice4, const char* voice5); + Tune createTune(const char* voices[6], int numVoices); + void playTune(Tune& tune); + void restartTune(Tune& tune); + bool tuneEnded(Tune& tune); + unsigned long update(Tune& tune); + bool parseTuneCommand(Tune& tune, byte voiceIndex); + void parseNote(Voice& voice); + void parseRest(Voice& voice); + byte parseNoteLength(Voice voice); + byte parseNumber(Voice voice, byte nMin, byte nMax); + + private: + OPL3Duo* opl3 = NULL; + byte oplChannel4OP = 0; + bool channelInUse[TP_NUM_CHANNELS] = { + false, false, false, false, false, false, + false, false, false, false, false, false + }; +}; diff --git a/src/instruments.h b/src/instruments.h index 66a0e43..f88ccf4 100644 --- a/src/instruments.h +++ b/src/instruments.h @@ -33,148 +33,154 @@ * 11 - Channel c, operator 2, register 0xE0 */ -const unsigned char INSTRUMENT_ACCORDN[12] PROGMEM = { 0x00, 0x24, 0x4F, 0xF2, 0x0B, 0x00, 0x0E, 0x31, 0x00, 0x52, 0x0B, 0x00 }; -const unsigned char INSTRUMENT_BAGPIPE1[12] PROGMEM = { 0x00, 0x31, 0x43, 0x6E, 0x17, 0x01, 0x02, 0x22, 0x05, 0x8B, 0x0C, 0x02 }; -const unsigned char INSTRUMENT_BAGPIPE2[12] PROGMEM = { 0x00, 0x30, 0x00, 0xFF, 0xA0, 0x03, 0x00, 0xA3, 0x00, 0x65, 0x0B, 0x02 }; -const unsigned char INSTRUMENT_BANJO1[12] PROGMEM = { 0x00, 0x31, 0x87, 0xA1, 0x11, 0x00, 0x08, 0x16, 0x80, 0x7D, 0x43, 0x00 }; -const unsigned char INSTRUMENT_BASS1[12] PROGMEM = { 0x00, 0x01, 0x15, 0x25, 0x2F, 0x00, 0x0A, 0x21, 0x80, 0x65, 0x6C, 0x00 }; -const unsigned char INSTRUMENT_BASS2[12] PROGMEM = { 0x00, 0x01, 0x1D, 0xF2, 0xEF, 0x00, 0x0A, 0x01, 0x00, 0xF5, 0x78, 0x00 }; -const unsigned char INSTRUMENT_BASSHARP[12] PROGMEM = { 0x00, 0xC0, 0x6D, 0xF9, 0x01, 0x01, 0x0E, 0x41, 0x00, 0xF2, 0x73, 0x00 }; -const unsigned char INSTRUMENT_BASSOON1[12] PROGMEM = { 0x00, 0x30, 0xC8, 0xD5, 0x19, 0x00, 0x0C, 0x71, 0x80, 0x61, 0x1B, 0x00 }; -const unsigned char INSTRUMENT_BASSTRLG[12] PROGMEM = { 0x00, 0xC1, 0x4F, 0xB1, 0x53, 0x03, 0x06, 0xE0, 0x00, 0x12, 0x74, 0x03 }; -const unsigned char INSTRUMENT_BDRUM1[12] PROGMEM = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xA8, 0x4C, 0x00 }; -const unsigned char INSTRUMENT_BELLONG[12] PROGMEM = { 0x00, 0x64, 0xDB, 0xFF, 0x01, 0x00, 0x04, 0x3E, 0xC0, 0xF3, 0x62, 0x00 }; -const unsigned char INSTRUMENT_BELLS[12] PROGMEM = { 0x00, 0x07, 0x4F, 0xF2, 0x60, 0x00, 0x08, 0x12, 0x00, 0xF2, 0x72, 0x00 }; -const unsigned char INSTRUMENT_BELSHORT[12] PROGMEM = { 0x00, 0x64, 0xDB, 0xFF, 0x01, 0x00, 0x04, 0x3E, 0xC0, 0xF5, 0xF3, 0x00 }; -const unsigned char INSTRUMENT_BNCEBASS[12] PROGMEM = { 0x00, 0x20, 0x4B, 0x7B, 0x04, 0x01, 0x0E, 0x21, 0x00, 0xF5, 0x72, 0x00 }; -const unsigned char INSTRUMENT_BRASS1[12] PROGMEM = { 0x00, 0x21, 0x16, 0x71, 0xAE, 0x00, 0x0E, 0x21, 0x00, 0x81, 0x9E, 0x00 }; -const unsigned char INSTRUMENT_CBASSOON[12] PROGMEM = { 0x00, 0x30, 0xC5, 0x52, 0x11, 0x00, 0x00, 0x31, 0x80, 0x31, 0x2E, 0x00 }; -const unsigned char INSTRUMENT_CELESTA[12] PROGMEM = { 0x00, 0x33, 0x87, 0x01, 0x10, 0x00, 0x08, 0x14, 0x80, 0x7D, 0x33, 0x00 }; -const unsigned char INSTRUMENT_CLAR1[12] PROGMEM = { 0x00, 0x32, 0x16, 0x73, 0x24, 0x00, 0x0E, 0x21, 0x80, 0x75, 0x57, 0x00 }; -const unsigned char INSTRUMENT_CLAR2[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x1B, 0x00, 0x0C, 0x60, 0x80, 0x42, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_CLARINET[12] PROGMEM = { 0x00, 0x32, 0x9A, 0x51, 0x1B, 0x00, 0x0C, 0x61, 0x82, 0xA2, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_CLAVECIN[12] PROGMEM = { 0x00, 0x11, 0x0D, 0xF2, 0x01, 0x00, 0x0A, 0x15, 0x0D, 0xF2, 0xB1, 0x00 }; -const unsigned char INSTRUMENT_CROMORNE[12] PROGMEM = { 0x00, 0x00, 0x02, 0xF0, 0xFF, 0x00, 0x06, 0x11, 0x80, 0xF0, 0xFF, 0x00 }; -const unsigned char INSTRUMENT_CYMBAL1[12] PROGMEM = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xF5, 0xB5, 0x00 }; -const unsigned char INSTRUMENT_ELCLAV1[12] PROGMEM = { 0x00, 0x05, 0x8A, 0xF0, 0x7B, 0x00, 0x08, 0x01, 0x80, 0xF4, 0x7B, 0x00 }; -const unsigned char INSTRUMENT_ELCLAV2[12] PROGMEM = { 0x00, 0x01, 0x49, 0xF1, 0x53, 0x01, 0x06, 0x11, 0x00, 0xF1, 0x74, 0x02 }; -const unsigned char INSTRUMENT_ELECFL[12] PROGMEM = { 0x00, 0xE0, 0x6D, 0x57, 0x04, 0x01, 0x0E, 0x61, 0x00, 0x67, 0x7D, 0x00 }; -const unsigned char INSTRUMENT_ELECVIBE[12] PROGMEM = { 0x00, 0x13, 0x97, 0x9A, 0x12, 0x02, 0x0E, 0x91, 0x80, 0x9B, 0x11, 0x00 }; -const unsigned char INSTRUMENT_ELGUIT1[12] PROGMEM = { 0x00, 0xF1, 0x01, 0x97, 0x17, 0x00, 0x08, 0x21, 0x0D, 0xF1, 0x18, 0x00 }; -const unsigned char INSTRUMENT_ELGUIT2[12] PROGMEM = { 0x00, 0x13, 0x96, 0xFF, 0x21, 0x00, 0x0A, 0x11, 0x80, 0xFF, 0x03, 0x00 }; -const unsigned char INSTRUMENT_ELGUIT3[12] PROGMEM = { 0x00, 0x07, 0x8F, 0x82, 0x7D, 0x00, 0x0C, 0x14, 0x80, 0x82, 0x7D, 0x00 }; -const unsigned char INSTRUMENT_ELGUIT4[12] PROGMEM = { 0x00, 0x05, 0x8F, 0xDA, 0x15, 0x00, 0x0A, 0x01, 0x80, 0xF9, 0x14, 0x02 }; -const unsigned char INSTRUMENT_ELORGAN1[12] PROGMEM = { 0x00, 0xB2, 0xCD, 0x91, 0x2A, 0x02, 0x09, 0xB1, 0x80, 0x91, 0x2A, 0x01 }; -const unsigned char INSTRUMENT_ELPIANO1[12] PROGMEM = { 0x00, 0x01, 0x4F, 0xF1, 0x50, 0x00, 0x06, 0x01, 0x04, 0xD2, 0x7C, 0x00 }; -const unsigned char INSTRUMENT_ELPIANO2[12] PROGMEM = { 0x00, 0x02, 0x22, 0xF2, 0x13, 0x00, 0x0E, 0x02, 0x00, 0xF5, 0x43, 0x00 }; -const unsigned char INSTRUMENT_EPIANO1A[12] PROGMEM = { 0x00, 0x81, 0x63, 0xF3, 0x58, 0x00, 0x00, 0x01, 0x80, 0xF2, 0x58, 0x00 }; -const unsigned char INSTRUMENT_EPIANO1B[12] PROGMEM = { 0x00, 0x07, 0x1F, 0xF5, 0xFA, 0x00, 0x0E, 0x01, 0x57, 0xF5, 0xFA, 0x00 }; -const unsigned char INSTRUMENT_FLUTE[12] PROGMEM = { 0x00, 0x21, 0x83, 0x74, 0x17, 0x00, 0x07, 0xA2, 0x8D, 0x65, 0x17, 0x00 }; -const unsigned char INSTRUMENT_FLUTE1[12] PROGMEM = { 0x00, 0xA1, 0x27, 0x74, 0x8F, 0x00, 0x02, 0xA1, 0x80, 0x65, 0x2A, 0x00 }; -const unsigned char INSTRUMENT_FLUTE2[12] PROGMEM = { 0x00, 0xE0, 0xEC, 0x6E, 0x8F, 0x00, 0x0E, 0x61, 0x00, 0x65, 0x2A, 0x00 }; -const unsigned char INSTRUMENT_FRHORN1[12] PROGMEM = { 0x00, 0x21, 0x9F, 0x53, 0x5A, 0x00, 0x0C, 0x21, 0x80, 0xAA, 0x1A, 0x00 }; -const unsigned char INSTRUMENT_FRHORN2[12] PROGMEM = { 0x00, 0x20, 0x8E, 0xA5, 0x8F, 0x02, 0x06, 0x21, 0x00, 0x36, 0x3D, 0x00 }; -const unsigned char INSTRUMENT_FSTRP1[12] PROGMEM = { 0x00, 0xF0, 0x18, 0x55, 0xEF, 0x02, 0x00, 0xE0, 0x80, 0x87, 0x1E, 0x03 }; -const unsigned char INSTRUMENT_FSTRP2[12] PROGMEM = { 0x00, 0x70, 0x16, 0x55, 0x2F, 0x02, 0x0C, 0xE0, 0x80, 0x87, 0x1E, 0x03 }; -const unsigned char INSTRUMENT_FUZGUIT1[12] PROGMEM = { 0x00, 0xF1, 0x00, 0x97, 0x13, 0x00, 0x0A, 0x25, 0x0D, 0xF1, 0x18, 0x01 }; -const unsigned char INSTRUMENT_FUZGUIT2[12] PROGMEM = { 0x00, 0x31, 0x48, 0xF1, 0x53, 0x00, 0x06, 0x32, 0x00, 0xF2, 0x27, 0x02 }; -const unsigned char INSTRUMENT_GUITAR1[12] PROGMEM = { 0x00, 0x01, 0x11, 0xF2, 0x1F, 0x00, 0x0A, 0x01, 0x00, 0xF5, 0x88, 0x00 }; -const unsigned char INSTRUMENT_HARP1[12] PROGMEM = { 0x00, 0x02, 0x29, 0xF5, 0x75, 0x00, 0x00, 0x01, 0x83, 0xF2, 0xF3, 0x00 }; -const unsigned char INSTRUMENT_HARP2[12] PROGMEM = { 0x00, 0x02, 0x99, 0xF5, 0x55, 0x00, 0x00, 0x01, 0x80, 0xF6, 0x53, 0x00 }; -const unsigned char INSTRUMENT_HARP3[12] PROGMEM = { 0x00, 0x02, 0x57, 0xF5, 0x56, 0x00, 0x00, 0x01, 0x80, 0xF6, 0x54, 0x00 }; -const unsigned char INSTRUMENT_HARPE1[12] PROGMEM = { 0x00, 0x02, 0x29, 0xF5, 0x75, 0x00, 0x00, 0x01, 0x03, 0xF2, 0xF3, 0x00 }; -const unsigned char INSTRUMENT_HARPSI1[12] PROGMEM = { 0x00, 0x32, 0x87, 0xA1, 0x10, 0x00, 0x08, 0x16, 0x80, 0x7D, 0x33, 0x00 }; -const unsigned char INSTRUMENT_HARPSI2[12] PROGMEM = { 0x00, 0x33, 0x87, 0xA1, 0x10, 0x00, 0x06, 0x15, 0x80, 0x7D, 0x43, 0x00 }; -const unsigned char INSTRUMENT_HARPSI3[12] PROGMEM = { 0x00, 0x35, 0x84, 0xA8, 0x10, 0x00, 0x08, 0x18, 0x80, 0x7D, 0x33, 0x00 }; -const unsigned char INSTRUMENT_HARPSI4[12] PROGMEM = { 0x00, 0x11, 0x0D, 0xF2, 0x01, 0x00, 0x0A, 0x15, 0x0D, 0xF2, 0xB1, 0x00 }; -const unsigned char INSTRUMENT_HARPSI5[12] PROGMEM = { 0x00, 0x36, 0x87, 0x8A, 0x00, 0x00, 0x08, 0x1A, 0x80, 0x7F, 0x33, 0x00 }; -const unsigned char INSTRUMENT_HELICPTR[12] PROGMEM = { 0x00, 0xF0, 0x00, 0x1E, 0x11, 0x01, 0x08, 0xE2, 0xC0, 0x11, 0x11, 0x01 }; -const unsigned char INSTRUMENT_HIHAT1[12] PROGMEM = { 0x0A, 0x01, 0x00, 0xF7, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_HIHAT2[12] PROGMEM = { 0x0A, 0x01, 0x03, 0xDA, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_JAVAICAN[12] PROGMEM = { 0x00, 0x87, 0x4D, 0x78, 0x42, 0x00, 0x0A, 0x94, 0x00, 0x85, 0x54, 0x00 }; -const unsigned char INSTRUMENT_JAZZGUIT[12] PROGMEM = { 0x00, 0x03, 0x5E, 0x85, 0x51, 0x01, 0x0E, 0x11, 0x00, 0xD2, 0x71, 0x00 }; -const unsigned char INSTRUMENT_JEWSHARP[12] PROGMEM = { 0x00, 0x00, 0x50, 0xF2, 0x70, 0x00, 0x0E, 0x13, 0x00, 0xF2, 0x72, 0x00 }; -const unsigned char INSTRUMENT_KEYBRD1[12] PROGMEM = { 0x00, 0x00, 0x02, 0xF0, 0xFA, 0x01, 0x06, 0x11, 0x80, 0xF2, 0xFA, 0x01 }; -const unsigned char INSTRUMENT_KEYBRD2[12] PROGMEM = { 0x00, 0x01, 0x8F, 0xF2, 0xBD, 0x00, 0x08, 0x14, 0x80, 0x82, 0xBD, 0x00 }; -const unsigned char INSTRUMENT_KEYBRD3[12] PROGMEM = { 0x00, 0x01, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0xE4, 0x03, 0xF3, 0x36, 0x00 }; -const unsigned char INSTRUMENT_LASER[12] PROGMEM = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x25, 0xB5, 0x00 }; -const unsigned char INSTRUMENT_LOGDRUM1[12] PROGMEM = { 0x00, 0x32, 0x44, 0xF8, 0xFF, 0x00, 0x0E, 0x11, 0x00, 0xF5, 0x7F, 0x00 }; -const unsigned char INSTRUMENT_MARIMBA1[12] PROGMEM = { 0x00, 0x05, 0x4E, 0xDA, 0x25, 0x00, 0x0A, 0x01, 0x00, 0xF9, 0x15, 0x00 }; -const unsigned char INSTRUMENT_MARIMBA2[12] PROGMEM = { 0x00, 0x85, 0x4E, 0xDA, 0x15, 0x00, 0x0A, 0x81, 0x80, 0xF9, 0x13, 0x00 }; -const unsigned char INSTRUMENT_MDRNPHON[12] PROGMEM = { 0x00, 0x30, 0x00, 0xFE, 0x11, 0x01, 0x08, 0xAE, 0xC0, 0xF1, 0x19, 0x01 }; -const unsigned char INSTRUMENT_MLTRDRUM[12] PROGMEM = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xC8, 0xB6, 0x01 }; -const unsigned char INSTRUMENT_MOOGSYNT[12] PROGMEM = { 0x00, 0x20, 0x90, 0xF5, 0x9E, 0x02, 0x0C, 0x11, 0x00, 0xF4, 0x5B, 0x03 }; -const unsigned char INSTRUMENT_NOISE1[12] PROGMEM = { 0x00, 0x0E, 0x40, 0xD1, 0x53, 0x00, 0x0E, 0x0E, 0x00, 0xF2, 0x7F, 0x03 }; -const unsigned char INSTRUMENT_OBOE1[12] PROGMEM = { 0x00, 0xB1, 0xC5, 0x6E, 0x17, 0x00, 0x02, 0x22, 0x05, 0x8B, 0x0E, 0x00 }; -const unsigned char INSTRUMENT_ORGAN1[12] PROGMEM = { 0x00, 0x65, 0xD2, 0x81, 0x03, 0x00, 0x02, 0x71, 0x80, 0xF1, 0x05, 0x00 }; -const unsigned char INSTRUMENT_ORGAN2[12] PROGMEM = { 0x00, 0x24, 0x80, 0xFF, 0x0F, 0x00, 0x01, 0x21, 0x80, 0xFF, 0x0F, 0x00 }; -const unsigned char INSTRUMENT_ORGAN3[12] PROGMEM = { 0x00, 0x03, 0x5B, 0xF0, 0x1F, 0x00, 0x0A, 0x01, 0x80, 0xF0, 0x1F, 0x00 }; -const unsigned char INSTRUMENT_ORGAN3A[12] PROGMEM = { 0x00, 0x03, 0x5B, 0xF0, 0x1F, 0x00, 0x0A, 0x01, 0x8D, 0xF0, 0x13, 0x00 }; -const unsigned char INSTRUMENT_ORGAN3B[12] PROGMEM = { 0x00, 0x03, 0x5B, 0xF0, 0x1F, 0x00, 0x0A, 0x01, 0x92, 0xF0, 0x12, 0x00 }; -const unsigned char INSTRUMENT_ORGNPERC[12] PROGMEM = { 0x00, 0x0C, 0x00, 0xF8, 0xB5, 0x00, 0x01, 0x00, 0x00, 0xD6, 0x4F, 0x00 }; -const unsigned char INSTRUMENT_PHONE1[12] PROGMEM = { 0x00, 0x17, 0x4F, 0xF2, 0x61, 0x00, 0x08, 0x12, 0x08, 0xF1, 0xB2, 0x00 }; -const unsigned char INSTRUMENT_PHONE2[12] PROGMEM = { 0x00, 0x17, 0x4F, 0xF2, 0x61, 0x00, 0x08, 0x12, 0x0A, 0xF1, 0xB4, 0x00 }; -const unsigned char INSTRUMENT_PIAN1A[12] PROGMEM = { 0x00, 0x81, 0x63, 0xF3, 0x58, 0x00, 0x00, 0x01, 0x80, 0xF2, 0x58, 0x00 }; -const unsigned char INSTRUMENT_PIAN1B[12] PROGMEM = { 0x00, 0x07, 0x1F, 0xF5, 0xFA, 0x00, 0x0E, 0x01, 0x26, 0xF5, 0xFA, 0x00 }; -const unsigned char INSTRUMENT_PIAN1C[12] PROGMEM = { 0x00, 0x07, 0x1F, 0xF5, 0xFA, 0x00, 0x0E, 0x01, 0x57, 0xF5, 0xFA, 0x00 }; -const unsigned char INSTRUMENT_PIANO[12] PROGMEM = { 0x00, 0x03, 0x4F, 0xF1, 0x53, 0x00, 0x06, 0x17, 0x00, 0xF2, 0x74, 0x00 }; -const unsigned char INSTRUMENT_PIANO1[12] PROGMEM = { 0x00, 0x01, 0x4F, 0xF1, 0x53, 0x00, 0x06, 0x11, 0x00, 0xD2, 0x74, 0x00 }; -const unsigned char INSTRUMENT_PIANO2[12] PROGMEM = { 0x00, 0x41, 0x9D, 0xF2, 0x51, 0x00, 0x06, 0x13, 0x00, 0xF2, 0xF1, 0x00 }; -const unsigned char INSTRUMENT_PIANO3[12] PROGMEM = { 0x00, 0x01, 0x4F, 0xF1, 0x50, 0x00, 0x06, 0x01, 0x04, 0xD2, 0x7C, 0x00 }; -const unsigned char INSTRUMENT_PIANO4[12] PROGMEM = { 0x00, 0x01, 0x4D, 0xF1, 0x60, 0x00, 0x08, 0x11, 0x00, 0xD2, 0x7B, 0x00 }; -const unsigned char INSTRUMENT_PIANOBEL[12] PROGMEM = { 0x00, 0x03, 0x4F, 0xF1, 0x53, 0x00, 0x06, 0x17, 0x03, 0xF2, 0x74, 0x00 }; -const unsigned char INSTRUMENT_PIANOF[12] PROGMEM = { 0x00, 0x01, 0xCF, 0xF1, 0x53, 0x00, 0x02, 0x12, 0x00, 0xF2, 0x83, 0x00 }; -const unsigned char INSTRUMENT_POPBASS1[12] PROGMEM = { 0x00, 0x10, 0x00, 0x75, 0x93, 0x01, 0x00, 0x01, 0x00, 0xF5, 0x82, 0x01 }; -const unsigned char INSTRUMENT_RKSNARE1[12] PROGMEM = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xC7, 0xB4, 0x00 }; -const unsigned char INSTRUMENT_SAX1[12] PROGMEM = { 0x00, 0x01, 0x4F, 0x71, 0x53, 0x00, 0x0A, 0x12, 0x00, 0x52, 0x7C, 0x00 }; -const unsigned char INSTRUMENT_SCRATCH[12] PROGMEM = { 0x00, 0x07, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x5C, 0xDC, 0x00 }; -const unsigned char INSTRUMENT_SCRATCH4[12] PROGMEM = { 0x00, 0x07, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x5C, 0xDC, 0x00 }; -const unsigned char INSTRUMENT_SDRUM2[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xF6, 0xB4, 0x00 }; -const unsigned char INSTRUMENT_SHRTVIBE[12] PROGMEM = { 0x00, 0xE4, 0x0E, 0xFF, 0x3F, 0x01, 0x00, 0xC0, 0x00, 0xF3, 0x07, 0x00 }; -const unsigned char INSTRUMENT_SITAR1[12] PROGMEM = { 0x00, 0x01, 0x40, 0xF1, 0x53, 0x00, 0x00, 0x08, 0x40, 0xF1, 0x53, 0x00 }; -const unsigned char INSTRUMENT_SITAR2[12] PROGMEM = { 0x00, 0x01, 0x40, 0xF1, 0x53, 0x00, 0x00, 0x08, 0x40, 0xF1, 0x53, 0x01 }; -const unsigned char INSTRUMENT_SNAKEFL[12] PROGMEM = { 0x00, 0x61, 0x0C, 0x81, 0x03, 0x00, 0x08, 0x71, 0x80, 0x61, 0x0C, 0x00 }; -const unsigned char INSTRUMENT_SNARE1[12] PROGMEM = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xF8, 0xB5, 0x00 }; -const unsigned char INSTRUMENT_SNRSUST[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0xC4, 0x03, 0xC4, 0x34, 0x00 }; -const unsigned char INSTRUMENT_SOLOVLN[12] PROGMEM = { 0x00, 0x70, 0x1C, 0x51, 0x03, 0x02, 0x0E, 0x20, 0x00, 0x54, 0x67, 0x02 }; -const unsigned char INSTRUMENT_STEELGT1[12] PROGMEM = { 0x00, 0x01, 0x46, 0xF1, 0x83, 0x00, 0x06, 0x61, 0x03, 0x31, 0x86, 0x00 }; -const unsigned char INSTRUMENT_STEELGT2[12] PROGMEM = { 0x00, 0x01, 0x47, 0xF1, 0x83, 0x00, 0x06, 0x61, 0x03, 0x91, 0x86, 0x00 }; -const unsigned char INSTRUMENT_STRINGS1[12] PROGMEM = { 0x00, 0xB1, 0x8B, 0x71, 0x11, 0x00, 0x06, 0x61, 0x40, 0x42, 0x15, 0x01 }; -const unsigned char INSTRUMENT_STRNLONG[12] PROGMEM = { 0x00, 0xE1, 0x4F, 0xB1, 0xD3, 0x03, 0x06, 0x21, 0x00, 0x12, 0x74, 0x01 }; -const unsigned char INSTRUMENT_SYN1[12] PROGMEM = { 0x00, 0x55, 0x97, 0x2A, 0x02, 0x00, 0x00, 0x12, 0x80, 0x42, 0xF3, 0x00 }; -const unsigned char INSTRUMENT_SYN2[12] PROGMEM = { 0x00, 0x13, 0x97, 0x9A, 0x12, 0x00, 0x0E, 0x11, 0x80, 0x9B, 0x14, 0x00 }; -const unsigned char INSTRUMENT_SYN3[12] PROGMEM = { 0x00, 0x11, 0x8A, 0xF1, 0x11, 0x00, 0x06, 0x01, 0x40, 0xF1, 0xB3, 0x00 }; -const unsigned char INSTRUMENT_SYN4[12] PROGMEM = { 0x00, 0x21, 0x0D, 0xE9, 0x3A, 0x00, 0x0A, 0x22, 0x80, 0x65, 0x6C, 0x00 }; -const unsigned char INSTRUMENT_SYN5[12] PROGMEM = { 0x00, 0x01, 0x4F, 0x71, 0x53, 0x00, 0x06, 0x19, 0x00, 0x52, 0x7C, 0x00 }; -const unsigned char INSTRUMENT_SYN6[12] PROGMEM = { 0x00, 0x24, 0x0F, 0x41, 0x7E, 0x00, 0x0A, 0x21, 0x00, 0xF1, 0x5E, 0x00 }; -const unsigned char INSTRUMENT_SYN9[12] PROGMEM = { 0x00, 0x07, 0x87, 0xF0, 0x05, 0x00, 0x04, 0x01, 0x80, 0xF0, 0x05, 0x00 }; -const unsigned char INSTRUMENT_SYNBAL1[12] PROGMEM = { 0x00, 0x26, 0x03, 0xE0, 0xF0, 0x00, 0x08, 0x1E, 0x00, 0xFF, 0x31, 0x00 }; -const unsigned char INSTRUMENT_SYNBAL2[12] PROGMEM = { 0x00, 0x28, 0x03, 0xE0, 0xF0, 0x00, 0x04, 0x13, 0x00, 0xE8, 0x11, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS1[12] PROGMEM = { 0x00, 0x30, 0x88, 0xD5, 0x19, 0x00, 0x0C, 0x71, 0x80, 0x61, 0x1B, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS2[12] PROGMEM = { 0x00, 0x81, 0x86, 0x65, 0x01, 0x00, 0x0C, 0x11, 0x00, 0x32, 0x74, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS4[12] PROGMEM = { 0x00, 0x81, 0x83, 0x65, 0x05, 0x00, 0x0A, 0x51, 0x00, 0x32, 0x74, 0x00 }; -const unsigned char INSTRUMENT_SYNSNR1[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xF8, 0xB6, 0x00 }; -const unsigned char INSTRUMENT_SYNSNR2[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xF6, 0xB4, 0x00 }; -const unsigned char INSTRUMENT_TINCAN1[12] PROGMEM = { 0x00, 0x8F, 0x81, 0xEF, 0x01, 0x00, 0x04, 0x01, 0x00, 0x98, 0xF1, 0x00 }; -const unsigned char INSTRUMENT_TOM1[12] PROGMEM = { 0x08, 0x04, 0x00, 0xF7, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_TOM2[12] PROGMEM = { 0x08, 0x02, 0x00, 0xC8, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_TRAINBEL[12] PROGMEM = { 0x00, 0x17, 0x4F, 0xF2, 0x61, 0x00, 0x08, 0x12, 0x08, 0xF2, 0x74, 0x00 }; -const unsigned char INSTRUMENT_TRIANGLE[12] PROGMEM = { 0x00, 0x26, 0x03, 0xE0, 0xF0, 0x00, 0x08, 0x1E, 0x00, 0xFF, 0x31, 0x00 }; -const unsigned char INSTRUMENT_TROMB1[12] PROGMEM = { 0x00, 0xB1, 0x1C, 0x41, 0x1F, 0x00, 0x0E, 0x61, 0x80, 0x92, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_TROMB2[12] PROGMEM = { 0x00, 0x21, 0x1C, 0x53, 0x1D, 0x00, 0x0C, 0x61, 0x80, 0x52, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_TRUMPET1[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x0B, 0x00, 0x0E, 0x61, 0x80, 0x92, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_TRUMPET2[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x23, 0x1D, 0x00, 0x0C, 0x61, 0x80, 0x52, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_TRUMPET3[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x01, 0x00, 0x0E, 0x61, 0x80, 0x92, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_TRUMPET4[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x0B, 0x00, 0x0C, 0x61, 0x80, 0x92, 0x3B, 0x00 }; -const unsigned char INSTRUMENT_TUBA1[12] PROGMEM = { 0x00, 0x21, 0x19, 0x43, 0x8C, 0x00, 0x0C, 0x21, 0x80, 0x85, 0x2F, 0x00 }; -const unsigned char INSTRUMENT_VIBRA1[12] PROGMEM = { 0x00, 0x84, 0x53, 0xF5, 0x33, 0x00, 0x06, 0xA0, 0x80, 0xFD, 0x25, 0x00 }; -const unsigned char INSTRUMENT_VIBRA2[12] PROGMEM = { 0x00, 0x06, 0x73, 0xF6, 0x54, 0x00, 0x00, 0x81, 0x03, 0xF2, 0xB3, 0x00 }; -const unsigned char INSTRUMENT_VIBRA3[12] PROGMEM = { 0x00, 0x93, 0x97, 0xAA, 0x12, 0x02, 0x0E, 0x91, 0x80, 0xAC, 0x21, 0x00 }; -const unsigned char INSTRUMENT_VIOLIN1[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x51, 0x03, 0x00, 0x0E, 0x61, 0x80, 0x54, 0x67, 0x00 }; -const unsigned char INSTRUMENT_VIOLIN2[12] PROGMEM = { 0x00, 0xE1, 0x88, 0x62, 0x29, 0x00, 0x0C, 0x22, 0x80, 0x53, 0x2C, 0x00 }; -const unsigned char INSTRUMENT_VIOLIN3[12] PROGMEM = { 0x00, 0xE1, 0x88, 0x64, 0x29, 0x00, 0x06, 0x22, 0x83, 0x53, 0x2C, 0x00 }; -const unsigned char INSTRUMENT_VLNPIZZ1[12] PROGMEM = { 0x00, 0x31, 0x9C, 0xF1, 0xF9, 0x00, 0x0E, 0x31, 0x80, 0xF7, 0xE6, 0x00 }; -const unsigned char INSTRUMENT_WAVE[12] PROGMEM = { 0x00, 0x00, 0x02, 0x00, 0xF0, 0x00, 0x0E, 0x14, 0x80, 0x1B, 0xA2, 0x00 }; -const unsigned char INSTRUMENT_XYLO1[12] PROGMEM = { 0x00, 0x11, 0x2D, 0xC8, 0x2F, 0x00, 0x0C, 0x31, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_XYLO2[12] PROGMEM = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0xFF, 0x0F, 0x00 }; -const unsigned char INSTRUMENT_XYLO3[12] PROGMEM = { 0x00, 0x06, 0x00, 0xFF, 0xF0, 0x00, 0x0E, 0xC4, 0x00, 0xF8, 0xB5, 0x00 }; +#ifndef _ADLIB_INST_H_ + #define _ADLIB_INST_H_ + + const unsigned char INSTRUMENT_ACCORDN[12] PROGMEM = { 0x00, 0x24, 0x4F, 0xF2, 0x0B, 0x00, 0x0E, 0x31, 0x00, 0x52, 0x0B, 0x00 }; + const unsigned char INSTRUMENT_BAGPIPE1[12] PROGMEM = { 0x00, 0x31, 0x43, 0x6E, 0x17, 0x01, 0x02, 0x22, 0x05, 0x8B, 0x0C, 0x02 }; + const unsigned char INSTRUMENT_BAGPIPE2[12] PROGMEM = { 0x00, 0x30, 0x00, 0xFF, 0xA0, 0x03, 0x00, 0xA3, 0x00, 0x65, 0x0B, 0x02 }; + const unsigned char INSTRUMENT_BANJO1[12] PROGMEM = { 0x00, 0x31, 0x87, 0xA1, 0x11, 0x00, 0x08, 0x16, 0x80, 0x7D, 0x43, 0x00 }; + const unsigned char INSTRUMENT_BASS1[12] PROGMEM = { 0x00, 0x01, 0x15, 0x25, 0x2F, 0x00, 0x0A, 0x21, 0x80, 0x65, 0x6C, 0x00 }; + const unsigned char INSTRUMENT_BASS2[12] PROGMEM = { 0x00, 0x01, 0x1D, 0xF2, 0xEF, 0x00, 0x0A, 0x01, 0x00, 0xF5, 0x78, 0x00 }; + const unsigned char INSTRUMENT_BASSHARP[12] PROGMEM = { 0x00, 0xC0, 0x6D, 0xF9, 0x01, 0x01, 0x0E, 0x41, 0x00, 0xF2, 0x73, 0x00 }; + const unsigned char INSTRUMENT_BASSOON1[12] PROGMEM = { 0x00, 0x30, 0xC8, 0xD5, 0x19, 0x00, 0x0C, 0x71, 0x80, 0x61, 0x1B, 0x00 }; + const unsigned char INSTRUMENT_BASSTRLG[12] PROGMEM = { 0x00, 0xC1, 0x4F, 0xB1, 0x53, 0x03, 0x06, 0xE0, 0x00, 0x12, 0x74, 0x03 }; + const unsigned char INSTRUMENT_BDRUM1[12] PROGMEM = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xA8, 0x4C, 0x00 }; + const unsigned char INSTRUMENT_BDRUM2[12] PROGMEM = { 0x06, 0x00, 0x0B, 0xA8, 0x4C, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x4C, 0x00 }; + const unsigned char INSTRUMENT_BELLONG[12] PROGMEM = { 0x00, 0x64, 0xDB, 0xFF, 0x01, 0x00, 0x04, 0x3E, 0xC0, 0xF3, 0x62, 0x00 }; + const unsigned char INSTRUMENT_BELLS[12] PROGMEM = { 0x00, 0x07, 0x4F, 0xF2, 0x60, 0x00, 0x08, 0x12, 0x00, 0xF2, 0x72, 0x00 }; + const unsigned char INSTRUMENT_BELSHORT[12] PROGMEM = { 0x00, 0x64, 0xDB, 0xFF, 0x01, 0x00, 0x04, 0x3E, 0xC0, 0xF5, 0xF3, 0x00 }; + const unsigned char INSTRUMENT_BNCEBASS[12] PROGMEM = { 0x00, 0x20, 0x4B, 0x7B, 0x04, 0x01, 0x0E, 0x21, 0x00, 0xF5, 0x72, 0x00 }; + const unsigned char INSTRUMENT_BRASS1[12] PROGMEM = { 0x00, 0x21, 0x16, 0x71, 0xAE, 0x00, 0x0E, 0x21, 0x00, 0x81, 0x9E, 0x00 }; + const unsigned char INSTRUMENT_CBASSOON[12] PROGMEM = { 0x00, 0x30, 0xC5, 0x52, 0x11, 0x00, 0x00, 0x31, 0x80, 0x31, 0x2E, 0x00 }; + const unsigned char INSTRUMENT_CELESTA[12] PROGMEM = { 0x00, 0x33, 0x87, 0x01, 0x10, 0x00, 0x08, 0x14, 0x80, 0x7D, 0x33, 0x00 }; + const unsigned char INSTRUMENT_CLAR1[12] PROGMEM = { 0x00, 0x32, 0x16, 0x73, 0x24, 0x00, 0x0E, 0x21, 0x80, 0x75, 0x57, 0x00 }; + const unsigned char INSTRUMENT_CLAR2[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x1B, 0x00, 0x0C, 0x60, 0x80, 0x42, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_CLARINET[12] PROGMEM = { 0x00, 0x32, 0x9A, 0x51, 0x1B, 0x00, 0x0C, 0x61, 0x82, 0xA2, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_CLAVECIN[12] PROGMEM = { 0x00, 0x11, 0x0D, 0xF2, 0x01, 0x00, 0x0A, 0x15, 0x0D, 0xF2, 0xB1, 0x00 }; + const unsigned char INSTRUMENT_CROMORNE[12] PROGMEM = { 0x00, 0x00, 0x02, 0xF0, 0xFF, 0x00, 0x06, 0x11, 0x80, 0xF0, 0xFF, 0x00 }; + const unsigned char INSTRUMENT_CYMBAL1[12] PROGMEM = { 0x09, 0x01, 0x00, 0xF5, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_ELCLAV1[12] PROGMEM = { 0x00, 0x05, 0x8A, 0xF0, 0x7B, 0x00, 0x08, 0x01, 0x80, 0xF4, 0x7B, 0x00 }; + const unsigned char INSTRUMENT_ELCLAV2[12] PROGMEM = { 0x00, 0x01, 0x49, 0xF1, 0x53, 0x01, 0x06, 0x11, 0x00, 0xF1, 0x74, 0x02 }; + const unsigned char INSTRUMENT_ELECFL[12] PROGMEM = { 0x00, 0xE0, 0x6D, 0x57, 0x04, 0x01, 0x0E, 0x61, 0x00, 0x67, 0x7D, 0x00 }; + const unsigned char INSTRUMENT_ELECVIBE[12] PROGMEM = { 0x00, 0x13, 0x97, 0x9A, 0x12, 0x02, 0x0E, 0x91, 0x80, 0x9B, 0x11, 0x00 }; + const unsigned char INSTRUMENT_ELGUIT1[12] PROGMEM = { 0x00, 0xF1, 0x01, 0x97, 0x17, 0x00, 0x08, 0x21, 0x0D, 0xF1, 0x18, 0x00 }; + const unsigned char INSTRUMENT_ELGUIT2[12] PROGMEM = { 0x00, 0x13, 0x96, 0xFF, 0x21, 0x00, 0x0A, 0x11, 0x80, 0xFF, 0x03, 0x00 }; + const unsigned char INSTRUMENT_ELGUIT3[12] PROGMEM = { 0x00, 0x07, 0x8F, 0x82, 0x7D, 0x00, 0x0C, 0x14, 0x80, 0x82, 0x7D, 0x00 }; + const unsigned char INSTRUMENT_ELGUIT4[12] PROGMEM = { 0x00, 0x05, 0x8F, 0xDA, 0x15, 0x00, 0x0A, 0x01, 0x80, 0xF9, 0x14, 0x02 }; + const unsigned char INSTRUMENT_ELORGAN1[12] PROGMEM = { 0x00, 0xB2, 0xCD, 0x91, 0x2A, 0x02, 0x09, 0xB1, 0x80, 0x91, 0x2A, 0x01 }; + const unsigned char INSTRUMENT_ELPIANO1[12] PROGMEM = { 0x00, 0x01, 0x4F, 0xF1, 0x50, 0x00, 0x06, 0x01, 0x04, 0xD2, 0x7C, 0x00 }; + const unsigned char INSTRUMENT_ELPIANO2[12] PROGMEM = { 0x00, 0x02, 0x22, 0xF2, 0x13, 0x00, 0x0E, 0x02, 0x00, 0xF5, 0x43, 0x00 }; + const unsigned char INSTRUMENT_EPIANO1A[12] PROGMEM = { 0x00, 0x81, 0x63, 0xF3, 0x58, 0x00, 0x00, 0x01, 0x80, 0xF2, 0x58, 0x00 }; + const unsigned char INSTRUMENT_EPIANO1B[12] PROGMEM = { 0x00, 0x07, 0x1F, 0xF5, 0xFA, 0x00, 0x0E, 0x01, 0x57, 0xF5, 0xFA, 0x00 }; + const unsigned char INSTRUMENT_FLUTE[12] PROGMEM = { 0x00, 0x21, 0x83, 0x74, 0x17, 0x00, 0x07, 0xA2, 0x8D, 0x65, 0x17, 0x00 }; + const unsigned char INSTRUMENT_FLUTE1[12] PROGMEM = { 0x00, 0xA1, 0x27, 0x74, 0x8F, 0x00, 0x02, 0xA1, 0x80, 0x65, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_FLUTE2[12] PROGMEM = { 0x00, 0xE0, 0xEC, 0x6E, 0x8F, 0x00, 0x0E, 0x61, 0x00, 0x65, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_FRHORN1[12] PROGMEM = { 0x00, 0x21, 0x9F, 0x53, 0x5A, 0x00, 0x0C, 0x21, 0x80, 0xAA, 0x1A, 0x00 }; + const unsigned char INSTRUMENT_FRHORN2[12] PROGMEM = { 0x00, 0x20, 0x8E, 0xA5, 0x8F, 0x02, 0x06, 0x21, 0x00, 0x36, 0x3D, 0x00 }; + const unsigned char INSTRUMENT_FSTRP1[12] PROGMEM = { 0x00, 0xF0, 0x18, 0x55, 0xEF, 0x02, 0x00, 0xE0, 0x80, 0x87, 0x1E, 0x03 }; + const unsigned char INSTRUMENT_FSTRP2[12] PROGMEM = { 0x00, 0x70, 0x16, 0x55, 0x2F, 0x02, 0x0C, 0xE0, 0x80, 0x87, 0x1E, 0x03 }; + const unsigned char INSTRUMENT_FUZGUIT1[12] PROGMEM = { 0x00, 0xF1, 0x00, 0x97, 0x13, 0x00, 0x0A, 0x25, 0x0D, 0xF1, 0x18, 0x01 }; + const unsigned char INSTRUMENT_FUZGUIT2[12] PROGMEM = { 0x00, 0x31, 0x48, 0xF1, 0x53, 0x00, 0x06, 0x32, 0x00, 0xF2, 0x27, 0x02 }; + const unsigned char INSTRUMENT_GUITAR1[12] PROGMEM = { 0x00, 0x01, 0x11, 0xF2, 0x1F, 0x00, 0x0A, 0x01, 0x00, 0xF5, 0x88, 0x00 }; + const unsigned char INSTRUMENT_HARP1[12] PROGMEM = { 0x00, 0x02, 0x29, 0xF5, 0x75, 0x00, 0x00, 0x01, 0x83, 0xF2, 0xF3, 0x00 }; + const unsigned char INSTRUMENT_HARP2[12] PROGMEM = { 0x00, 0x02, 0x99, 0xF5, 0x55, 0x00, 0x00, 0x01, 0x80, 0xF6, 0x53, 0x00 }; + const unsigned char INSTRUMENT_HARP3[12] PROGMEM = { 0x00, 0x02, 0x57, 0xF5, 0x56, 0x00, 0x00, 0x01, 0x80, 0xF6, 0x54, 0x00 }; + const unsigned char INSTRUMENT_HARPE1[12] PROGMEM = { 0x00, 0x02, 0x29, 0xF5, 0x75, 0x00, 0x00, 0x01, 0x03, 0xF2, 0xF3, 0x00 }; + const unsigned char INSTRUMENT_HARPSI1[12] PROGMEM = { 0x00, 0x32, 0x87, 0xA1, 0x10, 0x00, 0x08, 0x16, 0x80, 0x7D, 0x33, 0x00 }; + const unsigned char INSTRUMENT_HARPSI2[12] PROGMEM = { 0x00, 0x33, 0x87, 0xA1, 0x10, 0x00, 0x06, 0x15, 0x80, 0x7D, 0x43, 0x00 }; + const unsigned char INSTRUMENT_HARPSI3[12] PROGMEM = { 0x00, 0x35, 0x84, 0xA8, 0x10, 0x00, 0x08, 0x18, 0x80, 0x7D, 0x33, 0x00 }; + const unsigned char INSTRUMENT_HARPSI4[12] PROGMEM = { 0x00, 0x11, 0x0D, 0xF2, 0x01, 0x00, 0x0A, 0x15, 0x0D, 0xF2, 0xB1, 0x00 }; + const unsigned char INSTRUMENT_HARPSI5[12] PROGMEM = { 0x00, 0x36, 0x87, 0x8A, 0x00, 0x00, 0x08, 0x1A, 0x80, 0x7F, 0x33, 0x00 }; + const unsigned char INSTRUMENT_HELICPTR[12] PROGMEM = { 0x00, 0xF0, 0x00, 0x1E, 0x11, 0x01, 0x08, 0xE2, 0xC0, 0x11, 0x11, 0x01 }; + const unsigned char INSTRUMENT_HIHAT1[12] PROGMEM = { 0x0A, 0x01, 0x00, 0xF7, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_HIHAT2[12] PROGMEM = { 0x0A, 0x01, 0x03, 0xDA, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_JAVAICAN[12] PROGMEM = { 0x00, 0x87, 0x4D, 0x78, 0x42, 0x00, 0x0A, 0x94, 0x00, 0x85, 0x54, 0x00 }; + const unsigned char INSTRUMENT_JAZZGUIT[12] PROGMEM = { 0x00, 0x03, 0x5E, 0x85, 0x51, 0x01, 0x0E, 0x11, 0x00, 0xD2, 0x71, 0x00 }; + const unsigned char INSTRUMENT_JEWSHARP[12] PROGMEM = { 0x00, 0x00, 0x50, 0xF2, 0x70, 0x00, 0x0E, 0x13, 0x00, 0xF2, 0x72, 0x00 }; + const unsigned char INSTRUMENT_KEYBRD1[12] PROGMEM = { 0x00, 0x00, 0x02, 0xF0, 0xFA, 0x01, 0x06, 0x11, 0x80, 0xF2, 0xFA, 0x01 }; + const unsigned char INSTRUMENT_KEYBRD2[12] PROGMEM = { 0x00, 0x01, 0x8F, 0xF2, 0xBD, 0x00, 0x08, 0x14, 0x80, 0x82, 0xBD, 0x00 }; + const unsigned char INSTRUMENT_KEYBRD3[12] PROGMEM = { 0x00, 0x01, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0xE4, 0x03, 0xF3, 0x36, 0x00 }; + const unsigned char INSTRUMENT_LASER[12] PROGMEM = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x25, 0xB5, 0x00 }; + const unsigned char INSTRUMENT_LOGDRUM1[12] PROGMEM = { 0x00, 0x32, 0x44, 0xF8, 0xFF, 0x00, 0x0E, 0x11, 0x00, 0xF5, 0x7F, 0x00 }; + const unsigned char INSTRUMENT_MARIMBA1[12] PROGMEM = { 0x00, 0x05, 0x4E, 0xDA, 0x25, 0x00, 0x0A, 0x01, 0x00, 0xF9, 0x15, 0x00 }; + const unsigned char INSTRUMENT_MARIMBA2[12] PROGMEM = { 0x00, 0x85, 0x4E, 0xDA, 0x15, 0x00, 0x0A, 0x81, 0x80, 0xF9, 0x13, 0x00 }; + const unsigned char INSTRUMENT_MDRNPHON[12] PROGMEM = { 0x00, 0x30, 0x00, 0xFE, 0x11, 0x01, 0x08, 0xAE, 0xC0, 0xF1, 0x19, 0x01 }; + const unsigned char INSTRUMENT_MLTRDRUM[12] PROGMEM = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xC8, 0xB6, 0x01 }; + const unsigned char INSTRUMENT_MOOGSYNT[12] PROGMEM = { 0x00, 0x20, 0x90, 0xF5, 0x9E, 0x02, 0x0C, 0x11, 0x00, 0xF4, 0x5B, 0x03 }; + const unsigned char INSTRUMENT_NOISE1[12] PROGMEM = { 0x00, 0x0E, 0x40, 0xD1, 0x53, 0x00, 0x0E, 0x0E, 0x00, 0xF2, 0x7F, 0x03 }; + const unsigned char INSTRUMENT_OBOE1[12] PROGMEM = { 0x00, 0xB1, 0xC5, 0x6E, 0x17, 0x00, 0x02, 0x22, 0x05, 0x8B, 0x0E, 0x00 }; + const unsigned char INSTRUMENT_ORGAN1[12] PROGMEM = { 0x00, 0x65, 0xD2, 0x81, 0x03, 0x00, 0x02, 0x71, 0x80, 0xF1, 0x05, 0x00 }; + const unsigned char INSTRUMENT_ORGAN2[12] PROGMEM = { 0x00, 0x24, 0x80, 0xFF, 0x0F, 0x00, 0x01, 0x21, 0x80, 0xFF, 0x0F, 0x00 }; + const unsigned char INSTRUMENT_ORGAN3[12] PROGMEM = { 0x00, 0x03, 0x5B, 0xF0, 0x1F, 0x00, 0x0A, 0x01, 0x80, 0xF0, 0x1F, 0x00 }; + const unsigned char INSTRUMENT_ORGAN3A[12] PROGMEM = { 0x00, 0x03, 0x5B, 0xF0, 0x1F, 0x00, 0x0A, 0x01, 0x8D, 0xF0, 0x13, 0x00 }; + const unsigned char INSTRUMENT_ORGAN3B[12] PROGMEM = { 0x00, 0x03, 0x5B, 0xF0, 0x1F, 0x00, 0x0A, 0x01, 0x92, 0xF0, 0x12, 0x00 }; + const unsigned char INSTRUMENT_ORGNPERC[12] PROGMEM = { 0x00, 0x0C, 0x00, 0xF8, 0xB5, 0x00, 0x01, 0x00, 0x00, 0xD6, 0x4F, 0x00 }; + const unsigned char INSTRUMENT_PHONE1[12] PROGMEM = { 0x00, 0x17, 0x4F, 0xF2, 0x61, 0x00, 0x08, 0x12, 0x08, 0xF1, 0xB2, 0x00 }; + const unsigned char INSTRUMENT_PHONE2[12] PROGMEM = { 0x00, 0x17, 0x4F, 0xF2, 0x61, 0x00, 0x08, 0x12, 0x0A, 0xF1, 0xB4, 0x00 }; + const unsigned char INSTRUMENT_PIAN1A[12] PROGMEM = { 0x00, 0x81, 0x63, 0xF3, 0x58, 0x00, 0x00, 0x01, 0x80, 0xF2, 0x58, 0x00 }; + const unsigned char INSTRUMENT_PIAN1B[12] PROGMEM = { 0x00, 0x07, 0x1F, 0xF5, 0xFA, 0x00, 0x0E, 0x01, 0x26, 0xF5, 0xFA, 0x00 }; + const unsigned char INSTRUMENT_PIAN1C[12] PROGMEM = { 0x00, 0x07, 0x1F, 0xF5, 0xFA, 0x00, 0x0E, 0x01, 0x57, 0xF5, 0xFA, 0x00 }; + const unsigned char INSTRUMENT_PIANO[12] PROGMEM = { 0x00, 0x03, 0x4F, 0xF1, 0x53, 0x00, 0x06, 0x17, 0x00, 0xF2, 0x74, 0x00 }; + const unsigned char INSTRUMENT_PIANO1[12] PROGMEM = { 0x00, 0x01, 0x4F, 0xF1, 0x53, 0x00, 0x06, 0x11, 0x00, 0xD2, 0x74, 0x00 }; + const unsigned char INSTRUMENT_PIANO2[12] PROGMEM = { 0x00, 0x41, 0x9D, 0xF2, 0x51, 0x00, 0x06, 0x13, 0x00, 0xF2, 0xF1, 0x00 }; + const unsigned char INSTRUMENT_PIANO3[12] PROGMEM = { 0x00, 0x01, 0x4F, 0xF1, 0x50, 0x00, 0x06, 0x01, 0x04, 0xD2, 0x7C, 0x00 }; + const unsigned char INSTRUMENT_PIANO4[12] PROGMEM = { 0x00, 0x01, 0x4D, 0xF1, 0x60, 0x00, 0x08, 0x11, 0x00, 0xD2, 0x7B, 0x00 }; + const unsigned char INSTRUMENT_PIANOBEL[12] PROGMEM = { 0x00, 0x03, 0x4F, 0xF1, 0x53, 0x00, 0x06, 0x17, 0x03, 0xF2, 0x74, 0x00 }; + const unsigned char INSTRUMENT_PIANOF[12] PROGMEM = { 0x00, 0x01, 0xCF, 0xF1, 0x53, 0x00, 0x02, 0x12, 0x00, 0xF2, 0x83, 0x00 }; + const unsigned char INSTRUMENT_POPBASS1[12] PROGMEM = { 0x00, 0x10, 0x00, 0x75, 0x93, 0x01, 0x00, 0x01, 0x00, 0xF5, 0x82, 0x01 }; + const unsigned char INSTRUMENT_RKSNARE1[12] PROGMEM = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xC7, 0xB4, 0x00 }; + const unsigned char INSTRUMENT_SAX1[12] PROGMEM = { 0x00, 0x01, 0x4F, 0x71, 0x53, 0x00, 0x0A, 0x12, 0x00, 0x52, 0x7C, 0x00 }; + const unsigned char INSTRUMENT_SCRATCH[12] PROGMEM = { 0x00, 0x07, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x5C, 0xDC, 0x00 }; + const unsigned char INSTRUMENT_SCRATCH4[12] PROGMEM = { 0x00, 0x07, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x5C, 0xDC, 0x00 }; + const unsigned char INSTRUMENT_SDRUM2[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xF6, 0xB4, 0x00 }; + const unsigned char INSTRUMENT_SHRTVIBE[12] PROGMEM = { 0x00, 0xE4, 0x0E, 0xFF, 0x3F, 0x01, 0x00, 0xC0, 0x00, 0xF3, 0x07, 0x00 }; + const unsigned char INSTRUMENT_SITAR1[12] PROGMEM = { 0x00, 0x01, 0x40, 0xF1, 0x53, 0x00, 0x00, 0x08, 0x40, 0xF1, 0x53, 0x00 }; + const unsigned char INSTRUMENT_SITAR2[12] PROGMEM = { 0x00, 0x01, 0x40, 0xF1, 0x53, 0x00, 0x00, 0x08, 0x40, 0xF1, 0x53, 0x01 }; + const unsigned char INSTRUMENT_SNAKEFL[12] PROGMEM = { 0x00, 0x61, 0x0C, 0x81, 0x03, 0x00, 0x08, 0x71, 0x80, 0x61, 0x0C, 0x00 }; + const unsigned char INSTRUMENT_SNARE1[12] PROGMEM = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xF8, 0xB5, 0x00 }; + const unsigned char INSTRUMENT_SNRSUST[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0xC4, 0x03, 0xC4, 0x34, 0x00 }; + const unsigned char INSTRUMENT_SOLOVLN[12] PROGMEM = { 0x00, 0x70, 0x1C, 0x51, 0x03, 0x02, 0x0E, 0x20, 0x00, 0x54, 0x67, 0x02 }; + const unsigned char INSTRUMENT_STEELGT1[12] PROGMEM = { 0x00, 0x01, 0x46, 0xF1, 0x83, 0x00, 0x06, 0x61, 0x03, 0x31, 0x86, 0x00 }; + const unsigned char INSTRUMENT_STEELGT2[12] PROGMEM = { 0x00, 0x01, 0x47, 0xF1, 0x83, 0x00, 0x06, 0x61, 0x03, 0x91, 0x86, 0x00 }; + const unsigned char INSTRUMENT_STRINGS1[12] PROGMEM = { 0x00, 0xB1, 0x8B, 0x71, 0x11, 0x00, 0x06, 0x61, 0x40, 0x42, 0x15, 0x01 }; + const unsigned char INSTRUMENT_STRNLONG[12] PROGMEM = { 0x00, 0xE1, 0x4F, 0xB1, 0xD3, 0x03, 0x06, 0x21, 0x00, 0x12, 0x74, 0x01 }; + const unsigned char INSTRUMENT_SYN1[12] PROGMEM = { 0x00, 0x55, 0x97, 0x2A, 0x02, 0x00, 0x00, 0x12, 0x80, 0x42, 0xF3, 0x00 }; + const unsigned char INSTRUMENT_SYN2[12] PROGMEM = { 0x00, 0x13, 0x97, 0x9A, 0x12, 0x00, 0x0E, 0x11, 0x80, 0x9B, 0x14, 0x00 }; + const unsigned char INSTRUMENT_SYN3[12] PROGMEM = { 0x00, 0x11, 0x8A, 0xF1, 0x11, 0x00, 0x06, 0x01, 0x40, 0xF1, 0xB3, 0x00 }; + const unsigned char INSTRUMENT_SYN4[12] PROGMEM = { 0x00, 0x21, 0x0D, 0xE9, 0x3A, 0x00, 0x0A, 0x22, 0x80, 0x65, 0x6C, 0x00 }; + const unsigned char INSTRUMENT_SYN5[12] PROGMEM = { 0x00, 0x01, 0x4F, 0x71, 0x53, 0x00, 0x06, 0x19, 0x00, 0x52, 0x7C, 0x00 }; + const unsigned char INSTRUMENT_SYN6[12] PROGMEM = { 0x00, 0x24, 0x0F, 0x41, 0x7E, 0x00, 0x0A, 0x21, 0x00, 0xF1, 0x5E, 0x00 }; + const unsigned char INSTRUMENT_SYN9[12] PROGMEM = { 0x00, 0x07, 0x87, 0xF0, 0x05, 0x00, 0x04, 0x01, 0x80, 0xF0, 0x05, 0x00 }; + const unsigned char INSTRUMENT_SYNBAL1[12] PROGMEM = { 0x00, 0x26, 0x03, 0xE0, 0xF0, 0x00, 0x08, 0x1E, 0x00, 0xFF, 0x31, 0x00 }; + const unsigned char INSTRUMENT_SYNBAL2[12] PROGMEM = { 0x00, 0x28, 0x03, 0xE0, 0xF0, 0x00, 0x04, 0x13, 0x00, 0xE8, 0x11, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS1[12] PROGMEM = { 0x00, 0x30, 0x88, 0xD5, 0x19, 0x00, 0x0C, 0x71, 0x80, 0x61, 0x1B, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS2[12] PROGMEM = { 0x00, 0x81, 0x86, 0x65, 0x01, 0x00, 0x0C, 0x11, 0x00, 0x32, 0x74, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS4[12] PROGMEM = { 0x00, 0x81, 0x83, 0x65, 0x05, 0x00, 0x0A, 0x51, 0x00, 0x32, 0x74, 0x00 }; + const unsigned char INSTRUMENT_SYNSNR1[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xF8, 0xB6, 0x00 }; + const unsigned char INSTRUMENT_SYNSNR2[12] PROGMEM = { 0x00, 0x06, 0x00, 0xF0, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xF6, 0xB4, 0x00 }; + const unsigned char INSTRUMENT_TINCAN1[12] PROGMEM = { 0x00, 0x8F, 0x81, 0xEF, 0x01, 0x00, 0x04, 0x01, 0x00, 0x98, 0xF1, 0x00 }; + const unsigned char INSTRUMENT_TOM1[12] PROGMEM = { 0x08, 0x04, 0x00, 0xF7, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_TOM2[12] PROGMEM = { 0x08, 0x02, 0x00, 0xC8, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_TRAINBEL[12] PROGMEM = { 0x00, 0x17, 0x4F, 0xF2, 0x61, 0x00, 0x08, 0x12, 0x08, 0xF2, 0x74, 0x00 }; + const unsigned char INSTRUMENT_TRIANGLE[12] PROGMEM = { 0x00, 0x26, 0x03, 0xE0, 0xF0, 0x00, 0x08, 0x1E, 0x00, 0xFF, 0x31, 0x00 }; + const unsigned char INSTRUMENT_TROMB1[12] PROGMEM = { 0x00, 0xB1, 0x1C, 0x41, 0x1F, 0x00, 0x0E, 0x61, 0x80, 0x92, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_TROMB2[12] PROGMEM = { 0x00, 0x21, 0x1C, 0x53, 0x1D, 0x00, 0x0C, 0x61, 0x80, 0x52, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_TRUMPET1[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x0B, 0x00, 0x0E, 0x61, 0x80, 0x92, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_TRUMPET2[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x23, 0x1D, 0x00, 0x0C, 0x61, 0x80, 0x52, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_TRUMPET3[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x01, 0x00, 0x0E, 0x61, 0x80, 0x92, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_TRUMPET4[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x41, 0x0B, 0x00, 0x0C, 0x61, 0x80, 0x92, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_TUBA1[12] PROGMEM = { 0x00, 0x21, 0x19, 0x43, 0x8C, 0x00, 0x0C, 0x21, 0x80, 0x85, 0x2F, 0x00 }; + const unsigned char INSTRUMENT_VIBRA1[12] PROGMEM = { 0x00, 0x84, 0x53, 0xF5, 0x33, 0x00, 0x06, 0xA0, 0x80, 0xFD, 0x25, 0x00 }; + const unsigned char INSTRUMENT_VIBRA2[12] PROGMEM = { 0x00, 0x06, 0x73, 0xF6, 0x54, 0x00, 0x00, 0x81, 0x03, 0xF2, 0xB3, 0x00 }; + const unsigned char INSTRUMENT_VIBRA3[12] PROGMEM = { 0x00, 0x93, 0x97, 0xAA, 0x12, 0x02, 0x0E, 0x91, 0x80, 0xAC, 0x21, 0x00 }; + const unsigned char INSTRUMENT_VIOLIN1[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x51, 0x03, 0x00, 0x0E, 0x61, 0x80, 0x54, 0x67, 0x00 }; + const unsigned char INSTRUMENT_VIOLIN2[12] PROGMEM = { 0x00, 0xE1, 0x88, 0x62, 0x29, 0x00, 0x0C, 0x22, 0x80, 0x53, 0x2C, 0x00 }; + const unsigned char INSTRUMENT_VIOLIN3[12] PROGMEM = { 0x00, 0xE1, 0x88, 0x64, 0x29, 0x00, 0x06, 0x22, 0x83, 0x53, 0x2C, 0x00 }; + const unsigned char INSTRUMENT_VLNPIZZ1[12] PROGMEM = { 0x00, 0x31, 0x9C, 0xF1, 0xF9, 0x00, 0x0E, 0x31, 0x80, 0xF7, 0xE6, 0x00 }; + const unsigned char INSTRUMENT_WAVE[12] PROGMEM = { 0x00, 0x00, 0x02, 0x00, 0xF0, 0x00, 0x0E, 0x14, 0x80, 0x1B, 0xA2, 0x00 }; + const unsigned char INSTRUMENT_XYLO1[12] PROGMEM = { 0x00, 0x11, 0x2D, 0xC8, 0x2F, 0x00, 0x0C, 0x31, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_XYLO2[12] PROGMEM = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0xFF, 0x0F, 0x00 }; + const unsigned char INSTRUMENT_XYLO3[12] PROGMEM = { 0x00, 0x06, 0x00, 0xFF, 0xF0, 0x00, 0x0E, 0xC4, 0x00, 0xF8, 0xB5, 0x00 }; + +#endif diff --git a/src/midi_drums.h b/src/midi_drums.h index 878f0ab..e09e2c7 100644 --- a/src/midi_drums.h +++ b/src/midi_drums.h @@ -34,81 +34,86 @@ * 11 - Channel c, operator 2, register 0xE0 */ -const unsigned char DRUMINS_CLAP2[12] PROGMEM = { 0x00, 0x3E, 0x00, 0x9F, 0x0F, 0x0F, 0x00, 0x30, 0x00, 0x87, 0xFA, 0x00 }; -const unsigned char DRUMINS_SCRATCH1[12] PROGMEM = { 0x00, 0x01, 0x00, 0x78, 0x97, 0x09, 0x00, 0x02, 0x00, 0x88, 0x98, 0x03 }; -const unsigned char DRUMINS_SCRATCH2[12] PROGMEM = { 0x00, 0x01, 0x00, 0x78, 0x97, 0x09, 0x00, 0x02, 0x00, 0x88, 0x98, 0x03 }; -const unsigned char DRUMINS_RIMSHOT2[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; -const unsigned char DRUMINS_HIQ[12] PROGMEM = { 0x00, 0x00, 0x00, 0xF8, 0x6C, 0x01, 0x00, 0x0E, 0x80, 0xE8, 0x4A, 0x00 }; -const unsigned char DRUMINS_WOODBLOK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; -const unsigned char DRUMINS_GLOCK[12] PROGMEM = { 0x00, 0x06, 0x03, 0xF4, 0x44, 0x00, 0x01, 0x01, 0x1B, 0xF2, 0x34, 0x00 }; -const unsigned char DRUMINS_BASS_DR2[12] PROGMEM = { 0x00, 0x00, 0x00, 0xF9, 0xF3, 0x05, 0x00, 0x01, 0x00, 0xF7, 0x8A, 0x00 }; -const unsigned char DRUMINS_BASS_DR1[12] PROGMEM = { 0x00, 0x01, 0x07, 0xFA, 0xFD, 0x05, 0x00, 0x01, 0x00, 0xF6, 0x47, 0x00 }; -const unsigned char DRUMINS_RIMSHOT[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; -const unsigned char DRUMINS_SNARE_AC[12] PROGMEM = { 0x00, 0x24, 0x00, 0xFF, 0x00, 0x0F, 0x00, 0x02, 0x00, 0xF7, 0xA9, 0x00 }; -const unsigned char DRUMINS_CLAP[12] PROGMEM = { 0x00, 0x3E, 0x00, 0x9F, 0x0F, 0x0F, 0x00, 0x30, 0x00, 0x87, 0xFA, 0x00 }; -const unsigned char DRUMINS_SNARE_EL[12] PROGMEM = { 0x00, 0x24, 0x00, 0xFF, 0x00, 0x0F, 0x00, 0x02, 0x00, 0xF7, 0xA9, 0x00 }; -const unsigned char DRUMINS_LO_TOMS[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_HIHAT_CL[12] PROGMEM = { 0x00, 0x2C, 0x00, 0xF2, 0xFE, 0x07, 0x00, 0x02, 0x06, 0xB8, 0xD8, 0x03 }; -const unsigned char DRUMINS_HI_TOMS[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_HIHAT_PL[12] PROGMEM = { 0x00, 0x2C, 0x00, 0xF2, 0xFE, 0x07, 0x00, 0x02, 0x06, 0xB8, 0xD8, 0x03 }; -const unsigned char DRUMINS_LOW_TOM[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_HIHAT_OP[12] PROGMEM = { 0x00, 0x2E, 0x00, 0x82, 0xF6, 0x05, 0x00, 0x04, 0x10, 0x74, 0xF8, 0x03 }; -const unsigned char DRUMINS_LTOM_MID[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_HTOM_MID[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_CRASH[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x00, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; -const unsigned char DRUMINS_TOM_HIGH[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_RIDE_CY[12] PROGMEM = { 0x00, 0x29, 0x10, 0x94, 0x00, 0x0F, 0x00, 0x04, 0x04, 0xF9, 0x44, 0x03 }; -const unsigned char DRUMINS_TAMBOUR[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x00, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; -const unsigned char DRUMINS_CYMBAL[12] PROGMEM = { 0x00, 0x29, 0x10, 0x94, 0x00, 0x0F, 0x00, 0x04, 0x04, 0xF9, 0x44, 0x03 }; -const unsigned char DRUMINS_TAMBOU2[12] PROGMEM = { 0x00, 0x2E, 0x09, 0xF5, 0xF1, 0x01, 0x00, 0x06, 0x03, 0x87, 0xF7, 0x03 }; -const unsigned char DRUMINS_SPLASH[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x00, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; -const unsigned char DRUMINS_COWBELL[12] PROGMEM = { 0x00, 0x37, 0x14, 0xF7, 0xA1, 0x09, 0x01, 0x03, 0x00, 0xF6, 0x28, 0x00 }; -const unsigned char DRUMINS_CRASH2[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x00, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; -const unsigned char DRUMINS_VIBRASLA[12] PROGMEM = { 0x00, 0x80, 0x00, 0xFF, 0x00, 0x0D, 0x01, 0x00, 0x00, 0xF5, 0xF7, 0x01 }; -const unsigned char DRUMINS_RIDE2[12] PROGMEM = { 0x00, 0x29, 0x10, 0x94, 0x00, 0x0F, 0x00, 0x04, 0x04, 0xF9, 0x44, 0x03 }; -const unsigned char DRUMINS_HI_BONGO[12] PROGMEM = { 0x00, 0x25, 0xC4, 0xFA, 0xFA, 0x01, 0x00, 0x03, 0x00, 0x99, 0xF9, 0x00 }; -const unsigned char DRUMINS_LO_BONGO[12] PROGMEM = { 0x00, 0x21, 0x03, 0xFB, 0xFA, 0x01, 0x01, 0x02, 0x00, 0xA8, 0xF7, 0x00 }; -const unsigned char DRUMINS_MUTECONG[12] PROGMEM = { 0x00, 0x25, 0xC4, 0xFA, 0xFA, 0x01, 0x00, 0x03, 0x00, 0x99, 0xF9, 0x00 }; -const unsigned char DRUMINS_OPENCONG[12] PROGMEM = { 0x00, 0x24, 0x18, 0xF9, 0xFA, 0x0F, 0x02, 0x03, 0x00, 0xA6, 0xF6, 0x00 }; -const unsigned char DRUMINS_LOWCONGA[12] PROGMEM = { 0x00, 0x24, 0x18, 0xF9, 0xFA, 0x0F, 0x02, 0x03, 0x00, 0xA6, 0xF6, 0x00 }; -const unsigned char DRUMINS_HI_TIMBA[12] PROGMEM = { 0x00, 0x05, 0x14, 0xF5, 0xF5, 0x07, 0x02, 0x03, 0x00, 0xF6, 0x36, 0x02 }; -const unsigned char DRUMINS_LO_TIMBA[12] PROGMEM = { 0x00, 0x05, 0x14, 0xF5, 0xF5, 0x07, 0x02, 0x03, 0x00, 0xF6, 0x36, 0x02 }; -const unsigned char DRUMINS_HI_AGOGO[12] PROGMEM = { 0x00, 0x1C, 0x0C, 0xF9, 0x31, 0x0F, 0x01, 0x15, 0x00, 0x96, 0xE8, 0x01 }; -const unsigned char DRUMINS_LO_AGOGO[12] PROGMEM = { 0x00, 0x1C, 0x0C, 0xF9, 0x31, 0x0F, 0x01, 0x15, 0x00, 0x96, 0xE8, 0x01 }; -const unsigned char DRUMINS_CABASA[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xFF, 0x01, 0x0F, 0x00, 0x0E, 0x02, 0x79, 0x77, 0x03 }; -const unsigned char DRUMINS_MARACAS[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xFF, 0x01, 0x0F, 0x00, 0x0E, 0x02, 0x79, 0x77, 0x03 }; -const unsigned char DRUMINS_S_WHISTL[12] PROGMEM = { 0x00, 0x20, 0x15, 0xAF, 0x07, 0x05, 0x01, 0x0E, 0x00, 0xA5, 0x2B, 0x02 }; -const unsigned char DRUMINS_L_WHISTL[12] PROGMEM = { 0x00, 0x20, 0x18, 0xBF, 0x07, 0x01, 0x01, 0x0E, 0x00, 0x93, 0x3B, 0x02 }; -const unsigned char DRUMINS_S_GUIRO[12] PROGMEM = { 0x00, 0x20, 0x00, 0xF0, 0xF7, 0x0B, 0x00, 0x08, 0x01, 0x89, 0x3B, 0x03 }; -const unsigned char DRUMINS_L_GUIRO[12] PROGMEM = { 0x00, 0x20, 0x00, 0xF3, 0xFA, 0x09, 0x00, 0x08, 0x0A, 0x53, 0x2B, 0x02 }; -const unsigned char DRUMINS_CLAVES[12] PROGMEM = { 0x00, 0x15, 0x21, 0xF8, 0x9A, 0x09, 0x01, 0x13, 0x00, 0xF6, 0x89, 0x00 }; -const unsigned char DRUMINS_HI_WDBLK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; -const unsigned char DRUMINS_LO_WDBLK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; -const unsigned char DRUMINS_MU_CUICA[12] PROGMEM = { 0x00, 0x20, 0x01, 0x5F, 0x07, 0x01, 0x00, 0x08, 0x00, 0x87, 0x4B, 0x01 }; -const unsigned char DRUMINS_OP_CUICA[12] PROGMEM = { 0x00, 0x25, 0x12, 0x57, 0xF7, 0x01, 0x01, 0x03, 0x00, 0x78, 0x67, 0x01 }; -const unsigned char DRUMINS_MU_TRNGL[12] PROGMEM = { 0x00, 0x22, 0x2F, 0xF1, 0xF0, 0x07, 0x00, 0x27, 0x02, 0xF8, 0xFC, 0x00 }; -const unsigned char DRUMINS_OP_TRNGL[12] PROGMEM = { 0x00, 0x26, 0x44, 0xF1, 0xF0, 0x07, 0x00, 0x27, 0x40, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_SHAKER[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xFF, 0x01, 0x0F, 0x00, 0x0E, 0x02, 0x79, 0x77, 0x03 }; -const unsigned char DRUMINS_TRIANGL1[12] PROGMEM = { 0x00, 0x26, 0x44, 0xF1, 0xF0, 0x07, 0x00, 0x27, 0x40, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_TRIANGL2[12] PROGMEM = { 0x00, 0x26, 0x44, 0xF1, 0xF0, 0x07, 0x00, 0x27, 0x40, 0xF5, 0xF5, 0x00 }; -const unsigned char DRUMINS_RIMSHOT3[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; -const unsigned char DRUMINS_RIMSHOT4[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; -const unsigned char DRUMINS_TAIKO[12] PROGMEM = { 0x00, 0x02, 0x1D, 0xF5, 0x93, 0x01, 0x00, 0x00, 0x00, 0xC6, 0x45, 0x00 }; +#ifndef _MIDI_DRUM2OP_H_ + #define _MIDI_DRUM2OP_H_ -// MIDI note number of the first drum sound. -const unsigned char DRUM_NOTE_BASE = 27; -const unsigned char NUM_MIDI_DRUMS = 60; + const unsigned char DRUMINS_CLAP2[12] PROGMEM = { 0x00, 0x3E, 0x00, 0x9F, 0x0F, 0x0F, 0x00, 0x30, 0x00, 0x87, 0xFA, 0x00 }; + const unsigned char DRUMINS_SCRATCH1[12] PROGMEM = { 0x00, 0x01, 0x00, 0x78, 0x97, 0x09, 0x00, 0x02, 0x00, 0x88, 0x98, 0x03 }; + const unsigned char DRUMINS_SCRATCH2[12] PROGMEM = { 0x00, 0x01, 0x00, 0x78, 0x97, 0x09, 0x00, 0x02, 0x00, 0x88, 0x98, 0x03 }; + const unsigned char DRUMINS_RIMSHOT2[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; + const unsigned char DRUMINS_HIQ[12] PROGMEM = { 0x00, 0x00, 0x00, 0xF8, 0x6C, 0x01, 0x00, 0x0E, 0x80, 0xE8, 0x4A, 0x00 }; + const unsigned char DRUMINS_WOODBLOK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; + const unsigned char DRUMINS_GLOCK[12] PROGMEM = { 0x00, 0x06, 0x03, 0xF4, 0x44, 0x00, 0x01, 0x01, 0x1B, 0xF2, 0x34, 0x00 }; + const unsigned char DRUMINS_BASS_DR2[12] PROGMEM = { 0x00, 0x00, 0x00, 0xF9, 0xF3, 0x05, 0x00, 0x01, 0x00, 0xF7, 0x8A, 0x00 }; + const unsigned char DRUMINS_BASS_DR1[12] PROGMEM = { 0x00, 0x01, 0x07, 0xFA, 0xFD, 0x05, 0x00, 0x01, 0x00, 0xF6, 0x47, 0x00 }; + const unsigned char DRUMINS_RIMSHOT[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; + const unsigned char DRUMINS_SNARE_AC[12] PROGMEM = { 0x00, 0x24, 0x00, 0xFF, 0x0F, 0x0F, 0x00, 0x02, 0x00, 0xF7, 0xA9, 0x00 }; + const unsigned char DRUMINS_CLAP[12] PROGMEM = { 0x00, 0x3E, 0x00, 0x9F, 0x0F, 0x0F, 0x00, 0x30, 0x00, 0x87, 0xFA, 0x00 }; + const unsigned char DRUMINS_SNARE_EL[12] PROGMEM = { 0x00, 0x24, 0x00, 0xFF, 0x0F, 0x0F, 0x00, 0x02, 0x00, 0xF7, 0xA9, 0x00 }; + const unsigned char DRUMINS_LO_TOMS[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_HIHAT_CL[12] PROGMEM = { 0x00, 0x2C, 0x00, 0xF2, 0xFE, 0x07, 0x00, 0x02, 0x06, 0xB8, 0xD8, 0x03 }; + const unsigned char DRUMINS_HI_TOMS[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_HIHAT_PL[12] PROGMEM = { 0x00, 0x2C, 0x00, 0xF2, 0xFE, 0x07, 0x00, 0x02, 0x06, 0xB8, 0xD8, 0x03 }; + const unsigned char DRUMINS_LOW_TOM[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_HIHAT_OP[12] PROGMEM = { 0x00, 0x2E, 0x00, 0x82, 0xF6, 0x05, 0x00, 0x04, 0x10, 0x74, 0xF8, 0x03 }; + const unsigned char DRUMINS_LTOM_MID[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_HTOM_MID[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_CRASH[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x0F, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; + const unsigned char DRUMINS_TOM_HIGH[12] PROGMEM = { 0x00, 0x06, 0x0A, 0xFA, 0x1F, 0x0C, 0x00, 0x11, 0x00, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_RIDE_CY[12] PROGMEM = { 0x00, 0x29, 0x10, 0x94, 0x0F, 0x0F, 0x00, 0x04, 0x04, 0xF9, 0x44, 0x03 }; + const unsigned char DRUMINS_TAMBOUR[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x0F, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; + const unsigned char DRUMINS_CYMBAL[12] PROGMEM = { 0x00, 0x29, 0x10, 0x94, 0x0F, 0x0F, 0x00, 0x04, 0x04, 0xF9, 0x44, 0x03 }; + const unsigned char DRUMINS_TAMBOU2[12] PROGMEM = { 0x00, 0x2E, 0x09, 0xF5, 0xF1, 0x01, 0x00, 0x06, 0x03, 0x87, 0xF7, 0x03 }; + const unsigned char DRUMINS_SPLASH[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x0F, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; + const unsigned char DRUMINS_COWBELL[12] PROGMEM = { 0x00, 0x37, 0x14, 0xF7, 0xA1, 0x09, 0x01, 0x03, 0x00, 0xF6, 0x28, 0x00 }; + const unsigned char DRUMINS_CRASH2[12] PROGMEM = { 0x00, 0x2C, 0x00, 0x9F, 0x0F, 0x0F, 0x02, 0x0E, 0x05, 0xC5, 0xD4, 0x03 }; + const unsigned char DRUMINS_VIBRASLA[12] PROGMEM = { 0x00, 0x80, 0x00, 0xFF, 0x0F, 0x0D, 0x01, 0x00, 0x00, 0xF5, 0xF7, 0x01 }; + const unsigned char DRUMINS_RIDE2[12] PROGMEM = { 0x00, 0x29, 0x10, 0x94, 0x0F, 0x0F, 0x00, 0x04, 0x04, 0xF9, 0x44, 0x03 }; + const unsigned char DRUMINS_HI_BONGO[12] PROGMEM = { 0x00, 0x25, 0xC4, 0xFA, 0xFA, 0x01, 0x00, 0x03, 0x00, 0x99, 0xF9, 0x00 }; + const unsigned char DRUMINS_LO_BONGO[12] PROGMEM = { 0x00, 0x21, 0x03, 0xFB, 0xFA, 0x01, 0x01, 0x02, 0x00, 0xA8, 0xF7, 0x00 }; + const unsigned char DRUMINS_MUTECONG[12] PROGMEM = { 0x00, 0x25, 0xC4, 0xFA, 0xFA, 0x01, 0x00, 0x03, 0x00, 0x99, 0xF9, 0x00 }; + const unsigned char DRUMINS_OPENCONG[12] PROGMEM = { 0x00, 0x24, 0x18, 0xF9, 0xFA, 0x0F, 0x02, 0x03, 0x00, 0xA6, 0xF6, 0x00 }; + const unsigned char DRUMINS_LOWCONGA[12] PROGMEM = { 0x00, 0x24, 0x18, 0xF9, 0xFA, 0x0F, 0x02, 0x03, 0x00, 0xA6, 0xF6, 0x00 }; + const unsigned char DRUMINS_HI_TIMBA[12] PROGMEM = { 0x00, 0x05, 0x14, 0xF5, 0xF5, 0x07, 0x02, 0x03, 0x00, 0xF6, 0x36, 0x02 }; + const unsigned char DRUMINS_LO_TIMBA[12] PROGMEM = { 0x00, 0x05, 0x14, 0xF5, 0xF5, 0x07, 0x02, 0x03, 0x00, 0xF6, 0x36, 0x02 }; + const unsigned char DRUMINS_HI_AGOGO[12] PROGMEM = { 0x00, 0x1C, 0x0C, 0xF9, 0x31, 0x0F, 0x01, 0x15, 0x00, 0x96, 0xE8, 0x01 }; + const unsigned char DRUMINS_LO_AGOGO[12] PROGMEM = { 0x00, 0x1C, 0x0C, 0xF9, 0x31, 0x0F, 0x01, 0x15, 0x00, 0x96, 0xE8, 0x01 }; + const unsigned char DRUMINS_CABASA[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xFF, 0x01, 0x0F, 0x00, 0x0E, 0x02, 0x79, 0x77, 0x03 }; + const unsigned char DRUMINS_MARACAS[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xFF, 0x01, 0x0F, 0x00, 0x0E, 0x02, 0x79, 0x77, 0x03 }; + const unsigned char DRUMINS_S_WHISTL[12] PROGMEM = { 0x00, 0x20, 0x15, 0xAF, 0x07, 0x05, 0x01, 0x0E, 0x00, 0xA5, 0x2B, 0x02 }; + const unsigned char DRUMINS_L_WHISTL[12] PROGMEM = { 0x00, 0x20, 0x18, 0xBF, 0x07, 0x01, 0x01, 0x0E, 0x00, 0x93, 0x3B, 0x02 }; + const unsigned char DRUMINS_S_GUIRO[12] PROGMEM = { 0x00, 0x20, 0x00, 0xF0, 0xF7, 0x0B, 0x00, 0x08, 0x01, 0x89, 0x3B, 0x03 }; + const unsigned char DRUMINS_L_GUIRO[12] PROGMEM = { 0x00, 0x20, 0x00, 0xF3, 0xFA, 0x09, 0x00, 0x08, 0x0A, 0x53, 0x2B, 0x02 }; + const unsigned char DRUMINS_CLAVES[12] PROGMEM = { 0x00, 0x15, 0x21, 0xF8, 0x9A, 0x09, 0x01, 0x13, 0x00, 0xF6, 0x89, 0x00 }; + const unsigned char DRUMINS_HI_WDBLK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; + const unsigned char DRUMINS_LO_WDBLK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; + const unsigned char DRUMINS_MU_CUICA[12] PROGMEM = { 0x00, 0x20, 0x01, 0x5F, 0x07, 0x01, 0x00, 0x08, 0x00, 0x87, 0x4B, 0x01 }; + const unsigned char DRUMINS_OP_CUICA[12] PROGMEM = { 0x00, 0x25, 0x12, 0x57, 0xF7, 0x01, 0x01, 0x03, 0x00, 0x78, 0x67, 0x01 }; + const unsigned char DRUMINS_MU_TRNGL[12] PROGMEM = { 0x00, 0x22, 0x2F, 0xF1, 0xF0, 0x07, 0x00, 0x27, 0x02, 0xF8, 0xFC, 0x00 }; + const unsigned char DRUMINS_OP_TRNGL[12] PROGMEM = { 0x00, 0x26, 0x44, 0xF1, 0xF0, 0x07, 0x00, 0x27, 0x40, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_SHAKER[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xFF, 0x01, 0x0F, 0x00, 0x0E, 0x02, 0x79, 0x77, 0x03 }; + const unsigned char DRUMINS_TRIANGL1[12] PROGMEM = { 0x00, 0x26, 0x44, 0xF1, 0xFF, 0x07, 0x00, 0x27, 0x40, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_TRIANGL2[12] PROGMEM = { 0x00, 0x26, 0x44, 0xF1, 0xFF, 0x07, 0x00, 0x27, 0x40, 0xF5, 0xF5, 0x00 }; + const unsigned char DRUMINS_RIMSHOT3[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; + const unsigned char DRUMINS_RIMSHOT4[12] PROGMEM = { 0x00, 0x16, 0x08, 0xF1, 0xFB, 0x01, 0x00, 0x11, 0x00, 0xF9, 0x69, 0x00 }; + const unsigned char DRUMINS_TAIKO[12] PROGMEM = { 0x00, 0x02, 0x1D, 0xF5, 0x93, 0x01, 0x00, 0x00, 0x00, 0xC6, 0x45, 0x00 }; -// Instrument pointer array to access instruments by MIDI program. -const unsigned char *midiDrums[] = { - DRUMINS_CLAP2, DRUMINS_SCRATCH1, DRUMINS_SCRATCH2, DRUMINS_RIMSHOT2, DRUMINS_HIQ, DRUMINS_WOODBLOK, - DRUMINS_GLOCK, DRUMINS_BASS_DR2, DRUMINS_BASS_DR1, DRUMINS_RIMSHOT, DRUMINS_SNARE_AC, DRUMINS_CLAP, - DRUMINS_SNARE_EL, DRUMINS_LO_TOMS, DRUMINS_HIHAT_CL, DRUMINS_HI_TOMS, DRUMINS_HIHAT_PL, DRUMINS_LOW_TOM, - DRUMINS_HIHAT_OP, DRUMINS_LTOM_MID, DRUMINS_HTOM_MID, DRUMINS_CRASH, DRUMINS_TOM_HIGH, DRUMINS_RIDE_CY, - DRUMINS_TAMBOUR, DRUMINS_CYMBAL, DRUMINS_TAMBOU2, DRUMINS_SPLASH, DRUMINS_COWBELL, DRUMINS_CRASH2, - DRUMINS_VIBRASLA, DRUMINS_RIDE2, DRUMINS_HI_BONGO, DRUMINS_LO_BONGO, DRUMINS_MUTECONG, DRUMINS_OPENCONG, - DRUMINS_LOWCONGA, DRUMINS_HI_TIMBA, DRUMINS_LO_TIMBA, DRUMINS_HI_AGOGO, DRUMINS_LO_AGOGO, DRUMINS_CABASA, - DRUMINS_MARACAS, DRUMINS_S_WHISTL, DRUMINS_L_WHISTL, DRUMINS_S_GUIRO, DRUMINS_L_GUIRO, DRUMINS_CLAVES, - DRUMINS_HI_WDBLK, DRUMINS_LO_WDBLK, DRUMINS_MU_CUICA, DRUMINS_OP_CUICA, DRUMINS_MU_TRNGL, DRUMINS_OP_TRNGL, - DRUMINS_SHAKER, DRUMINS_TRIANGL1, DRUMINS_TRIANGL2, DRUMINS_RIMSHOT3, DRUMINS_RIMSHOT4, DRUMINS_TAIKO, -}; + // MIDI note number of the first drum sound. + const unsigned char DRUM_NOTE_BASE = 27; + const unsigned char NUM_MIDI_DRUMS = 60; + + // Instrument pointer array to access instruments by MIDI program. + const unsigned char *midiDrums[] = { + DRUMINS_CLAP2, DRUMINS_SCRATCH1, DRUMINS_SCRATCH2, DRUMINS_RIMSHOT2, DRUMINS_HIQ, DRUMINS_WOODBLOK, + DRUMINS_GLOCK, DRUMINS_BASS_DR2, DRUMINS_BASS_DR1, DRUMINS_RIMSHOT, DRUMINS_SNARE_AC, DRUMINS_CLAP, + DRUMINS_SNARE_EL, DRUMINS_LO_TOMS, DRUMINS_HIHAT_CL, DRUMINS_HI_TOMS, DRUMINS_HIHAT_PL, DRUMINS_LOW_TOM, + DRUMINS_HIHAT_OP, DRUMINS_LTOM_MID, DRUMINS_HTOM_MID, DRUMINS_CRASH, DRUMINS_TOM_HIGH, DRUMINS_RIDE_CY, + DRUMINS_TAMBOUR, DRUMINS_CYMBAL, DRUMINS_TAMBOU2, DRUMINS_SPLASH, DRUMINS_COWBELL, DRUMINS_CRASH2, + DRUMINS_VIBRASLA, DRUMINS_RIDE2, DRUMINS_HI_BONGO, DRUMINS_LO_BONGO, DRUMINS_MUTECONG, DRUMINS_OPENCONG, + DRUMINS_LOWCONGA, DRUMINS_HI_TIMBA, DRUMINS_LO_TIMBA, DRUMINS_HI_AGOGO, DRUMINS_LO_AGOGO, DRUMINS_CABASA, + DRUMINS_MARACAS, DRUMINS_S_WHISTL, DRUMINS_L_WHISTL, DRUMINS_S_GUIRO, DRUMINS_L_GUIRO, DRUMINS_CLAVES, + DRUMINS_HI_WDBLK, DRUMINS_LO_WDBLK, DRUMINS_MU_CUICA, DRUMINS_OP_CUICA, DRUMINS_MU_TRNGL, DRUMINS_OP_TRNGL, + DRUMINS_SHAKER, DRUMINS_TRIANGL1, DRUMINS_TRIANGL2, DRUMINS_RIMSHOT3, DRUMINS_RIMSHOT4, DRUMINS_TAIKO + }; + +#endif diff --git a/src/midi_instruments.h b/src/midi_instruments.h index 3370733..94ac088 100644 --- a/src/midi_instruments.h +++ b/src/midi_instruments.h @@ -33,158 +33,163 @@ * 11 - Channel c, operator 2, register 0xE0 */ -const unsigned char INSTRUMENT_PIANO1[12] PROGMEM = { 0x00, 0x33, 0x5A, 0xB2, 0x50, 0x01, 0x00, 0x31, 0x00, 0xB1, 0xF5, 0x01 }; -const unsigned char INSTRUMENT_PIANO2[12] PROGMEM = { 0x00, 0x31, 0x49, 0xF2, 0x53, 0x07, 0x01, 0x11, 0x03, 0xF1, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_PIANO3[12] PROGMEM = { 0x00, 0x31, 0x95, 0xD1, 0x83, 0x0D, 0x01, 0x32, 0x03, 0xC1, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_HONKTONK[12] PROGMEM = { 0x00, 0x34, 0x9B, 0xF3, 0x63, 0x01, 0x01, 0x11, 0x00, 0x92, 0xF5, 0x01 }; -const unsigned char INSTRUMENT_EP1[12] PROGMEM = { 0x00, 0x27, 0x28, 0xF8, 0xB7, 0x01, 0x02, 0x91, 0x00, 0xF1, 0xF9, 0x00 }; -const unsigned char INSTRUMENT_EP2[12] PROGMEM = { 0x00, 0x1A, 0x2D, 0xF3, 0xEE, 0x01, 0x01, 0x11, 0x00, 0xF1, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_HARPSIC[12] PROGMEM = { 0x00, 0x35, 0x95, 0xF2, 0x58, 0x0F, 0x01, 0x32, 0x02, 0x81, 0xF6, 0x01 }; -const unsigned char INSTRUMENT_CLAVIC[12] PROGMEM = { 0x00, 0x31, 0x85, 0xC9, 0x40, 0x01, 0x00, 0x35, 0x00, 0xC2, 0xB9, 0x01 }; -const unsigned char INSTRUMENT_CELESTA[12] PROGMEM = { 0x00, 0x09, 0x15, 0xC7, 0x64, 0x08, 0x00, 0x01, 0x05, 0xB2, 0x35, 0x00 }; -const unsigned char INSTRUMENT_GLOCK[12] PROGMEM = { 0x00, 0x06, 0x03, 0xF4, 0x44, 0x00, 0x01, 0x01, 0x1B, 0xF2, 0x34, 0x00 }; -const unsigned char INSTRUMENT_MUSICBOX[12] PROGMEM = { 0x00, 0x04, 0x06, 0xA9, 0x24, 0x0A, 0x01, 0x01, 0x01, 0xF5, 0x74, 0x00 }; -const unsigned char INSTRUMENT_VIBES[12] PROGMEM = { 0x00, 0xD4, 0x00, 0xF6, 0x33, 0x00, 0x00, 0xF1, 0x00, 0x61, 0xE3, 0x00 }; -const unsigned char INSTRUMENT_MARIMBA[12] PROGMEM = { 0x00, 0xD4, 0x00, 0xF7, 0xE8, 0x04, 0x00, 0xD1, 0x00, 0xA4, 0x64, 0x00 }; -const unsigned char INSTRUMENT_XYLO[12] PROGMEM = { 0x00, 0x36, 0x16, 0xF7, 0xF7, 0x01, 0x00, 0x31, 0x07, 0xB5, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_TUBEBELL[12] PROGMEM = { 0x00, 0x03, 0x1B, 0xA2, 0x43, 0x0B, 0x00, 0x00, 0x00, 0xF3, 0x74, 0x00 }; -const unsigned char INSTRUMENT_SANTUR[12] PROGMEM = { 0x00, 0xC3, 0x8E, 0xF8, 0x35, 0x01, 0x01, 0x11, 0x00, 0xC3, 0x94, 0x01 }; -const unsigned char INSTRUMENT_ORGAN1[12] PROGMEM = { 0x00, 0xE2, 0x07, 0xF4, 0x1B, 0x06, 0x01, 0xE0, 0x00, 0xF4, 0x0D, 0x01 }; -const unsigned char INSTRUMENT_ORGAN2[12] PROGMEM = { 0x00, 0xF2, 0x00, 0xF6, 0x2C, 0x04, 0x00, 0xF0, 0x00, 0xF5, 0x0B, 0x01 }; -const unsigned char INSTRUMENT_ORGAN3[12] PROGMEM = { 0x00, 0xF1, 0x06, 0xB6, 0x15, 0x0A, 0x00, 0xF0, 0x00, 0xBF, 0x07, 0x00 }; -const unsigned char INSTRUMENT_PIPEORG[12] PROGMEM = { 0x00, 0x22, 0x03, 0x79, 0x16, 0x08, 0x01, 0xE0, 0x00, 0x6D, 0x08, 0x01 }; -const unsigned char INSTRUMENT_REEDORG[12] PROGMEM = { 0x00, 0x31, 0x27, 0x63, 0x06, 0x01, 0x00, 0x72, 0x00, 0x51, 0x17, 0x01 }; -const unsigned char INSTRUMENT_ACORDIAN[12] PROGMEM = { 0x00, 0xB4, 0x1D, 0x53, 0x16, 0x0F, 0x01, 0x71, 0x00, 0x51, 0x17, 0x01 }; -const unsigned char INSTRUMENT_HARMONIC[12] PROGMEM = { 0x00, 0x25, 0x29, 0x97, 0x15, 0x01, 0x00, 0x32, 0x00, 0x53, 0x08, 0x01 }; -const unsigned char INSTRUMENT_BANDNEON[12] PROGMEM = { 0x00, 0x24, 0x9E, 0x67, 0x15, 0x0F, 0x00, 0x31, 0x00, 0x53, 0x06, 0x01 }; -const unsigned char INSTRUMENT_NYLONGT[12] PROGMEM = { 0x00, 0x13, 0x27, 0xA3, 0xB4, 0x05, 0x01, 0x31, 0x00, 0xD2, 0xF8, 0x00 }; -const unsigned char INSTRUMENT_STEELGT[12] PROGMEM = { 0x00, 0x17, 0xA3, 0xF3, 0x32, 0x01, 0x00, 0x11, 0x00, 0xE2, 0xC7, 0x01 }; -const unsigned char INSTRUMENT_JAZZGT[12] PROGMEM = { 0x00, 0x33, 0x24, 0xD2, 0xC1, 0x0F, 0x01, 0x31, 0x00, 0xF1, 0x9C, 0x00 }; -const unsigned char INSTRUMENT_CLEANGT[12] PROGMEM = { 0x00, 0x31, 0x05, 0xF8, 0x44, 0x01, 0x00, 0x32, 0x02, 0xF2, 0xC9, 0x01 }; -const unsigned char INSTRUMENT_MUTEGT[12] PROGMEM = { 0x00, 0x21, 0x09, 0x9C, 0x7B, 0x07, 0x00, 0x02, 0x03, 0x95, 0xFB, 0x00 }; -const unsigned char INSTRUMENT_OVERDGT[12] PROGMEM = { 0x00, 0x21, 0x84, 0x81, 0x98, 0x07, 0x01, 0x21, 0x04, 0xA1, 0x59, 0x00 }; -const unsigned char INSTRUMENT_DISTGT[12] PROGMEM = { 0x00, 0xB1, 0x0C, 0x78, 0x43, 0x01, 0x00, 0x22, 0x03, 0x91, 0xFC, 0x03 }; -const unsigned char INSTRUMENT_GTHARMS[12] PROGMEM = { 0x00, 0x00, 0x0A, 0x82, 0x8C, 0x09, 0x00, 0x08, 0x02, 0xB4, 0xEC, 0x00 }; -const unsigned char INSTRUMENT_ACOUBASS[12] PROGMEM = { 0x00, 0x21, 0x13, 0xAB, 0x46, 0x01, 0x00, 0x21, 0x00, 0x93, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_FINGBASS[12] PROGMEM = { 0x00, 0x01, 0x0A, 0xF9, 0x32, 0x01, 0x00, 0x22, 0x04, 0xC1, 0x58, 0x00 }; -const unsigned char INSTRUMENT_PICKBASS[12] PROGMEM = { 0x00, 0x21, 0x07, 0xFA, 0x77, 0x0B, 0x00, 0x22, 0x02, 0xC3, 0x6A, 0x00 }; -const unsigned char INSTRUMENT_FRETLESS[12] PROGMEM = { 0x00, 0x21, 0x17, 0x71, 0x57, 0x0B, 0x00, 0x21, 0x00, 0x62, 0x87, 0x00 }; -const unsigned char INSTRUMENT_SLAPBAS1[12] PROGMEM = { 0x00, 0x25, 0x01, 0xFA, 0x78, 0x07, 0x01, 0x12, 0x00, 0xF3, 0x97, 0x00 }; -const unsigned char INSTRUMENT_SLAPBAS2[12] PROGMEM = { 0x00, 0x21, 0x03, 0xFA, 0x88, 0x0D, 0x00, 0x13, 0x00, 0xB3, 0x97, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS1[12] PROGMEM = { 0x00, 0x21, 0x09, 0xF5, 0x7F, 0x09, 0x01, 0x23, 0x04, 0xF3, 0xCC, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS2[12] PROGMEM = { 0x00, 0x01, 0x10, 0xA3, 0x9B, 0x09, 0x00, 0x01, 0x00, 0x93, 0xAA, 0x00 }; -const unsigned char INSTRUMENT_VIOLIN[12] PROGMEM = { 0x00, 0xE2, 0x19, 0xF6, 0x29, 0x0D, 0x01, 0xE1, 0x00, 0x78, 0x08, 0x01 }; -const unsigned char INSTRUMENT_VIOLA[12] PROGMEM = { 0x00, 0xE2, 0x1C, 0xF6, 0x29, 0x0D, 0x01, 0xE1, 0x00, 0x78, 0x08, 0x01 }; -const unsigned char INSTRUMENT_CELLO[12] PROGMEM = { 0x00, 0x61, 0x19, 0x69, 0x16, 0x0B, 0x01, 0x61, 0x00, 0x54, 0x27, 0x01 }; -const unsigned char INSTRUMENT_CONTRAB[12] PROGMEM = { 0x00, 0x71, 0x18, 0x82, 0x31, 0x0D, 0x01, 0x32, 0x00, 0x61, 0x56, 0x00 }; -const unsigned char INSTRUMENT_TREMSTR[12] PROGMEM = { 0x00, 0xE2, 0x23, 0x70, 0x06, 0x0D, 0x01, 0xE1, 0x00, 0x75, 0x16, 0x01 }; -const unsigned char INSTRUMENT_PIZZ[12] PROGMEM = { 0x00, 0x02, 0x00, 0x88, 0xE6, 0x08, 0x00, 0x61, 0x00, 0xF5, 0xF6, 0x01 }; -const unsigned char INSTRUMENT_HARP[12] PROGMEM = { 0x00, 0x12, 0x20, 0xF6, 0xD5, 0x0F, 0x01, 0x11, 0x80, 0xF3, 0xE3, 0x00 }; -const unsigned char INSTRUMENT_TIMPANI[12] PROGMEM = { 0x00, 0x61, 0x0E, 0xF4, 0xF4, 0x01, 0x01, 0x00, 0x00, 0xB5, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_STRINGS[12] PROGMEM = { 0x00, 0x61, 0x1E, 0x9C, 0x04, 0x0F, 0x01, 0x21, 0x80, 0x71, 0x16, 0x00 }; -const unsigned char INSTRUMENT_SLOWSTR[12] PROGMEM = { 0x00, 0xA2, 0x2A, 0xC0, 0xD6, 0x0F, 0x02, 0x21, 0x00, 0x30, 0x55, 0x01 }; -const unsigned char INSTRUMENT_SYNSTR1[12] PROGMEM = { 0x00, 0x61, 0x21, 0x72, 0x35, 0x0F, 0x01, 0x61, 0x00, 0x62, 0x36, 0x01 }; -const unsigned char INSTRUMENT_SYNSTR2[12] PROGMEM = { 0x00, 0x21, 0x1A, 0x72, 0x23, 0x0F, 0x01, 0x21, 0x02, 0x51, 0x07, 0x00 }; -const unsigned char INSTRUMENT_CHOIR[12] PROGMEM = { 0x00, 0xE1, 0x16, 0x97, 0x31, 0x09, 0x00, 0x61, 0x00, 0x62, 0x39, 0x00 }; -const unsigned char INSTRUMENT_OOHS[12] PROGMEM = { 0x00, 0x22, 0xC3, 0x79, 0x45, 0x01, 0x00, 0x21, 0x00, 0x66, 0x27, 0x00 }; -const unsigned char INSTRUMENT_SYNVOX[12] PROGMEM = { 0x00, 0x21, 0xDE, 0x63, 0x55, 0x01, 0x01, 0x21, 0x00, 0x73, 0x46, 0x00 }; -const unsigned char INSTRUMENT_ORCHIT[12] PROGMEM = { 0x00, 0x42, 0x05, 0x86, 0xF7, 0x0A, 0x00, 0x50, 0x00, 0x74, 0x76, 0x01 }; -const unsigned char INSTRUMENT_TRUMPET[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x61, 0x02, 0x0F, 0x00, 0x61, 0x81, 0x92, 0x38, 0x00 }; -const unsigned char INSTRUMENT_TROMBONE[12] PROGMEM = { 0x00, 0x71, 0x1E, 0x52, 0x23, 0x0F, 0x00, 0x61, 0x02, 0x71, 0x19, 0x00 }; -const unsigned char INSTRUMENT_TUBA[12] PROGMEM = { 0x00, 0x21, 0x1A, 0x76, 0x16, 0x0F, 0x00, 0x21, 0x01, 0x81, 0x09, 0x00 }; -const unsigned char INSTRUMENT_MUTETRP[12] PROGMEM = { 0x00, 0x25, 0x28, 0x89, 0x2C, 0x07, 0x02, 0x20, 0x00, 0x83, 0x4B, 0x02 }; -const unsigned char INSTRUMENT_FRHORN[12] PROGMEM = { 0x00, 0x21, 0x1F, 0x79, 0x16, 0x09, 0x00, 0xA2, 0x05, 0x71, 0x59, 0x00 }; -const unsigned char INSTRUMENT_BRASS1[12] PROGMEM = { 0x00, 0x21, 0x19, 0x87, 0x16, 0x0F, 0x00, 0x21, 0x03, 0x82, 0x39, 0x00 }; -const unsigned char INSTRUMENT_SYNBRAS1[12] PROGMEM = { 0x00, 0x21, 0x17, 0x75, 0x35, 0x0F, 0x00, 0x22, 0x82, 0x84, 0x17, 0x00 }; -const unsigned char INSTRUMENT_SYNBRAS2[12] PROGMEM = { 0x00, 0x21, 0x22, 0x62, 0x58, 0x0F, 0x00, 0x21, 0x02, 0x72, 0x16, 0x00 }; -const unsigned char INSTRUMENT_SOPSAX[12] PROGMEM = { 0x00, 0xB1, 0x1B, 0x59, 0x07, 0x01, 0x01, 0xA1, 0x00, 0x7B, 0x0A, 0x00 }; -const unsigned char INSTRUMENT_ALTOSAX[12] PROGMEM = { 0x00, 0x21, 0x16, 0x9F, 0x04, 0x0B, 0x00, 0x21, 0x00, 0x85, 0x0C, 0x01 }; -const unsigned char INSTRUMENT_TENSAX[12] PROGMEM = { 0x00, 0x21, 0x0F, 0xA8, 0x20, 0x0D, 0x00, 0x23, 0x00, 0x7B, 0x0A, 0x01 }; -const unsigned char INSTRUMENT_BARISAX[12] PROGMEM = { 0x00, 0x21, 0x0F, 0x88, 0x04, 0x09, 0x00, 0x26, 0x00, 0x79, 0x18, 0x01 }; -const unsigned char INSTRUMENT_OBOE[12] PROGMEM = { 0x00, 0x31, 0x18, 0x8F, 0x05, 0x01, 0x00, 0x32, 0x01, 0x73, 0x08, 0x00 }; -const unsigned char INSTRUMENT_ENGLHORN[12] PROGMEM = { 0x00, 0xA1, 0x0A, 0x8C, 0x37, 0x01, 0x01, 0x24, 0x04, 0x77, 0x0A, 0x00 }; -const unsigned char INSTRUMENT_BASSOON[12] PROGMEM = { 0x00, 0x31, 0x04, 0xA8, 0x67, 0x0B, 0x00, 0x75, 0x00, 0x51, 0x19, 0x00 }; -const unsigned char INSTRUMENT_CLARINET[12] PROGMEM = { 0x00, 0xA2, 0x1F, 0x77, 0x26, 0x01, 0x01, 0x21, 0x01, 0x74, 0x09, 0x00 }; -const unsigned char INSTRUMENT_PICCOLO[12] PROGMEM = { 0x00, 0xE1, 0x07, 0xB8, 0x94, 0x01, 0x01, 0x21, 0x01, 0x63, 0x28, 0x00 }; -const unsigned char INSTRUMENT_FLUTE1[12] PROGMEM = { 0x00, 0xA1, 0x93, 0x87, 0x59, 0x01, 0x00, 0xE1, 0x00, 0x65, 0x0A, 0x00 }; -const unsigned char INSTRUMENT_RECORDER[12] PROGMEM = { 0x00, 0x22, 0x10, 0x9F, 0x38, 0x01, 0x00, 0x61, 0x00, 0x67, 0x29, 0x00 }; -const unsigned char INSTRUMENT_PANFLUTE[12] PROGMEM = { 0x00, 0xE2, 0x0D, 0x88, 0x9A, 0x01, 0x01, 0x21, 0x00, 0x67, 0x09, 0x00 }; -const unsigned char INSTRUMENT_BOTTLEB[12] PROGMEM = { 0x00, 0xA2, 0x10, 0x98, 0x94, 0x0F, 0x00, 0x21, 0x01, 0x6A, 0x28, 0x00 }; -const unsigned char INSTRUMENT_SHAKU[12] PROGMEM = { 0x00, 0xF1, 0x1C, 0x86, 0x26, 0x0F, 0x00, 0xF1, 0x00, 0x55, 0x27, 0x00 }; -const unsigned char INSTRUMENT_WHISTLE[12] PROGMEM = { 0x00, 0xE1, 0x3F, 0x9F, 0x09, 0x00, 0x00, 0xE1, 0x00, 0x6F, 0x08, 0x00 }; -const unsigned char INSTRUMENT_OCARINA[12] PROGMEM = { 0x00, 0xE2, 0x3B, 0xF7, 0x19, 0x01, 0x00, 0x21, 0x00, 0x7A, 0x07, 0x00 }; -const unsigned char INSTRUMENT_SQUARWAV[12] PROGMEM = { 0x00, 0x22, 0x1E, 0x92, 0x0C, 0x0F, 0x00, 0x61, 0x06, 0xA2, 0x0D, 0x00 }; -const unsigned char INSTRUMENT_SAWWAV[12] PROGMEM = { 0x00, 0x21, 0x15, 0xF4, 0x22, 0x0F, 0x01, 0x21, 0x00, 0xA3, 0x5F, 0x00 }; -const unsigned char INSTRUMENT_SYNCALLI[12] PROGMEM = { 0x00, 0xF2, 0x20, 0x47, 0x66, 0x03, 0x01, 0xF1, 0x00, 0x42, 0x27, 0x00 }; -const unsigned char INSTRUMENT_CHIFLEAD[12] PROGMEM = { 0x00, 0x61, 0x19, 0x88, 0x28, 0x0F, 0x00, 0x61, 0x05, 0xB2, 0x49, 0x00 }; -const unsigned char INSTRUMENT_CHARANG[12] PROGMEM = { 0x00, 0x21, 0x16, 0x82, 0x1B, 0x01, 0x00, 0x23, 0x00, 0xB2, 0x79, 0x01 }; -const unsigned char INSTRUMENT_SOLOVOX[12] PROGMEM = { 0x00, 0x21, 0x00, 0xCA, 0x93, 0x01, 0x00, 0x22, 0x00, 0x7A, 0x1A, 0x00 }; -const unsigned char INSTRUMENT_FIFTHSAW[12] PROGMEM = { 0x00, 0x23, 0x00, 0x92, 0xC9, 0x08, 0x01, 0x22, 0x00, 0x82, 0x28, 0x01 }; -const unsigned char INSTRUMENT_BASSLEAD[12] PROGMEM = { 0x00, 0x21, 0x1D, 0xF3, 0x7B, 0x0F, 0x00, 0x22, 0x02, 0xC3, 0x5F, 0x00 }; -const unsigned char INSTRUMENT_FANTASIA[12] PROGMEM = { 0x00, 0xE1, 0x00, 0x81, 0x25, 0x00, 0x01, 0xA6, 0x86, 0xC4, 0x95, 0x01 }; -const unsigned char INSTRUMENT_WARMPAD[12] PROGMEM = { 0x00, 0x21, 0x27, 0x31, 0x01, 0x0F, 0x00, 0x21, 0x00, 0x44, 0x15, 0x00 }; -const unsigned char INSTRUMENT_POLYSYN[12] PROGMEM = { 0x00, 0x60, 0x14, 0x83, 0x35, 0x0D, 0x02, 0x61, 0x00, 0xD1, 0x06, 0x00 }; -const unsigned char INSTRUMENT_SPACEVOX[12] PROGMEM = { 0x00, 0xE1, 0x5C, 0xD3, 0x01, 0x01, 0x01, 0x62, 0x00, 0x82, 0x37, 0x00 }; -const unsigned char INSTRUMENT_BOWEDGLS[12] PROGMEM = { 0x00, 0x28, 0x38, 0x34, 0x86, 0x01, 0x02, 0x21, 0x00, 0x41, 0x35, 0x00 }; -const unsigned char INSTRUMENT_METALPAD[12] PROGMEM = { 0x00, 0x24, 0x12, 0x52, 0xF3, 0x05, 0x01, 0x23, 0x02, 0x32, 0xF5, 0x01 }; -const unsigned char INSTRUMENT_HALOPAD[12] PROGMEM = { 0x00, 0x61, 0x1D, 0x62, 0xA6, 0x0B, 0x00, 0xA1, 0x00, 0x61, 0x26, 0x00 }; -const unsigned char INSTRUMENT_SWEEPPAD[12] PROGMEM = { 0x00, 0x22, 0x0F, 0x22, 0xD5, 0x0B, 0x01, 0x21, 0x84, 0x3F, 0x05, 0x01 }; -const unsigned char INSTRUMENT_ICERAIN[12] PROGMEM = { 0x00, 0xE3, 0x1F, 0xF9, 0x24, 0x01, 0x00, 0x31, 0x01, 0xD1, 0xF6, 0x00 }; -const unsigned char INSTRUMENT_SOUNDTRK[12] PROGMEM = { 0x00, 0x63, 0x00, 0x41, 0x55, 0x06, 0x01, 0xA2, 0x00, 0x41, 0x05, 0x01 }; -const unsigned char INSTRUMENT_CRYSTAL[12] PROGMEM = { 0x00, 0xC7, 0x25, 0xA7, 0x65, 0x01, 0x01, 0xC1, 0x05, 0xF3, 0xE4, 0x00 }; -const unsigned char INSTRUMENT_ATMOSPH[12] PROGMEM = { 0x00, 0xE3, 0x19, 0xF7, 0xB7, 0x01, 0x01, 0x61, 0x00, 0x92, 0xF5, 0x01 }; -const unsigned char INSTRUMENT_BRIGHT[12] PROGMEM = { 0x00, 0x66, 0x9B, 0xA8, 0x44, 0x0F, 0x00, 0x41, 0x04, 0xF2, 0xE4, 0x01 }; -const unsigned char INSTRUMENT_GOBLIN[12] PROGMEM = { 0x00, 0x61, 0x20, 0x22, 0x75, 0x0D, 0x00, 0x61, 0x00, 0x45, 0x25, 0x00 }; -const unsigned char INSTRUMENT_ECHODROP[12] PROGMEM = { 0x00, 0xE1, 0x21, 0xF6, 0x84, 0x0F, 0x00, 0xE1, 0x01, 0xA3, 0x36, 0x00 }; -const unsigned char INSTRUMENT_STARTHEM[12] PROGMEM = { 0x00, 0xE2, 0x14, 0x73, 0x64, 0x0B, 0x01, 0xE1, 0x01, 0x98, 0x05, 0x01 }; -const unsigned char INSTRUMENT_SITAR[12] PROGMEM = { 0x00, 0x21, 0x0B, 0x72, 0x34, 0x09, 0x00, 0x24, 0x02, 0xA3, 0xF6, 0x01 }; -const unsigned char INSTRUMENT_BANJO[12] PROGMEM = { 0x00, 0x21, 0x16, 0xF4, 0x53, 0x0D, 0x00, 0x04, 0x00, 0xF6, 0xF8, 0x00 }; -const unsigned char INSTRUMENT_SHAMISEN[12] PROGMEM = { 0x00, 0x21, 0x18, 0xDA, 0x02, 0x0D, 0x00, 0x35, 0x00, 0xF3, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_KOTO[12] PROGMEM = { 0x00, 0x25, 0x0F, 0xFA, 0x63, 0x09, 0x00, 0x02, 0x00, 0x94, 0xE5, 0x01 }; -const unsigned char INSTRUMENT_KALIMBA[12] PROGMEM = { 0x00, 0x32, 0x07, 0xF9, 0x96, 0x01, 0x00, 0x11, 0x00, 0x84, 0x44, 0x00 }; -const unsigned char INSTRUMENT_BAGPIPE[12] PROGMEM = { 0x00, 0x20, 0x0E, 0x97, 0x18, 0x09, 0x02, 0x25, 0x03, 0x83, 0x18, 0x01 }; -const unsigned char INSTRUMENT_FIDDLE[12] PROGMEM = { 0x00, 0x61, 0x18, 0xF6, 0x29, 0x01, 0x00, 0x62, 0x01, 0x78, 0x08, 0x01 }; -const unsigned char INSTRUMENT_SHANNAI[12] PROGMEM = { 0x00, 0xE6, 0x21, 0x76, 0x19, 0x0B, 0x00, 0x61, 0x03, 0x8E, 0x08, 0x01 }; -const unsigned char INSTRUMENT_TINKLBEL[12] PROGMEM = { 0x00, 0x27, 0x23, 0xF0, 0xD4, 0x01, 0x00, 0x05, 0x09, 0xF2, 0x46, 0x00 }; -const unsigned char INSTRUMENT_AGOGO[12] PROGMEM = { 0x00, 0x1C, 0x0C, 0xF9, 0x31, 0x0F, 0x01, 0x15, 0x00, 0x96, 0xE8, 0x01 }; -const unsigned char INSTRUMENT_STEELDRM[12] PROGMEM = { 0x00, 0x02, 0x00, 0x75, 0x16, 0x06, 0x02, 0x01, 0x00, 0xF6, 0xF6, 0x01 }; -const unsigned char INSTRUMENT_WOODBLOK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; -const unsigned char INSTRUMENT_TAIKO[12] PROGMEM = { 0x00, 0x02, 0x1D, 0xF5, 0x93, 0x01, 0x00, 0x00, 0x00, 0xC6, 0x45, 0x00 }; -const unsigned char INSTRUMENT_MELOTOM[12] PROGMEM = { 0x00, 0x11, 0x15, 0xF5, 0x32, 0x05, 0x00, 0x10, 0x00, 0xF4, 0xB4, 0x00 }; -const unsigned char INSTRUMENT_SYNDRUM[12] PROGMEM = { 0x00, 0x22, 0x06, 0xFA, 0x99, 0x09, 0x00, 0x01, 0x00, 0xD5, 0x25, 0x00 }; -const unsigned char INSTRUMENT_REVRSCYM[12] PROGMEM = { 0x00, 0x2E, 0x00, 0xFF, 0x00, 0x0F, 0x02, 0x0E, 0x0E, 0x21, 0x2D, 0x00 }; -const unsigned char INSTRUMENT_FRETNOIS[12] PROGMEM = { 0x00, 0x30, 0x0B, 0x56, 0xE4, 0x01, 0x01, 0x17, 0x00, 0x55, 0x87, 0x02 }; -const unsigned char INSTRUMENT_BRTHNOIS[12] PROGMEM = { 0x00, 0x24, 0x00, 0xFF, 0x03, 0x0D, 0x00, 0x05, 0x08, 0x98, 0x87, 0x01 }; -const unsigned char INSTRUMENT_SEASHORE[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xF0, 0x00, 0x0F, 0x02, 0x0A, 0x04, 0x17, 0x04, 0x03 }; -const unsigned char INSTRUMENT_BIRDS[12] PROGMEM = { 0x00, 0x20, 0x08, 0xF6, 0xF7, 0x01, 0x00, 0x0E, 0x05, 0x77, 0xF9, 0x02 }; -const unsigned char INSTRUMENT_TELEPHON[12] PROGMEM = { 0x00, 0x20, 0x14, 0xF1, 0x08, 0x01, 0x00, 0x2E, 0x02, 0xF4, 0x08, 0x00 }; -const unsigned char INSTRUMENT_HELICOPT[12] PROGMEM = { 0x00, 0x20, 0x04, 0xF2, 0x00, 0x03, 0x01, 0x23, 0x00, 0x36, 0x05, 0x01 }; -const unsigned char INSTRUMENT_APPLAUSE[12] PROGMEM = { 0x00, 0x2E, 0x00, 0xFF, 0x02, 0x0F, 0x00, 0x2A, 0x05, 0x32, 0x55, 0x03 }; -const unsigned char INSTRUMENT_GUNSHOT[12] PROGMEM = { 0x00, 0x20, 0x00, 0xA1, 0xEF, 0x0F, 0x00, 0x10, 0x00, 0xF3, 0xDF, 0x00 }; +#ifndef _MIDI_INST2OP_H_ + #define _MIDI_INST2OP_H_ + const unsigned char INSTRUMENT_PIANO1[12] PROGMEM = { 0x00, 0x33, 0x5A, 0xB2, 0x50, 0x01, 0x00, 0x31, 0x00, 0xB1, 0xF5, 0x01 }; + const unsigned char INSTRUMENT_PIANO2[12] PROGMEM = { 0x00, 0x31, 0x49, 0xF2, 0x53, 0x07, 0x01, 0x11, 0x03, 0xF1, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_PIANO3[12] PROGMEM = { 0x00, 0x31, 0x95, 0xD1, 0x83, 0x0D, 0x01, 0x32, 0x03, 0xC1, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_HONKTONK[12] PROGMEM = { 0x00, 0x34, 0x9B, 0xF3, 0x63, 0x01, 0x01, 0x11, 0x00, 0x92, 0xF5, 0x01 }; + const unsigned char INSTRUMENT_EP1[12] PROGMEM = { 0x00, 0x27, 0x28, 0xF8, 0xB7, 0x01, 0x02, 0x91, 0x00, 0xF1, 0xF9, 0x00 }; + const unsigned char INSTRUMENT_EP2[12] PROGMEM = { 0x00, 0x1A, 0x2D, 0xF3, 0xEE, 0x01, 0x01, 0x11, 0x00, 0xF1, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_HARPSIC[12] PROGMEM = { 0x00, 0x35, 0x95, 0xF2, 0x58, 0x0F, 0x01, 0x32, 0x02, 0x81, 0xF6, 0x01 }; + const unsigned char INSTRUMENT_CLAVIC[12] PROGMEM = { 0x00, 0x31, 0x85, 0xC9, 0x40, 0x01, 0x00, 0x35, 0x00, 0xC2, 0xB9, 0x01 }; + const unsigned char INSTRUMENT_CELESTA[12] PROGMEM = { 0x00, 0x09, 0x15, 0xC7, 0x64, 0x08, 0x00, 0x01, 0x05, 0xB2, 0x35, 0x00 }; + const unsigned char INSTRUMENT_GLOCK[12] PROGMEM = { 0x00, 0x06, 0x03, 0xF4, 0x44, 0x00, 0x01, 0x01, 0x1B, 0xF2, 0x34, 0x00 }; + const unsigned char INSTRUMENT_MUSICBOX[12] PROGMEM = { 0x00, 0x04, 0x06, 0xA9, 0x24, 0x0A, 0x01, 0x01, 0x01, 0xF5, 0x74, 0x00 }; + const unsigned char INSTRUMENT_VIBES[12] PROGMEM = { 0x00, 0xD4, 0x00, 0xF6, 0x33, 0x00, 0x00, 0xF1, 0x00, 0x61, 0xE3, 0x00 }; + const unsigned char INSTRUMENT_MARIMBA[12] PROGMEM = { 0x00, 0xD4, 0x00, 0xF7, 0xE8, 0x04, 0x00, 0xD1, 0x00, 0xA4, 0x64, 0x00 }; + const unsigned char INSTRUMENT_XYLO[12] PROGMEM = { 0x00, 0x36, 0x16, 0xF7, 0xF7, 0x01, 0x00, 0x31, 0x07, 0xB5, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_TUBEBELL[12] PROGMEM = { 0x00, 0x03, 0x1B, 0xA2, 0x43, 0x0B, 0x00, 0x00, 0x00, 0xF3, 0x74, 0x00 }; + const unsigned char INSTRUMENT_SANTUR[12] PROGMEM = { 0x00, 0xC3, 0x8E, 0xF8, 0x35, 0x01, 0x01, 0x11, 0x00, 0xC3, 0x94, 0x01 }; + const unsigned char INSTRUMENT_ORGAN1[12] PROGMEM = { 0x00, 0xE2, 0x07, 0xF4, 0x1B, 0x06, 0x01, 0xE0, 0x00, 0xF4, 0x0D, 0x01 }; + const unsigned char INSTRUMENT_ORGAN2[12] PROGMEM = { 0x00, 0xF2, 0x00, 0xF6, 0x2C, 0x04, 0x00, 0xF0, 0x00, 0xF5, 0x0B, 0x01 }; + const unsigned char INSTRUMENT_ORGAN3[12] PROGMEM = { 0x00, 0xF1, 0x06, 0xB6, 0x15, 0x0A, 0x00, 0xF0, 0x00, 0xBF, 0x07, 0x00 }; + const unsigned char INSTRUMENT_PIPEORG[12] PROGMEM = { 0x00, 0x22, 0x03, 0x79, 0x16, 0x08, 0x01, 0xE0, 0x00, 0x6D, 0x08, 0x01 }; + const unsigned char INSTRUMENT_REEDORG[12] PROGMEM = { 0x00, 0x31, 0x27, 0x63, 0x06, 0x01, 0x00, 0x72, 0x00, 0x51, 0x17, 0x01 }; + const unsigned char INSTRUMENT_ACORDIAN[12] PROGMEM = { 0x00, 0xB4, 0x1D, 0x53, 0x16, 0x0F, 0x01, 0x71, 0x00, 0x51, 0x17, 0x01 }; + const unsigned char INSTRUMENT_HARMONIC[12] PROGMEM = { 0x00, 0x25, 0x29, 0x97, 0x15, 0x01, 0x00, 0x32, 0x00, 0x53, 0x08, 0x01 }; + const unsigned char INSTRUMENT_BANDNEON[12] PROGMEM = { 0x00, 0x24, 0x9E, 0x67, 0x15, 0x0F, 0x00, 0x31, 0x00, 0x53, 0x06, 0x01 }; + const unsigned char INSTRUMENT_NYLONGT[12] PROGMEM = { 0x00, 0x13, 0x27, 0xA3, 0xB4, 0x05, 0x01, 0x31, 0x00, 0xD2, 0xF8, 0x00 }; + const unsigned char INSTRUMENT_STEELGT[12] PROGMEM = { 0x00, 0x17, 0xA3, 0xF3, 0x32, 0x01, 0x00, 0x11, 0x00, 0xE2, 0xC7, 0x01 }; + const unsigned char INSTRUMENT_JAZZGT[12] PROGMEM = { 0x00, 0x33, 0x24, 0xD2, 0xC1, 0x0F, 0x01, 0x31, 0x00, 0xF1, 0x9C, 0x00 }; + const unsigned char INSTRUMENT_CLEANGT[12] PROGMEM = { 0x00, 0x31, 0x05, 0xF8, 0x44, 0x01, 0x00, 0x32, 0x02, 0xF2, 0xC9, 0x01 }; + const unsigned char INSTRUMENT_MUTEGT[12] PROGMEM = { 0x00, 0x21, 0x09, 0x9C, 0x7B, 0x07, 0x00, 0x02, 0x03, 0x95, 0xFB, 0x00 }; + const unsigned char INSTRUMENT_OVERDGT[12] PROGMEM = { 0x00, 0x21, 0x84, 0x81, 0x98, 0x07, 0x01, 0x21, 0x04, 0xA1, 0x59, 0x00 }; + const unsigned char INSTRUMENT_DISTGT[12] PROGMEM = { 0x00, 0xB1, 0x0C, 0x78, 0x43, 0x01, 0x00, 0x22, 0x03, 0x91, 0xFC, 0x03 }; + const unsigned char INSTRUMENT_GTHARMS[12] PROGMEM = { 0x00, 0x00, 0x0A, 0x82, 0x8C, 0x09, 0x00, 0x08, 0x02, 0xB4, 0xEC, 0x00 }; + const unsigned char INSTRUMENT_ACOUBASS[12] PROGMEM = { 0x00, 0x21, 0x13, 0xAB, 0x46, 0x01, 0x00, 0x21, 0x00, 0x93, 0xF7, 0x00 }; + const unsigned char INSTRUMENT_FINGBASS[12] PROGMEM = { 0x00, 0x01, 0x0A, 0xF9, 0x32, 0x01, 0x00, 0x22, 0x04, 0xC1, 0x58, 0x00 }; + const unsigned char INSTRUMENT_PICKBASS[12] PROGMEM = { 0x00, 0x21, 0x07, 0xFA, 0x77, 0x0B, 0x00, 0x22, 0x02, 0xC3, 0x6A, 0x00 }; + const unsigned char INSTRUMENT_FRETLESS[12] PROGMEM = { 0x00, 0x21, 0x17, 0x71, 0x57, 0x0B, 0x00, 0x21, 0x00, 0x62, 0x87, 0x00 }; + const unsigned char INSTRUMENT_SLAPBAS1[12] PROGMEM = { 0x00, 0x25, 0x01, 0xFA, 0x78, 0x07, 0x01, 0x12, 0x00, 0xF3, 0x97, 0x00 }; + const unsigned char INSTRUMENT_SLAPBAS2[12] PROGMEM = { 0x00, 0x21, 0x03, 0xFA, 0x88, 0x0D, 0x00, 0x13, 0x00, 0xB3, 0x97, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS1[12] PROGMEM = { 0x00, 0x21, 0x09, 0xF5, 0x7F, 0x09, 0x01, 0x23, 0x04, 0xF3, 0xCC, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS2[12] PROGMEM = { 0x00, 0x01, 0x10, 0xA3, 0x9B, 0x09, 0x00, 0x01, 0x00, 0x93, 0xAA, 0x00 }; + const unsigned char INSTRUMENT_VIOLIN[12] PROGMEM = { 0x00, 0xE2, 0x19, 0xF6, 0x29, 0x0D, 0x01, 0xE1, 0x00, 0x78, 0x08, 0x01 }; + const unsigned char INSTRUMENT_VIOLA[12] PROGMEM = { 0x00, 0xE2, 0x1C, 0xF6, 0x29, 0x0D, 0x01, 0xE1, 0x00, 0x78, 0x08, 0x01 }; + const unsigned char INSTRUMENT_CELLO[12] PROGMEM = { 0x00, 0x61, 0x19, 0x69, 0x16, 0x0B, 0x01, 0x61, 0x00, 0x54, 0x27, 0x01 }; + const unsigned char INSTRUMENT_CONTRAB[12] PROGMEM = { 0x00, 0x71, 0x18, 0x82, 0x31, 0x0D, 0x01, 0x32, 0x00, 0x61, 0x56, 0x00 }; + const unsigned char INSTRUMENT_TREMSTR[12] PROGMEM = { 0x00, 0xE2, 0x23, 0x70, 0x06, 0x0D, 0x01, 0xE1, 0x00, 0x75, 0x16, 0x01 }; + const unsigned char INSTRUMENT_PIZZ[12] PROGMEM = { 0x00, 0x02, 0x00, 0x88, 0xE6, 0x08, 0x00, 0x61, 0x00, 0xF5, 0xF6, 0x01 }; + const unsigned char INSTRUMENT_HARP[12] PROGMEM = { 0x00, 0x12, 0x20, 0xF6, 0xD5, 0x0F, 0x01, 0x11, 0x80, 0xF3, 0xE3, 0x00 }; + const unsigned char INSTRUMENT_TIMPANI[12] PROGMEM = { 0x00, 0x61, 0x0E, 0xF4, 0xF4, 0x01, 0x01, 0x00, 0x00, 0xB5, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_STRINGS[12] PROGMEM = { 0x00, 0x61, 0x1E, 0x9C, 0x04, 0x0F, 0x01, 0x21, 0x80, 0x71, 0x16, 0x00 }; + const unsigned char INSTRUMENT_SLOWSTR[12] PROGMEM = { 0x00, 0xA2, 0x2A, 0xC0, 0xD6, 0x0F, 0x02, 0x21, 0x00, 0x30, 0x55, 0x01 }; + const unsigned char INSTRUMENT_SYNSTR1[12] PROGMEM = { 0x00, 0x61, 0x21, 0x72, 0x35, 0x0F, 0x01, 0x61, 0x00, 0x62, 0x36, 0x01 }; + const unsigned char INSTRUMENT_SYNSTR2[12] PROGMEM = { 0x00, 0x21, 0x1A, 0x72, 0x23, 0x0F, 0x01, 0x21, 0x02, 0x51, 0x07, 0x00 }; + const unsigned char INSTRUMENT_CHOIR[12] PROGMEM = { 0x00, 0xE1, 0x16, 0x97, 0x31, 0x09, 0x00, 0x61, 0x00, 0x62, 0x39, 0x00 }; + const unsigned char INSTRUMENT_OOHS[12] PROGMEM = { 0x00, 0x22, 0xC3, 0x79, 0x45, 0x01, 0x00, 0x21, 0x00, 0x66, 0x27, 0x00 }; + const unsigned char INSTRUMENT_SYNVOX[12] PROGMEM = { 0x00, 0x21, 0xDE, 0x63, 0x55, 0x01, 0x01, 0x21, 0x00, 0x73, 0x46, 0x00 }; + const unsigned char INSTRUMENT_ORCHIT[12] PROGMEM = { 0x00, 0x42, 0x05, 0x86, 0xF7, 0x0A, 0x00, 0x50, 0x00, 0x74, 0x76, 0x01 }; + const unsigned char INSTRUMENT_TRUMPET[12] PROGMEM = { 0x00, 0x31, 0x1C, 0x61, 0x02, 0x0F, 0x00, 0x61, 0x81, 0x92, 0x38, 0x00 }; + const unsigned char INSTRUMENT_TROMBONE[12] PROGMEM = { 0x00, 0x71, 0x1E, 0x52, 0x23, 0x0F, 0x00, 0x61, 0x02, 0x71, 0x19, 0x00 }; + const unsigned char INSTRUMENT_TUBA[12] PROGMEM = { 0x00, 0x21, 0x1A, 0x76, 0x16, 0x0F, 0x00, 0x21, 0x01, 0x81, 0x09, 0x00 }; + const unsigned char INSTRUMENT_MUTETRP[12] PROGMEM = { 0x00, 0x25, 0x28, 0x89, 0x2C, 0x07, 0x02, 0x20, 0x00, 0x83, 0x4B, 0x02 }; + const unsigned char INSTRUMENT_FRHORN[12] PROGMEM = { 0x00, 0x21, 0x1F, 0x79, 0x16, 0x09, 0x00, 0xA2, 0x05, 0x71, 0x59, 0x00 }; + const unsigned char INSTRUMENT_BRASS1[12] PROGMEM = { 0x00, 0x21, 0x19, 0x87, 0x16, 0x0F, 0x00, 0x21, 0x03, 0x82, 0x39, 0x00 }; + const unsigned char INSTRUMENT_SYNBRAS1[12] PROGMEM = { 0x00, 0x21, 0x17, 0x75, 0x35, 0x0F, 0x00, 0x22, 0x82, 0x84, 0x17, 0x00 }; + const unsigned char INSTRUMENT_SYNBRAS2[12] PROGMEM = { 0x00, 0x21, 0x22, 0x62, 0x58, 0x0F, 0x00, 0x21, 0x02, 0x72, 0x16, 0x00 }; + const unsigned char INSTRUMENT_SOPSAX[12] PROGMEM = { 0x00, 0xB1, 0x1B, 0x59, 0x07, 0x01, 0x01, 0xA1, 0x00, 0x7B, 0x0A, 0x00 }; + const unsigned char INSTRUMENT_ALTOSAX[12] PROGMEM = { 0x00, 0x21, 0x16, 0x9F, 0x04, 0x0B, 0x00, 0x21, 0x00, 0x85, 0x0C, 0x01 }; + const unsigned char INSTRUMENT_TENSAX[12] PROGMEM = { 0x00, 0x21, 0x0F, 0xA8, 0x20, 0x0D, 0x00, 0x23, 0x00, 0x7B, 0x0A, 0x01 }; + const unsigned char INSTRUMENT_BARISAX[12] PROGMEM = { 0x00, 0x21, 0x0F, 0x88, 0x04, 0x09, 0x00, 0x26, 0x00, 0x79, 0x18, 0x01 }; + const unsigned char INSTRUMENT_OBOE[12] PROGMEM = { 0x00, 0x31, 0x18, 0x8F, 0x05, 0x01, 0x00, 0x32, 0x01, 0x73, 0x08, 0x00 }; + const unsigned char INSTRUMENT_ENGLHORN[12] PROGMEM = { 0x00, 0xA1, 0x0A, 0x8C, 0x37, 0x01, 0x01, 0x24, 0x04, 0x77, 0x0A, 0x00 }; + const unsigned char INSTRUMENT_BASSOON[12] PROGMEM = { 0x00, 0x31, 0x04, 0xA8, 0x67, 0x0B, 0x00, 0x75, 0x00, 0x51, 0x19, 0x00 }; + const unsigned char INSTRUMENT_CLARINET[12] PROGMEM = { 0x00, 0xA2, 0x1F, 0x77, 0x26, 0x01, 0x01, 0x21, 0x01, 0x74, 0x09, 0x00 }; + const unsigned char INSTRUMENT_PICCOLO[12] PROGMEM = { 0x00, 0xE1, 0x07, 0xB8, 0x94, 0x01, 0x01, 0x21, 0x01, 0x63, 0x28, 0x00 }; + const unsigned char INSTRUMENT_FLUTE1[12] PROGMEM = { 0x00, 0xA1, 0x93, 0x87, 0x59, 0x01, 0x00, 0xE1, 0x00, 0x65, 0x0A, 0x00 }; + const unsigned char INSTRUMENT_RECORDER[12] PROGMEM = { 0x00, 0x22, 0x10, 0x9F, 0x38, 0x01, 0x00, 0x61, 0x00, 0x67, 0x29, 0x00 }; + const unsigned char INSTRUMENT_PANFLUTE[12] PROGMEM = { 0x00, 0xE2, 0x0D, 0x88, 0x9A, 0x01, 0x01, 0x21, 0x00, 0x67, 0x09, 0x00 }; + const unsigned char INSTRUMENT_BOTTLEB[12] PROGMEM = { 0x00, 0xA2, 0x10, 0x98, 0x94, 0x0F, 0x00, 0x21, 0x01, 0x6A, 0x28, 0x00 }; + const unsigned char INSTRUMENT_SHAKU[12] PROGMEM = { 0x00, 0xF1, 0x1C, 0x86, 0x26, 0x0F, 0x00, 0xF1, 0x00, 0x55, 0x27, 0x00 }; + const unsigned char INSTRUMENT_WHISTLE[12] PROGMEM = { 0x00, 0xE1, 0x3F, 0x9F, 0x09, 0x00, 0x00, 0xE1, 0x00, 0x6F, 0x08, 0x00 }; + const unsigned char INSTRUMENT_OCARINA[12] PROGMEM = { 0x00, 0xE2, 0x3B, 0xF7, 0x19, 0x01, 0x00, 0x21, 0x00, 0x7A, 0x07, 0x00 }; + const unsigned char INSTRUMENT_SQUARWAV[12] PROGMEM = { 0x00, 0x22, 0x1E, 0x92, 0x0C, 0x0F, 0x00, 0x61, 0x06, 0xA2, 0x0D, 0x00 }; + const unsigned char INSTRUMENT_SAWWAV[12] PROGMEM = { 0x00, 0x21, 0x15, 0xF4, 0x22, 0x0F, 0x01, 0x21, 0x00, 0xA3, 0x5F, 0x00 }; + const unsigned char INSTRUMENT_SYNCALLI[12] PROGMEM = { 0x00, 0xF2, 0x20, 0x47, 0x66, 0x03, 0x01, 0xF1, 0x00, 0x42, 0x27, 0x00 }; + const unsigned char INSTRUMENT_CHIFLEAD[12] PROGMEM = { 0x00, 0x61, 0x19, 0x88, 0x28, 0x0F, 0x00, 0x61, 0x05, 0xB2, 0x49, 0x00 }; + const unsigned char INSTRUMENT_CHARANG[12] PROGMEM = { 0x00, 0x21, 0x16, 0x82, 0x1B, 0x01, 0x00, 0x23, 0x00, 0xB2, 0x79, 0x01 }; + const unsigned char INSTRUMENT_SOLOVOX[12] PROGMEM = { 0x00, 0x21, 0x00, 0xCA, 0x93, 0x01, 0x00, 0x22, 0x00, 0x7A, 0x1A, 0x00 }; + const unsigned char INSTRUMENT_FIFTHSAW[12] PROGMEM = { 0x00, 0x23, 0x00, 0x92, 0xC9, 0x08, 0x01, 0x22, 0x00, 0x82, 0x28, 0x01 }; + const unsigned char INSTRUMENT_BASSLEAD[12] PROGMEM = { 0x00, 0x21, 0x1D, 0xF3, 0x7B, 0x0F, 0x00, 0x22, 0x02, 0xC3, 0x5F, 0x00 }; + const unsigned char INSTRUMENT_FANTASIA[12] PROGMEM = { 0x00, 0xE1, 0x00, 0x81, 0x25, 0x00, 0x01, 0xA6, 0x86, 0xC4, 0x95, 0x01 }; + const unsigned char INSTRUMENT_WARMPAD[12] PROGMEM = { 0x00, 0x21, 0x27, 0x31, 0x01, 0x0F, 0x00, 0x21, 0x00, 0x44, 0x15, 0x00 }; + const unsigned char INSTRUMENT_POLYSYN[12] PROGMEM = { 0x00, 0x60, 0x14, 0x83, 0x35, 0x0D, 0x02, 0x61, 0x00, 0xD1, 0x06, 0x00 }; + const unsigned char INSTRUMENT_SPACEVOX[12] PROGMEM = { 0x00, 0xE1, 0x5C, 0xD3, 0x01, 0x01, 0x01, 0x62, 0x00, 0x82, 0x37, 0x00 }; + const unsigned char INSTRUMENT_BOWEDGLS[12] PROGMEM = { 0x00, 0x28, 0x38, 0x34, 0x86, 0x01, 0x02, 0x21, 0x00, 0x41, 0x35, 0x00 }; + const unsigned char INSTRUMENT_METALPAD[12] PROGMEM = { 0x00, 0x24, 0x12, 0x52, 0xF3, 0x05, 0x01, 0x23, 0x02, 0x32, 0xF5, 0x01 }; + const unsigned char INSTRUMENT_HALOPAD[12] PROGMEM = { 0x00, 0x61, 0x1D, 0x62, 0xA6, 0x0B, 0x00, 0xA1, 0x00, 0x61, 0x26, 0x00 }; + const unsigned char INSTRUMENT_SWEEPPAD[12] PROGMEM = { 0x00, 0x22, 0x0F, 0x22, 0xD5, 0x0B, 0x01, 0x21, 0x84, 0x3F, 0x05, 0x01 }; + const unsigned char INSTRUMENT_ICERAIN[12] PROGMEM = { 0x00, 0xE3, 0x1F, 0xF9, 0x24, 0x01, 0x00, 0x31, 0x01, 0xD1, 0xF6, 0x00 }; + const unsigned char INSTRUMENT_SOUNDTRK[12] PROGMEM = { 0x00, 0x63, 0x00, 0x41, 0x55, 0x06, 0x01, 0xA2, 0x00, 0x41, 0x05, 0x01 }; + const unsigned char INSTRUMENT_CRYSTAL[12] PROGMEM = { 0x00, 0xC7, 0x25, 0xA7, 0x65, 0x01, 0x01, 0xC1, 0x05, 0xF3, 0xE4, 0x00 }; + const unsigned char INSTRUMENT_ATMOSPH[12] PROGMEM = { 0x00, 0xE3, 0x19, 0xF7, 0xB7, 0x01, 0x01, 0x61, 0x00, 0x92, 0xF5, 0x01 }; + const unsigned char INSTRUMENT_BRIGHT[12] PROGMEM = { 0x00, 0x66, 0x9B, 0xA8, 0x44, 0x0F, 0x00, 0x41, 0x04, 0xF2, 0xE4, 0x01 }; + const unsigned char INSTRUMENT_GOBLIN[12] PROGMEM = { 0x00, 0x61, 0x20, 0x22, 0x75, 0x0D, 0x00, 0x61, 0x00, 0x45, 0x25, 0x00 }; + const unsigned char INSTRUMENT_ECHODROP[12] PROGMEM = { 0x00, 0xE1, 0x21, 0xF6, 0x84, 0x0F, 0x00, 0xE1, 0x01, 0xA3, 0x36, 0x00 }; + const unsigned char INSTRUMENT_STARTHEM[12] PROGMEM = { 0x00, 0xE2, 0x14, 0x73, 0x64, 0x0B, 0x01, 0xE1, 0x01, 0x98, 0x05, 0x01 }; + const unsigned char INSTRUMENT_SITAR[12] PROGMEM = { 0x00, 0x21, 0x0B, 0x72, 0x34, 0x09, 0x00, 0x24, 0x02, 0xA3, 0xF6, 0x01 }; + const unsigned char INSTRUMENT_BANJO[12] PROGMEM = { 0x00, 0x21, 0x16, 0xF4, 0x53, 0x0D, 0x00, 0x04, 0x00, 0xF6, 0xF8, 0x00 }; + const unsigned char INSTRUMENT_SHAMISEN[12] PROGMEM = { 0x00, 0x21, 0x18, 0xDA, 0x02, 0x0D, 0x00, 0x35, 0x00, 0xF3, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_KOTO[12] PROGMEM = { 0x00, 0x25, 0x0F, 0xFA, 0x63, 0x09, 0x00, 0x02, 0x00, 0x94, 0xE5, 0x01 }; + const unsigned char INSTRUMENT_KALIMBA[12] PROGMEM = { 0x00, 0x32, 0x07, 0xF9, 0x96, 0x01, 0x00, 0x11, 0x00, 0x84, 0x44, 0x00 }; + const unsigned char INSTRUMENT_BAGPIPE[12] PROGMEM = { 0x00, 0x20, 0x0E, 0x97, 0x18, 0x09, 0x02, 0x25, 0x03, 0x83, 0x18, 0x01 }; + const unsigned char INSTRUMENT_FIDDLE[12] PROGMEM = { 0x00, 0x61, 0x18, 0xF6, 0x29, 0x01, 0x00, 0x62, 0x01, 0x78, 0x08, 0x01 }; + const unsigned char INSTRUMENT_SHANNAI[12] PROGMEM = { 0x00, 0xE6, 0x21, 0x76, 0x19, 0x0B, 0x00, 0x61, 0x03, 0x8E, 0x08, 0x01 }; + const unsigned char INSTRUMENT_TINKLBEL[12] PROGMEM = { 0x00, 0x27, 0x23, 0xF0, 0xD4, 0x01, 0x00, 0x05, 0x09, 0xF2, 0x46, 0x00 }; + const unsigned char INSTRUMENT_AGOGO[12] PROGMEM = { 0x00, 0x1C, 0x0C, 0xF9, 0x31, 0x0F, 0x01, 0x15, 0x00, 0x96, 0xE8, 0x01 }; + const unsigned char INSTRUMENT_STEELDRM[12] PROGMEM = { 0x00, 0x02, 0x00, 0x75, 0x16, 0x06, 0x02, 0x01, 0x00, 0xF6, 0xF6, 0x01 }; + const unsigned char INSTRUMENT_WOODBLOK[12] PROGMEM = { 0x00, 0x25, 0x1B, 0xFA, 0xF2, 0x01, 0x00, 0x12, 0x00, 0xF6, 0x9A, 0x00 }; + const unsigned char INSTRUMENT_TAIKO[12] PROGMEM = { 0x00, 0x02, 0x1D, 0xF5, 0x93, 0x01, 0x00, 0x00, 0x00, 0xC6, 0x45, 0x00 }; + const unsigned char INSTRUMENT_MELOTOM[12] PROGMEM = { 0x00, 0x11, 0x15, 0xF5, 0x32, 0x05, 0x00, 0x10, 0x00, 0xF4, 0xB4, 0x00 }; + const unsigned char INSTRUMENT_SYNDRUM[12] PROGMEM = { 0x00, 0x22, 0x06, 0xFA, 0x99, 0x09, 0x00, 0x01, 0x00, 0xD5, 0x25, 0x00 }; + const unsigned char INSTRUMENT_REVRSCYM[12] PROGMEM = { 0x00, 0x2E, 0x00, 0xFF, 0x00, 0x0F, 0x02, 0x0E, 0x0E, 0x21, 0x2D, 0x00 }; + const unsigned char INSTRUMENT_FRETNOIS[12] PROGMEM = { 0x00, 0x30, 0x0B, 0x56, 0xE4, 0x01, 0x01, 0x17, 0x00, 0x55, 0x87, 0x02 }; + const unsigned char INSTRUMENT_BRTHNOIS[12] PROGMEM = { 0x00, 0x24, 0x00, 0xFF, 0x03, 0x0D, 0x00, 0x05, 0x08, 0x98, 0x87, 0x01 }; + const unsigned char INSTRUMENT_SEASHORE[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xF0, 0x00, 0x0F, 0x02, 0x0A, 0x04, 0x17, 0x04, 0x03 }; + const unsigned char INSTRUMENT_BIRDS[12] PROGMEM = { 0x00, 0x20, 0x08, 0xF6, 0xF7, 0x01, 0x00, 0x0E, 0x05, 0x77, 0xF9, 0x02 }; + const unsigned char INSTRUMENT_TELEPHON[12] PROGMEM = { 0x00, 0x20, 0x14, 0xF1, 0x08, 0x01, 0x00, 0x2E, 0x02, 0xF4, 0x08, 0x00 }; + const unsigned char INSTRUMENT_HELICOPT[12] PROGMEM = { 0x00, 0x20, 0x04, 0xF2, 0x00, 0x03, 0x01, 0x23, 0x00, 0x36, 0x05, 0x01 }; + const unsigned char INSTRUMENT_APPLAUSE[12] PROGMEM = { 0x00, 0x2E, 0x00, 0xFF, 0x02, 0x0F, 0x00, 0x2A, 0x05, 0x32, 0x55, 0x03 }; + const unsigned char INSTRUMENT_GUNSHOT[12] PROGMEM = { 0x00, 0x20, 0x00, 0xA1, 0xEF, 0x0F, 0x00, 0x10, 0x00, 0xF3, 0xDF, 0x00 }; -// Instrument pointer array to access instruments by MIDI program. -const unsigned char *midiInstruments[] = { - INSTRUMENT_PIANO1, INSTRUMENT_PIANO2, INSTRUMENT_PIANO3, INSTRUMENT_HONKTONK, INSTRUMENT_EP1, INSTRUMENT_EP2, - INSTRUMENT_HARPSIC, INSTRUMENT_CLAVIC, INSTRUMENT_CELESTA, INSTRUMENT_GLOCK, INSTRUMENT_MUSICBOX, INSTRUMENT_VIBES, - INSTRUMENT_MARIMBA, INSTRUMENT_XYLO, INSTRUMENT_TUBEBELL, INSTRUMENT_SANTUR, INSTRUMENT_ORGAN1, INSTRUMENT_ORGAN2, - INSTRUMENT_ORGAN3, INSTRUMENT_PIPEORG, INSTRUMENT_REEDORG, INSTRUMENT_ACORDIAN, INSTRUMENT_HARMONIC, INSTRUMENT_BANDNEON, - INSTRUMENT_NYLONGT, INSTRUMENT_STEELGT, INSTRUMENT_JAZZGT, INSTRUMENT_CLEANGT, INSTRUMENT_MUTEGT, INSTRUMENT_OVERDGT, - INSTRUMENT_DISTGT, INSTRUMENT_GTHARMS, INSTRUMENT_ACOUBASS, INSTRUMENT_FINGBASS, INSTRUMENT_PICKBASS, INSTRUMENT_FRETLESS, - INSTRUMENT_SLAPBAS1, INSTRUMENT_SLAPBAS2, INSTRUMENT_SYNBASS1, INSTRUMENT_SYNBASS2, INSTRUMENT_VIOLIN, INSTRUMENT_VIOLA, - INSTRUMENT_CELLO, INSTRUMENT_CONTRAB, INSTRUMENT_TREMSTR, INSTRUMENT_PIZZ, INSTRUMENT_HARP, INSTRUMENT_TIMPANI, - INSTRUMENT_STRINGS, INSTRUMENT_SLOWSTR, INSTRUMENT_SYNSTR1, INSTRUMENT_SYNSTR2, INSTRUMENT_CHOIR, INSTRUMENT_OOHS, - INSTRUMENT_SYNVOX, INSTRUMENT_ORCHIT, INSTRUMENT_TRUMPET, INSTRUMENT_TROMBONE, INSTRUMENT_TUBA, INSTRUMENT_MUTETRP, - INSTRUMENT_FRHORN, INSTRUMENT_BRASS1, INSTRUMENT_SYNBRAS1, INSTRUMENT_SYNBRAS2, INSTRUMENT_SOPSAX, INSTRUMENT_ALTOSAX, - INSTRUMENT_TENSAX, INSTRUMENT_BARISAX, INSTRUMENT_OBOE, INSTRUMENT_ENGLHORN, INSTRUMENT_BASSOON, INSTRUMENT_CLARINET, - INSTRUMENT_PICCOLO, INSTRUMENT_FLUTE1, INSTRUMENT_RECORDER, INSTRUMENT_PANFLUTE, INSTRUMENT_BOTTLEB, INSTRUMENT_SHAKU, - INSTRUMENT_WHISTLE, INSTRUMENT_OCARINA, INSTRUMENT_SQUARWAV, INSTRUMENT_SAWWAV, INSTRUMENT_SYNCALLI, INSTRUMENT_CHIFLEAD, - INSTRUMENT_CHARANG, INSTRUMENT_SOLOVOX, INSTRUMENT_FIFTHSAW, INSTRUMENT_BASSLEAD, INSTRUMENT_FANTASIA, INSTRUMENT_WARMPAD, - INSTRUMENT_POLYSYN, INSTRUMENT_SPACEVOX, INSTRUMENT_BOWEDGLS, INSTRUMENT_METALPAD, INSTRUMENT_HALOPAD, INSTRUMENT_SWEEPPAD, - INSTRUMENT_ICERAIN, INSTRUMENT_SOUNDTRK, INSTRUMENT_CRYSTAL, INSTRUMENT_ATMOSPH, INSTRUMENT_BRIGHT, INSTRUMENT_GOBLIN, - INSTRUMENT_ECHODROP, INSTRUMENT_STARTHEM, INSTRUMENT_SITAR, INSTRUMENT_BANJO, INSTRUMENT_SHAMISEN, INSTRUMENT_KOTO, - INSTRUMENT_KALIMBA, INSTRUMENT_BAGPIPE, INSTRUMENT_FIDDLE, INSTRUMENT_SHANNAI, INSTRUMENT_TINKLBEL, INSTRUMENT_AGOGO, - INSTRUMENT_STEELDRM, INSTRUMENT_WOODBLOK, INSTRUMENT_TAIKO, INSTRUMENT_MELOTOM, INSTRUMENT_SYNDRUM, INSTRUMENT_REVRSCYM, - INSTRUMENT_FRETNOIS, INSTRUMENT_BRTHNOIS, INSTRUMENT_SEASHORE, INSTRUMENT_BIRDS, INSTRUMENT_TELEPHON, INSTRUMENT_HELICOPT, - INSTRUMENT_APPLAUSE, INSTRUMENT_GUNSHOT -}; + + // Instrument pointer array to access instruments by MIDI program. + const unsigned char *midiInstruments[] = { + INSTRUMENT_PIANO1, INSTRUMENT_PIANO2, INSTRUMENT_PIANO3, INSTRUMENT_HONKTONK, INSTRUMENT_EP1, INSTRUMENT_EP2, + INSTRUMENT_HARPSIC, INSTRUMENT_CLAVIC, INSTRUMENT_CELESTA, INSTRUMENT_GLOCK, INSTRUMENT_MUSICBOX, INSTRUMENT_VIBES, + INSTRUMENT_MARIMBA, INSTRUMENT_XYLO, INSTRUMENT_TUBEBELL, INSTRUMENT_SANTUR, INSTRUMENT_ORGAN1, INSTRUMENT_ORGAN2, + INSTRUMENT_ORGAN3, INSTRUMENT_PIPEORG, INSTRUMENT_REEDORG, INSTRUMENT_ACORDIAN, INSTRUMENT_HARMONIC, INSTRUMENT_BANDNEON, + INSTRUMENT_NYLONGT, INSTRUMENT_STEELGT, INSTRUMENT_JAZZGT, INSTRUMENT_CLEANGT, INSTRUMENT_MUTEGT, INSTRUMENT_OVERDGT, + INSTRUMENT_DISTGT, INSTRUMENT_GTHARMS, INSTRUMENT_ACOUBASS, INSTRUMENT_FINGBASS, INSTRUMENT_PICKBASS, INSTRUMENT_FRETLESS, + INSTRUMENT_SLAPBAS1, INSTRUMENT_SLAPBAS2, INSTRUMENT_SYNBASS1, INSTRUMENT_SYNBASS2, INSTRUMENT_VIOLIN, INSTRUMENT_VIOLA, + INSTRUMENT_CELLO, INSTRUMENT_CONTRAB, INSTRUMENT_TREMSTR, INSTRUMENT_PIZZ, INSTRUMENT_HARP, INSTRUMENT_TIMPANI, + INSTRUMENT_STRINGS, INSTRUMENT_SLOWSTR, INSTRUMENT_SYNSTR1, INSTRUMENT_SYNSTR2, INSTRUMENT_CHOIR, INSTRUMENT_OOHS, + INSTRUMENT_SYNVOX, INSTRUMENT_ORCHIT, INSTRUMENT_TRUMPET, INSTRUMENT_TROMBONE, INSTRUMENT_TUBA, INSTRUMENT_MUTETRP, + INSTRUMENT_FRHORN, INSTRUMENT_BRASS1, INSTRUMENT_SYNBRAS1, INSTRUMENT_SYNBRAS2, INSTRUMENT_SOPSAX, INSTRUMENT_ALTOSAX, + INSTRUMENT_TENSAX, INSTRUMENT_BARISAX, INSTRUMENT_OBOE, INSTRUMENT_ENGLHORN, INSTRUMENT_BASSOON, INSTRUMENT_CLARINET, + INSTRUMENT_PICCOLO, INSTRUMENT_FLUTE1, INSTRUMENT_RECORDER, INSTRUMENT_PANFLUTE, INSTRUMENT_BOTTLEB, INSTRUMENT_SHAKU, + INSTRUMENT_WHISTLE, INSTRUMENT_OCARINA, INSTRUMENT_SQUARWAV, INSTRUMENT_SAWWAV, INSTRUMENT_SYNCALLI, INSTRUMENT_CHIFLEAD, + INSTRUMENT_CHARANG, INSTRUMENT_SOLOVOX, INSTRUMENT_FIFTHSAW, INSTRUMENT_BASSLEAD, INSTRUMENT_FANTASIA, INSTRUMENT_WARMPAD, + INSTRUMENT_POLYSYN, INSTRUMENT_SPACEVOX, INSTRUMENT_BOWEDGLS, INSTRUMENT_METALPAD, INSTRUMENT_HALOPAD, INSTRUMENT_SWEEPPAD, + INSTRUMENT_ICERAIN, INSTRUMENT_SOUNDTRK, INSTRUMENT_CRYSTAL, INSTRUMENT_ATMOSPH, INSTRUMENT_BRIGHT, INSTRUMENT_GOBLIN, + INSTRUMENT_ECHODROP, INSTRUMENT_STARTHEM, INSTRUMENT_SITAR, INSTRUMENT_BANJO, INSTRUMENT_SHAMISEN, INSTRUMENT_KOTO, + INSTRUMENT_KALIMBA, INSTRUMENT_BAGPIPE, INSTRUMENT_FIDDLE, INSTRUMENT_SHANNAI, INSTRUMENT_TINKLBEL, INSTRUMENT_AGOGO, + INSTRUMENT_STEELDRM, INSTRUMENT_WOODBLOK, INSTRUMENT_TAIKO, INSTRUMENT_MELOTOM, INSTRUMENT_SYNDRUM, INSTRUMENT_REVRSCYM, + INSTRUMENT_FRETNOIS, INSTRUMENT_BRTHNOIS, INSTRUMENT_SEASHORE, INSTRUMENT_BIRDS, INSTRUMENT_TELEPHON, INSTRUMENT_HELICOPT, + INSTRUMENT_APPLAUSE, INSTRUMENT_GUNSHOT + }; + +#endif diff --git a/src/midi_instruments2_4op.h b/src/midi_instruments2_4op.h new file mode 100644 index 0000000..55ad5cc --- /dev/null +++ b/src/midi_instruments2_4op.h @@ -0,0 +1,195 @@ +/** + * This file contains 4-operator MIDI instrument defenitions for use with the OPL2 Audio Board library. These are a more + * generic set of instruments. This file contains the melodic instrments only. + * + * Instrument definition is based on Adlib instrument bank format. + * 0 - Rhythm mode drum channel + * Drum channels are predefined by the YM3812 and cannot be redefined. Regular instruments have their channel set + * to 0x00 and can be assigned to any channel by the setInstrument function. Rhythm mode instruments can only be + * used when rhythm mode is active (see OPL2.setPercussion). + * + * 1 - Channel c, operator 1, register 0x20 + * Tremolo(1) | Vibrato(1) | Sustain(1) | KSR(1) | Frequency multiplier (4) + * + * 2 - Channel c, operator 1, register 0x40 + * Key scale level(2) | Output level(6) + * + * 3 - Channel c, operator 1, register 0x60 + * Attack(4) | Decay(4) + * + * 4 - Channel c, operator 1, register 0x80 + * Sustain(4) | Release(4) + * + * 5 - Channel c, operator 1, register 0xE0 + * Undefined(5) | Waveform(3) + * + * 6 - Channel c, register 0xC0 + * Undefined(4) | Modulation feedback factor(3) | Synth type(1) + * + * 7 - Channel c, operator 2, register 0x20 + * 8 - Channel c, operator 2, register 0x40 + * 9 - Channel c, operator 2, register 0x60 + * 10 - Channel c, operator 2, register 0x80 + * 11 - Channel c, operator 2, register 0xE0 + */ + +#ifndef _MIDI_INST4OP_H_ + #define _MIDI_INST4OP_H_ + + const unsigned char INSTRUMENT_PIANO1[24] PROGMEM = { 0x00, 0x23, 0x15, 0xFD, 0x7C, 0x03, 0x00, 0x01, 0x08, 0x84, 0xF5, 0x00, 0x00, 0x03, 0x5D, 0xF2, 0x35, 0x00, 0x01, 0x01, 0x08, 0xF4, 0xF5, 0x04 }; + const unsigned char INSTRUMENT_PIANO2[24] PROGMEM = { 0x00, 0x03, 0x7D, 0xF3, 0xF5, 0x00, 0x00, 0x01, 0x08, 0xF3, 0xF5, 0x04, 0x00, 0x03, 0x55, 0xF2, 0xF5, 0x00, 0x01, 0x01, 0x08, 0xF2, 0xF5, 0x04 }; + const unsigned char INSTRUMENT_PIANO3[24] PROGMEM = { 0x00, 0x03, 0x4D, 0xFB, 0x55, 0x04, 0x00, 0x01, 0x08, 0xF3, 0xC5, 0x04, 0x00, 0x03, 0xCE, 0xF3, 0x55, 0x00, 0x01, 0x01, 0x08, 0xF3, 0xD5, 0x04 }; + const unsigned char INSTRUMENT_HONKTONK[24] PROGMEM = { 0x00, 0x03, 0xD7, 0xF3, 0xF5, 0x04, 0x00, 0x01, 0x08, 0xF2, 0xF5, 0x04, 0x00, 0x03, 0xD5, 0xF3, 0xF5, 0x00, 0x01, 0x01, 0x08, 0xF3, 0xF5, 0x04 }; + const unsigned char INSTRUMENT_EP1[24] PROGMEM = { 0x00, 0x16, 0x57, 0xFF, 0x8A, 0x00, 0x0C, 0x01, 0x08, 0xF3, 0x66, 0x00, 0x00, 0x0B, 0x2B, 0xE5, 0xB5, 0x00, 0x01, 0x81, 0x08, 0xE2, 0x86, 0x00 }; + const unsigned char INSTRUMENT_EP2[24] PROGMEM = { 0x00, 0x0A, 0x5F, 0xF4, 0x87, 0x00, 0x00, 0x01, 0x08, 0xF4, 0x86, 0x00, 0x00, 0x03, 0xCC, 0xF2, 0x86, 0x00, 0x01, 0x01, 0x08, 0xE2, 0x86, 0x00 }; + const unsigned char INSTRUMENT_HARPSIC[24] PROGMEM = { 0x00, 0x22, 0xD1, 0xE3, 0x79, 0x04, 0x04, 0x01, 0x88, 0xF3, 0xA7, 0x04, 0x00, 0x22, 0x96, 0xF2, 0x79, 0x04, 0x01, 0x01, 0x08, 0xF3, 0xA7, 0x04 }; + const unsigned char INSTRUMENT_CLAVIC[24] PROGMEM = { 0x00, 0x22, 0x9C, 0xF4, 0x19, 0x05, 0x00, 0x01, 0x08, 0xF3, 0xA6, 0x05, 0x00, 0x22, 0x97, 0xF4, 0x19, 0x04, 0x01, 0x01, 0x08, 0xF3, 0xE6, 0x04 }; + const unsigned char INSTRUMENT_CELESTA[24] PROGMEM = { 0x00, 0x1B, 0x5A, 0xF4, 0xF6, 0x00, 0x00, 0x19, 0x09, 0xE3, 0xA2, 0x00, 0x00, 0x1A, 0x57, 0xF3, 0xB2, 0x00, 0x01, 0x11, 0x08, 0xF2, 0xA3, 0x00 }; + const unsigned char INSTRUMENT_GLOCK[24] PROGMEM = { 0x00, 0x1B, 0x5A, 0xD6, 0x53, 0x00, 0x00, 0x17, 0x0A, 0xF3, 0x53, 0x00, 0x00, 0x1A, 0x49, 0xD1, 0x52, 0x00, 0x01, 0x11, 0x08, 0xF3, 0x52, 0x00 }; + const unsigned char INSTRUMENT_MUSICBOX[24] PROGMEM = { 0x00, 0x1B, 0x5A, 0xF6, 0xF6, 0x00, 0x00, 0x14, 0x08, 0x63, 0xA3, 0x00, 0x00, 0x1B, 0x52, 0xD3, 0xB2, 0x00, 0x01, 0x11, 0x08, 0xF2, 0xA3, 0x00 }; + const unsigned char INSTRUMENT_VIBES[24] PROGMEM = { 0x00, 0x8B, 0x5A, 0xD7, 0x15, 0x00, 0x00, 0x84, 0x08, 0xF1, 0x95, 0x00, 0x00, 0x9B, 0x49, 0xDC, 0x25, 0x00, 0x01, 0x81, 0x08, 0xD2, 0xB5, 0x00 }; + const unsigned char INSTRUMENT_MARIMBA[24] PROGMEM = { 0x00, 0x08, 0xC0, 0xFD, 0x56, 0x00, 0x00, 0x01, 0x08, 0xF6, 0x68, 0x00, 0x00, 0x95, 0x40, 0xFE, 0x27, 0x00, 0x01, 0x81, 0x08, 0xF0, 0x05, 0x00 }; + const unsigned char INSTRUMENT_XYLO[24] PROGMEM = { 0x00, 0x08, 0xC0, 0xFA, 0x56, 0x00, 0x00, 0x03, 0x08, 0xF8, 0x66, 0x00, 0x00, 0x97, 0x40, 0xDF, 0x26, 0x00, 0x01, 0x81, 0x08, 0xF8, 0x06, 0x00 }; + const unsigned char INSTRUMENT_TUBEBELL[24] PROGMEM = { 0x00, 0x03, 0x95, 0xF3, 0x33, 0x00, 0x00, 0x00, 0x88, 0xF3, 0x23, 0x00, 0x00, 0x03, 0x8C, 0xF4, 0x23, 0x00, 0x01, 0x00, 0x88, 0xF3, 0x03, 0x00 }; + const unsigned char INSTRUMENT_SANTUR[24] PROGMEM = { 0x00, 0x01, 0x8B, 0xA7, 0xF9, 0x06, 0x00, 0x00, 0x08, 0x94, 0x36, 0x05, 0x00, 0x02, 0x18, 0xF6, 0x79, 0x04, 0x01, 0x81, 0x88, 0xF4, 0x55, 0x04 }; + const unsigned char INSTRUMENT_ORGAN1[24] PROGMEM = { 0x00, 0x24, 0x40, 0xFD, 0xFD, 0x00, 0x00, 0x24, 0x0A, 0xFB, 0x0E, 0x00, 0x00, 0x20, 0x95, 0xFB, 0x0E, 0x00, 0x01, 0x20, 0x08, 0xF6, 0x0E, 0x00 }; + const unsigned char INSTRUMENT_ORGAN2[24] PROGMEM = { 0x00, 0x04, 0x17, 0xFE, 0xB7, 0x00, 0x00, 0x24, 0x08, 0xF7, 0x67, 0x00, 0x00, 0x20, 0x14, 0xF9, 0x06, 0x00, 0x01, 0xA0, 0x08, 0xF6, 0x07, 0x00 }; + const unsigned char INSTRUMENT_ORGAN3[24] PROGMEM = { 0x00, 0xA2, 0x1E, 0xB9, 0x36, 0x00, 0x00, 0x20, 0x08, 0xA9, 0x0E, 0x00, 0x00, 0xB4, 0x1A, 0x79, 0x51, 0x04, 0x01, 0x20, 0x08, 0x77, 0x4C, 0x00 }; + const unsigned char INSTRUMENT_PIPEORG[24] PROGMEM = { 0x00, 0x25, 0x23, 0x74, 0x11, 0x00, 0x02, 0xA1, 0x08, 0x60, 0x05, 0x00, 0x00, 0xB0, 0xD3, 0x74, 0x12, 0x04, 0x01, 0xB0, 0x08, 0x60, 0x05, 0x01 }; + const unsigned char INSTRUMENT_REEDORG[24] PROGMEM = { 0x00, 0x22, 0x24, 0x76, 0x06, 0x04, 0x00, 0x21, 0x48, 0x76, 0x06, 0x04, 0x00, 0x20, 0x21, 0x76, 0x06, 0x00, 0x01, 0x21, 0x08, 0x66, 0x06, 0x02 }; + const unsigned char INSTRUMENT_ACORDIAN[24] PROGMEM = { 0x00, 0x22, 0x1B, 0x76, 0x07, 0x00, 0x00, 0x21, 0x08, 0x76, 0x07, 0x04, 0x00, 0x21, 0x19, 0x76, 0x07, 0x00, 0x01, 0x21, 0x08, 0x66, 0x07, 0x02 }; + const unsigned char INSTRUMENT_HARMONIC[24] PROGMEM = { 0x00, 0x21, 0x20, 0x93, 0x09, 0x04, 0x00, 0x21, 0x08, 0x73, 0x09, 0x04, 0x00, 0x21, 0x27, 0x76, 0x09, 0x04, 0x01, 0x21, 0x08, 0x76, 0x09, 0x04 }; + const unsigned char INSTRUMENT_BANDNEON[24] PROGMEM = { 0x00, 0x21, 0x1E, 0x76, 0x09, 0x04, 0x00, 0x21, 0x08, 0x66, 0x19, 0x05, 0x00, 0x21, 0x22, 0x76, 0x29, 0x04, 0x01, 0x21, 0x08, 0x66, 0x19, 0x04 }; + const unsigned char INSTRUMENT_NYLONGT[24] PROGMEM = { 0x00, 0x1B, 0x4C, 0xFE, 0xFE, 0x04, 0x00, 0x11, 0x08, 0xF2, 0xE3, 0x00, 0x00, 0x31, 0x4C, 0xF2, 0x45, 0x04, 0x01, 0x11, 0x08, 0xF2, 0xF4, 0x00 }; + const unsigned char INSTRUMENT_STEELGT[24] PROGMEM = { 0x00, 0x30, 0x08, 0xF2, 0x49, 0x02, 0x01, 0x05, 0x0B, 0xFE, 0x43, 0x01, 0x00, 0x01, 0x08, 0xF2, 0xE7, 0x01, 0x01, 0x00, 0x08, 0xF3, 0x9D, 0x02 }; + const unsigned char INSTRUMENT_JAZZGT[24] PROGMEM = { 0x00, 0x34, 0x0D, 0xF2, 0x49, 0x00, 0x01, 0x04, 0x16, 0xFD, 0x43, 0x00, 0x00, 0x01, 0x08, 0xF2, 0xE7, 0x00, 0x01, 0x01, 0x0C, 0xF3, 0x9D, 0x00 }; + const unsigned char INSTRUMENT_CLEANGT[24] PROGMEM = { 0x00, 0x03, 0x00, 0xFB, 0x49, 0x06, 0x09, 0x23, 0x00, 0xFC, 0x64, 0x00, 0x00, 0x01, 0x08, 0xF4, 0xC4, 0x02, 0x01, 0x01, 0x08, 0xF6, 0xC4, 0x06 }; + const unsigned char INSTRUMENT_MUTEGT[24] PROGMEM = { 0x00, 0x01, 0x06, 0xF6, 0x27, 0x05, 0x00, 0x01, 0x0D, 0xF3, 0xE7, 0x01, 0x00, 0x02, 0x05, 0xFA, 0x96, 0x04, 0x01, 0x01, 0x08, 0x65, 0x9B, 0x04 }; + const unsigned char INSTRUMENT_OVERDGT[24] PROGMEM = { 0x00, 0x21, 0xC1, 0xF2, 0x13, 0x00, 0x00, 0x21, 0x48, 0xF3, 0x16, 0x04, 0x00, 0x21, 0x03, 0x97, 0xAE, 0x03, 0x01, 0x21, 0x08, 0x96, 0x26, 0x05 }; + const unsigned char INSTRUMENT_DISTGT[24] PROGMEM = { 0x00, 0x21, 0xC1, 0xF2, 0x16, 0x00, 0x00, 0x21, 0x08, 0xF2, 0x16, 0x04, 0x00, 0x21, 0x03, 0xC7, 0x46, 0x03, 0x01, 0x20, 0x08, 0x90, 0x16, 0x03 }; + const unsigned char INSTRUMENT_GTHARMS[24] PROGMEM = { 0x00, 0x0B, 0x40, 0x65, 0x1A, 0x00, 0x0C, 0x01, 0x48, 0xF2, 0x3E, 0x03, 0x00, 0x05, 0x00, 0xE2, 0x1A, 0x02, 0x01, 0x0A, 0x49, 0x54, 0x1A, 0x01 }; + const unsigned char INSTRUMENT_ACOUBASS[24] PROGMEM = { 0x00, 0x21, 0x12, 0xE4, 0x15, 0x00, 0x00, 0x21, 0x08, 0xD3, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_FINGBASS[24] PROGMEM = { 0x00, 0x21, 0x08, 0xF2, 0x49, 0x04, 0x01, 0x01, 0x0B, 0xF2, 0x97, 0x05, 0x00, 0x01, 0x09, 0xF6, 0xE7, 0x01, 0x01, 0x01, 0x08, 0xF3, 0x9D, 0x04 }; + const unsigned char INSTRUMENT_PICKBASS[24] PROGMEM = { 0x00, 0x21, 0x08, 0xF2, 0x49, 0x04, 0x01, 0x01, 0x08, 0xF2, 0x97, 0x05, 0x00, 0x01, 0x08, 0xF6, 0xE7, 0x01, 0x01, 0x01, 0x08, 0xF3, 0x9D, 0x04 }; + const unsigned char INSTRUMENT_FRETLESS[24] PROGMEM = { 0x00, 0x01, 0xC8, 0xF2, 0x6A, 0x00, 0x09, 0x01, 0x08, 0xC4, 0x97, 0x00, 0x00, 0x01, 0x11, 0x91, 0xE7, 0x00, 0x01, 0x01, 0x08, 0xF2, 0x6D, 0x00 }; + const unsigned char INSTRUMENT_SLAPBAS1[24] PROGMEM = { 0x00, 0x01, 0x06, 0xFD, 0x49, 0x06, 0x01, 0x0B, 0x08, 0xFA, 0x87, 0x04, 0x00, 0x01, 0x08, 0xF3, 0xB7, 0x04, 0x01, 0x01, 0x08, 0xF3, 0x9D, 0x04 }; + const unsigned char INSTRUMENT_SLAPBAS2[24] PROGMEM = { 0x00, 0x26, 0x24, 0xF6, 0x87, 0x04, 0x00, 0x21, 0x08, 0xF2, 0xF7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS1[24] PROGMEM = { 0x00, 0x21, 0x08, 0xF5, 0x47, 0x00, 0x00, 0x01, 0x48, 0xF2, 0xF7, 0x00, 0x00, 0x21, 0x07, 0xF5, 0x47, 0x00, 0x09, 0x01, 0x48, 0xF2, 0xF7, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS2[24] PROGMEM = { 0x00, 0xC1, 0x08, 0xF2, 0x48, 0x00, 0x01, 0x01, 0x21, 0xF2, 0x97, 0x00, 0x00, 0x01, 0x0A, 0xF2, 0x97, 0x00, 0x00, 0x01, 0x08, 0xF2, 0x77, 0x00 }; + const unsigned char INSTRUMENT_VIOLIN[24] PROGMEM = { 0x00, 0x22, 0xCA, 0xB4, 0x26, 0x04, 0x0C, 0x21, 0x11, 0x44, 0x06, 0x04, 0x00, 0x22, 0xCC, 0x89, 0x16, 0x04, 0x01, 0x01, 0x10, 0x5D, 0x06, 0x04 }; + const unsigned char INSTRUMENT_VIOLA[24] PROGMEM = { 0x00, 0x24, 0xCB, 0x88, 0x26, 0x04, 0x0C, 0x21, 0x10, 0x66, 0x16, 0x04, 0x00, 0x34, 0xC4, 0x86, 0x66, 0x04, 0x01, 0x21, 0x10, 0x66, 0x06, 0x04 }; + const unsigned char INSTRUMENT_CELLO[24] PROGMEM = { 0x00, 0x22, 0xCB, 0x72, 0x46, 0x04, 0x06, 0x01, 0x1C, 0x5F, 0x86, 0x04, 0x00, 0x22, 0xCD, 0x76, 0x36, 0x04, 0x01, 0x21, 0x08, 0x54, 0x06, 0x04 }; + const unsigned char INSTRUMENT_CONTRAB[24] PROGMEM = { 0x00, 0x22, 0xFF, 0x86, 0x06, 0x04, 0x06, 0x01, 0x08, 0x6F, 0x08, 0x04, 0x00, 0x22, 0xD2, 0x74, 0x16, 0x04, 0x01, 0x21, 0x08, 0x54, 0x06, 0x04 }; + const unsigned char INSTRUMENT_TREMSTR[24] PROGMEM = { 0x00, 0x60, 0x00, 0x68, 0x04, 0x02, 0x01, 0x61, 0x09, 0x53, 0x45, 0x03, 0x00, 0x61, 0x11, 0x54, 0x54, 0x01, 0x01, 0x60, 0x08, 0x78, 0x35, 0x03 }; + const unsigned char INSTRUMENT_PIZZ[24] PROGMEM = { 0x00, 0x00, 0x07, 0xF9, 0xF1, 0x03, 0x06, 0x00, 0x08, 0xF6, 0x34, 0x02, 0x00, 0x00, 0x0C, 0x89, 0xF1, 0x03, 0x01, 0x00, 0x08, 0xB5, 0x34, 0x02 }; + const unsigned char INSTRUMENT_HARP[24] PROGMEM = { 0x00, 0x12, 0xD0, 0xB5, 0x23, 0x04, 0x00, 0x01, 0x17, 0xC3, 0xE3, 0x00, 0x00, 0x12, 0xD9, 0xE5, 0x15, 0x04, 0x01, 0x11, 0x08, 0xA2, 0xF3, 0x00 }; + const unsigned char INSTRUMENT_TIMPANI[24] PROGMEM = { 0x00, 0x11, 0xD0, 0xE4, 0xE4, 0x01, 0x00, 0x10, 0x08, 0xD3, 0xF4, 0x00, 0x00, 0x14, 0x14, 0xF6, 0xF4, 0x02, 0x01, 0x10, 0x08, 0xF3, 0xF4, 0x02 }; + const unsigned char INSTRUMENT_STRINGS[24] PROGMEM = { 0x00, 0x21, 0x1B, 0xA9, 0x23, 0x00, 0x0E, 0x21, 0xC8, 0x63, 0x25, 0x04, 0x00, 0x21, 0x22, 0xA9, 0x23, 0x00, 0x01, 0x21, 0x48, 0x43, 0x24, 0x04 }; + const unsigned char INSTRUMENT_SLOWSTR[24] PROGMEM = { 0x00, 0x21, 0x1F, 0xA9, 0x23, 0x00, 0x0E, 0x21, 0xC8, 0x33, 0x15, 0x04, 0x00, 0x21, 0x23, 0x60, 0x23, 0x00, 0x01, 0x21, 0x88, 0x33, 0x25, 0x04 }; + const unsigned char INSTRUMENT_SYNSTR1[24] PROGMEM = { 0x00, 0x20, 0x08, 0x52, 0xB6, 0x02, 0x01, 0x01, 0x0C, 0x50, 0x15, 0x01, 0x00, 0x21, 0x09, 0x44, 0x04, 0x01, 0x01, 0x20, 0x51, 0x41, 0x27, 0x02 }; + const unsigned char INSTRUMENT_SYNSTR2[24] PROGMEM = { 0x00, 0x22, 0x48, 0x51, 0xA4, 0x04, 0x01, 0x01, 0xC2, 0x31, 0xF4, 0x01, 0x00, 0x21, 0x08, 0x70, 0xF4, 0x01, 0x01, 0x21, 0x48, 0x34, 0x74, 0x04 }; + const unsigned char INSTRUMENT_CHOIR[24] PROGMEM = { 0x00, 0x21, 0x10, 0x61, 0x04, 0x00, 0x0A, 0x21, 0x08, 0x66, 0x45, 0x04, 0x00, 0x20, 0x1C, 0x63, 0x05, 0x00, 0x01, 0x21, 0x08, 0x63, 0x04, 0x00 }; + const unsigned char INSTRUMENT_OOHS[24] PROGMEM = { 0x00, 0x21, 0x16, 0xA6, 0x66, 0x00, 0x00, 0x21, 0x08, 0x77, 0x06, 0x00, 0x00, 0x20, 0xD8, 0x66, 0x36, 0x00, 0x01, 0x21, 0x08, 0x68, 0x06, 0x00 }; + const unsigned char INSTRUMENT_SYNVOX[24] PROGMEM = { 0x00, 0x21, 0x12, 0x75, 0x66, 0x00, 0x00, 0x21, 0x08, 0x67, 0x06, 0x00, 0x00, 0x21, 0x2D, 0x62, 0x36, 0x00, 0x01, 0x21, 0x08, 0x68, 0x06, 0x00 }; + const unsigned char INSTRUMENT_ORCHIT[24] PROGMEM = { 0x00, 0x02, 0x0E, 0x76, 0x34, 0x00, 0x00, 0x01, 0x08, 0x64, 0x35, 0x04, 0x00, 0x01, 0x2D, 0x66, 0x35, 0x04, 0x01, 0x00, 0x08, 0x63, 0x04, 0x00 }; + const unsigned char INSTRUMENT_TRUMPET[24] PROGMEM = { 0x00, 0x21, 0x23, 0x72, 0x9B, 0x01, 0x00, 0x21, 0x08, 0x72, 0x3B, 0x04, 0x00, 0x21, 0x23, 0x82, 0x9B, 0x01, 0x01, 0x21, 0x08, 0x92, 0x3B, 0x04 }; + const unsigned char INSTRUMENT_TROMBONE[24] PROGMEM = { 0x00, 0x21, 0x23, 0x63, 0x9B, 0x01, 0x00, 0x21, 0x08, 0x62, 0x3B, 0x04, 0x00, 0x21, 0x21, 0x73, 0x9B, 0x01, 0x01, 0x21, 0x08, 0x82, 0x3B, 0x04 }; + const unsigned char INSTRUMENT_TUBA[24] PROGMEM = { 0x00, 0x01, 0x14, 0x62, 0x0B, 0x05, 0x06, 0x01, 0x08, 0xE6, 0x2B, 0x05, 0x00, 0x21, 0x13, 0x55, 0x1B, 0x04, 0x01, 0x22, 0x08, 0x72, 0x2B, 0x00 }; + const unsigned char INSTRUMENT_MUTETRP[24] PROGMEM = { 0x00, 0x01, 0x11, 0x60, 0xFB, 0x05, 0x00, 0x21, 0x18, 0x62, 0x7B, 0x00, 0x00, 0x01, 0x10, 0x60, 0x3B, 0x05, 0x01, 0x21, 0x17, 0x62, 0x7B, 0x00 }; + const unsigned char INSTRUMENT_FRHORN[24] PROGMEM = { 0x00, 0x21, 0x23, 0x41, 0x94, 0x00, 0x0E, 0x21, 0x08, 0x81, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_BRASS1[24] PROGMEM = { 0x00, 0x22, 0x4C, 0x75, 0x37, 0x01, 0x00, 0x61, 0x48, 0xF1, 0xB7, 0x05, 0x00, 0x21, 0x4D, 0x56, 0x07, 0x05, 0x01, 0x20, 0x08, 0x72, 0x17, 0x02 }; + const unsigned char INSTRUMENT_SYNBRAS1[24] PROGMEM = { 0x00, 0x21, 0x04, 0x82, 0xCB, 0x01, 0x06, 0x21, 0x09, 0x71, 0x2B, 0x01, 0x00, 0x21, 0x11, 0x75, 0x8B, 0x00, 0x01, 0x21, 0x08, 0x80, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_SYNBRAS2[24] PROGMEM = { 0x00, 0x21, 0x83, 0x84, 0x3B, 0x01, 0x06, 0x21, 0x4D, 0xA2, 0x3B, 0x00, 0x00, 0x21, 0x0E, 0x74, 0x7B, 0x00, 0x01, 0x21, 0x08, 0x73, 0x3B, 0x00 }; + const unsigned char INSTRUMENT_SOPSAX[24] PROGMEM = { 0x00, 0x01, 0x15, 0x70, 0xE7, 0x05, 0x00, 0x02, 0x08, 0x70, 0xE8, 0x00, 0x00, 0x01, 0x42, 0x70, 0xF8, 0x07, 0x01, 0x00, 0x08, 0x70, 0xE8, 0x02 }; + const unsigned char INSTRUMENT_ALTOSAX[24] PROGMEM = { 0x00, 0x01, 0x13, 0x70, 0xE9, 0x05, 0x00, 0x01, 0x08, 0x70, 0xE9, 0x00, 0x00, 0x01, 0x47, 0x70, 0xE9, 0x07, 0x01, 0x40, 0x48, 0x70, 0xE9, 0x02 }; + const unsigned char INSTRUMENT_TENSAX[24] PROGMEM = { 0x00, 0x01, 0x15, 0x70, 0xEB, 0x05, 0x00, 0x01, 0x08, 0x70, 0xEA, 0x00, 0x00, 0x01, 0x09, 0x70, 0xEB, 0x07, 0x01, 0x40, 0x08, 0x70, 0xEB, 0x02 }; + const unsigned char INSTRUMENT_BARISAX[24] PROGMEM = { 0x00, 0x01, 0x11, 0xA4, 0xBB, 0x00, 0x00, 0x04, 0x0D, 0x67, 0x6A, 0x00, 0x00, 0x01, 0x0C, 0xD0, 0xEB, 0x01, 0x01, 0x02, 0x08, 0x80, 0xEB, 0x02 }; + const unsigned char INSTRUMENT_OBOE[24] PROGMEM = { 0x00, 0x11, 0x17, 0x70, 0x29, 0x00, 0x00, 0x34, 0x08, 0x61, 0x29, 0x00, 0x00, 0x31, 0xFF, 0x60, 0x09, 0x00, 0x01, 0x34, 0x7F, 0x60, 0x09, 0x02 }; + const unsigned char INSTRUMENT_ENGLHORN[24] PROGMEM = { 0x00, 0x01, 0x11, 0xF0, 0x29, 0x00, 0x00, 0x24, 0x08, 0x80, 0x09, 0x00, 0x00, 0x31, 0xDA, 0x80, 0x09, 0x00, 0x01, 0x24, 0x08, 0x80, 0x09, 0x00 }; + const unsigned char INSTRUMENT_BASSOON[24] PROGMEM = { 0x00, 0x01, 0x13, 0x60, 0x22, 0x00, 0x00, 0x24, 0x0C, 0x80, 0x09, 0x00, 0x00, 0x31, 0x86, 0x80, 0x05, 0x00, 0x01, 0x24, 0x18, 0x80, 0x09, 0x00 }; + const unsigned char INSTRUMENT_CLARINET[24] PROGMEM = { 0x00, 0x32, 0x1D, 0xA2, 0x16, 0x04, 0x0A, 0x31, 0x08, 0x51, 0x26, 0x00, 0x00, 0x32, 0x45, 0xFE, 0x52, 0x04, 0x01, 0x31, 0x08, 0x55, 0x15, 0x00 }; + const unsigned char INSTRUMENT_PICCOLO[24] PROGMEM = { 0x00, 0x24, 0x20, 0x67, 0xF6, 0x00, 0x00, 0xA2, 0x08, 0x65, 0x06, 0x00, 0x00, 0x24, 0x1C, 0x7F, 0x27, 0x00, 0x01, 0xA2, 0x08, 0x67, 0x06, 0x00 }; + const unsigned char INSTRUMENT_FLUTE1[24] PROGMEM = { 0x00, 0x22, 0x26, 0x65, 0x66, 0x00, 0x00, 0xA1, 0x10, 0x67, 0x06, 0x00, 0x00, 0x02, 0x2A, 0xA2, 0x36, 0x00, 0x01, 0x21, 0x10, 0x6F, 0x06, 0x00 }; + const unsigned char INSTRUMENT_RECORDER[24] PROGMEM = { 0x00, 0x21, 0x11, 0x85, 0x66, 0x00, 0x00, 0x31, 0x1B, 0x68, 0x06, 0x00, 0x00, 0x32, 0x19, 0xD5, 0x39, 0x00, 0x01, 0x31, 0x08, 0x68, 0x06, 0x00 }; + const unsigned char INSTRUMENT_PANFLUTE[24] PROGMEM = { 0x00, 0x20, 0x00, 0x77, 0x08, 0x00, 0x0E, 0xA0, 0x15, 0x77, 0x58, 0x00, 0x00, 0x24, 0xD3, 0x76, 0xA9, 0x04, 0x01, 0x21, 0x08, 0x76, 0x08, 0x00 }; + const unsigned char INSTRUMENT_BOTTLEB[24] PROGMEM = { 0x00, 0x2B, 0x12, 0x73, 0x68, 0x00, 0x0E, 0x26, 0x24, 0x67, 0x97, 0x00, 0x00, 0x22, 0x14, 0x66, 0x46, 0x00, 0x01, 0x21, 0x17, 0x60, 0xB6, 0x00 }; + const unsigned char INSTRUMENT_SHAKU[24] PROGMEM = { 0x00, 0x61, 0x16, 0x67, 0x56, 0x02, 0x00, 0xA1, 0x11, 0x77, 0x06, 0x00, 0x00, 0x21, 0x15, 0xD7, 0x66, 0x02, 0x01, 0x01, 0x08, 0x40, 0xB6, 0x00 }; + const unsigned char INSTRUMENT_WHISTLE[24] PROGMEM = { 0x00, 0x61, 0x31, 0xC4, 0x56, 0x02, 0x00, 0xA1, 0x08, 0x50, 0xB6, 0x00, 0x00, 0x61, 0x30, 0xC4, 0x66, 0x01, 0x01, 0x81, 0x08, 0x50, 0xB6, 0x00 }; + const unsigned char INSTRUMENT_OCARINA[24] PROGMEM = { 0x00, 0x31, 0x2B, 0x57, 0x46, 0x04, 0x00, 0x31, 0x08, 0x68, 0x06, 0x00, 0x00, 0x32, 0x30, 0x47, 0x69, 0x04, 0x01, 0x31, 0x08, 0x68, 0x06, 0x00 }; + const unsigned char INSTRUMENT_SQUARWAV[24] PROGMEM = { 0x00, 0x21, 0x0D, 0xD4, 0x1B, 0x04, 0x01, 0x21, 0x0D, 0xC2, 0x26, 0x06, 0x00, 0x21, 0x15, 0xC6, 0x19, 0x04, 0x01, 0x21, 0x15, 0xD0, 0x27, 0x06 }; + const unsigned char INSTRUMENT_SAWWAV[24] PROGMEM = { 0x00, 0x21, 0x11, 0xD4, 0x1B, 0x04, 0x00, 0x20, 0x08, 0xC2, 0x36, 0x03, 0x00, 0x21, 0x10, 0xC9, 0x49, 0x04, 0x01, 0x21, 0x08, 0xD0, 0x37, 0x01 }; + const unsigned char INSTRUMENT_SYNCALLI[24] PROGMEM = { 0x00, 0x22, 0x0E, 0x76, 0x66, 0x00, 0x06, 0xA1, 0x14, 0x67, 0x06, 0x00, 0x00, 0x22, 0x1E, 0x75, 0x06, 0x02, 0x01, 0x21, 0x14, 0x75, 0x06, 0x00 }; + const unsigned char INSTRUMENT_CHIFLEAD[24] PROGMEM = { 0x00, 0xD1, 0x00, 0xB7, 0x66, 0x02, 0x00, 0xA0, 0x08, 0x87, 0x06, 0x02, 0x00, 0x01, 0x14, 0x75, 0x66, 0x02, 0x01, 0x60, 0x08, 0xB5, 0x06, 0x02 }; + const unsigned char INSTRUMENT_CHARANG[24] PROGMEM = { 0x00, 0x30, 0x0C, 0xF4, 0xA0, 0x00, 0x00, 0x22, 0x0C, 0x62, 0x0E, 0x00, 0x00, 0x20, 0x14, 0x77, 0x4E, 0x00, 0x01, 0x21, 0x0C, 0x90, 0x1C, 0x00 }; + const unsigned char INSTRUMENT_SOLOVOX[24] PROGMEM = { 0x00, 0x20, 0x1A, 0x76, 0x64, 0x00, 0x06, 0x32, 0x0C, 0x47, 0x05, 0x00, 0x00, 0x31, 0x1B, 0x75, 0x03, 0x00, 0x01, 0x21, 0x0C, 0x75, 0x05, 0x00 }; + const unsigned char INSTRUMENT_FIFTHSAW[24] PROGMEM = { 0x00, 0x03, 0x0C, 0xF2, 0xA6, 0x00, 0x07, 0x06, 0x3F, 0xF0, 0xFB, 0x00, 0x00, 0x01, 0x15, 0xF0, 0xF8, 0x00, 0x00, 0x00, 0x14, 0xF3, 0xC8, 0x00 }; + const unsigned char INSTRUMENT_BASSLEAD[24] PROGMEM = { 0x00, 0x02, 0x0B, 0xF3, 0xFB, 0x01, 0x06, 0x21, 0x09, 0xF1, 0x2B, 0x01, 0x00, 0x01, 0xE1, 0xF3, 0xFB, 0x05, 0x01, 0x21, 0x10, 0xF0, 0x2B, 0x00 }; + const unsigned char INSTRUMENT_FANTASIA[24] PROGMEM = { 0x00, 0x12, 0xC0, 0xF2, 0x23, 0x00, 0x00, 0x12, 0x14, 0xE2, 0x55, 0x00, 0x00, 0x31, 0x1C, 0x69, 0x33, 0x02, 0x01, 0x30, 0x0D, 0x52, 0x15, 0x02 }; + const unsigned char INSTRUMENT_WARMPAD[24] PROGMEM = { 0x00, 0x01, 0x18, 0x21, 0x53, 0x00, 0x00, 0x31, 0x08, 0x22, 0x55, 0x00, 0x00, 0x11, 0xD4, 0x21, 0x53, 0x01, 0x01, 0x31, 0x08, 0x21, 0x45, 0x00 }; + const unsigned char INSTRUMENT_POLYSYN[24] PROGMEM = { 0x00, 0x20, 0x00, 0xC3, 0xF4, 0x02, 0x00, 0x01, 0x08, 0xF0, 0xF5, 0x00, 0x00, 0x01, 0x08, 0x32, 0x14, 0x05, 0x01, 0x21, 0x12, 0x20, 0x04, 0x00 }; + const unsigned char INSTRUMENT_SPACEVOX[24] PROGMEM = { 0x00, 0x30, 0xD1, 0xA2, 0x40, 0x00, 0x00, 0x20, 0x04, 0x63, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_BOWEDGLS[24] PROGMEM = { 0x00, 0x06, 0x08, 0xF0, 0xE4, 0x00, 0x00, 0x21, 0x16, 0x45, 0x36, 0x00, 0x00, 0x01, 0x46, 0xE5, 0x34, 0x04, 0x01, 0x21, 0x0C, 0x40, 0x05, 0x00 }; + const unsigned char INSTRUMENT_METALPAD[24] PROGMEM = { 0x00, 0x21, 0x40, 0x63, 0x83, 0x00, 0x00, 0x21, 0x08, 0x30, 0x13, 0x00, 0x00, 0x21, 0x17, 0x63, 0xA3, 0x05, 0x01, 0x21, 0x09, 0x40, 0x13, 0x04 }; + const unsigned char INSTRUMENT_HALOPAD[24] PROGMEM = { 0x00, 0x31, 0x08, 0x60, 0x15, 0x00, 0x05, 0x30, 0xC4, 0x64, 0xF8, 0x02, 0x00, 0x31, 0x14, 0xB0, 0xC5, 0x00, 0x01, 0x31, 0x0C, 0xD0, 0x45, 0x00 }; + const unsigned char INSTRUMENT_SWEEPPAD[24] PROGMEM = { 0x00, 0x31, 0x00, 0x44, 0xF4, 0x00, 0x05, 0x12, 0x8C, 0x12, 0xB3, 0x00, 0x00, 0x10, 0x10, 0x30, 0xB4, 0x01, 0x01, 0x30, 0x08, 0x74, 0x04, 0x01 }; + const unsigned char INSTRUMENT_ICERAIN[24] PROGMEM = { 0x00, 0x08, 0xC0, 0xFB, 0x66, 0x00, 0x00, 0x83, 0x08, 0xF5, 0x68, 0x00, 0x00, 0x21, 0x14, 0xF0, 0x25, 0x00, 0x01, 0x21, 0x08, 0xDE, 0x05, 0x00 }; + const unsigned char INSTRUMENT_SOUNDTRK[24] PROGMEM = { 0x00, 0x08, 0x01, 0x33, 0xF2, 0x00, 0x00, 0x01, 0x17, 0x31, 0xF2, 0x00, 0x00, 0x01, 0x04, 0x31, 0xF2, 0x01, 0x01, 0x01, 0x08, 0x32, 0xF2, 0x00 }; + const unsigned char INSTRUMENT_CRYSTAL[24] PROGMEM = { 0x00, 0x17, 0xC0, 0xF1, 0x31, 0x00, 0x08, 0x91, 0x08, 0xF1, 0x22, 0x00, 0x00, 0x95, 0x9B, 0xF1, 0x21, 0x00, 0x01, 0x91, 0x09, 0xF1, 0x23, 0x00 }; + const unsigned char INSTRUMENT_ATMOSPH[24] PROGMEM = { 0x00, 0x01, 0x00, 0xD2, 0x24, 0x00, 0x00, 0x17, 0x0C, 0xD8, 0x34, 0x00, 0x00, 0x01, 0x17, 0xEA, 0x34, 0x02, 0x01, 0x20, 0x08, 0xE1, 0x14, 0x02 }; + const unsigned char INSTRUMENT_BRIGHT[24] PROGMEM = { 0x00, 0x06, 0x08, 0xF0, 0xE4, 0x00, 0x00, 0x01, 0x08, 0xF5, 0x34, 0x00, 0x00, 0x01, 0x44, 0xE5, 0x34, 0x02, 0x01, 0xA0, 0x08, 0xE0, 0x44, 0x02 }; + const unsigned char INSTRUMENT_GOBLIN[24] PROGMEM = { 0x00, 0x04, 0x02, 0x11, 0x32, 0x00, 0x08, 0x01, 0x08, 0x21, 0x22, 0x00, 0x00, 0x01, 0x41, 0x11, 0x24, 0x00, 0x01, 0x01, 0x08, 0x11, 0x23, 0x00 }; + const unsigned char INSTRUMENT_ECHODROP[24] PROGMEM = { 0x00, 0x05, 0xC0, 0xF8, 0xD3, 0x00, 0x00, 0x01, 0x0C, 0xE1, 0x03, 0x00, 0x00, 0x21, 0x10, 0x69, 0x33, 0x01, 0x01, 0x21, 0x08, 0x52, 0x13, 0x00 }; + const unsigned char INSTRUMENT_STARTHEM[24] PROGMEM = { 0x00, 0x02, 0x00, 0x83, 0xF3, 0x01, 0x06, 0x21, 0x08, 0x61, 0x23, 0x00, 0x00, 0x01, 0x0B, 0x73, 0xF3, 0x05, 0x01, 0x21, 0x08, 0x52, 0x23, 0x00 }; + const unsigned char INSTRUMENT_SITAR[24] PROGMEM = { 0x00, 0x25, 0x12, 0xF7, 0x44, 0x04, 0x00, 0x01, 0x0F, 0xF8, 0x04, 0x04, 0x00, 0xA7, 0x17, 0x80, 0x64, 0x04, 0x01, 0x01, 0x10, 0xF3, 0x74, 0x04 }; + const unsigned char INSTRUMENT_BANJO[24] PROGMEM = { 0x00, 0x01, 0x08, 0xF4, 0xA6, 0x04, 0x05, 0x05, 0x25, 0xF8, 0xFB, 0x00, 0x00, 0x01, 0x10, 0xF4, 0xFB, 0x00, 0x00, 0x02, 0x08, 0xF6, 0xC7, 0x04 }; + const unsigned char INSTRUMENT_SHAMISEN[24] PROGMEM = { 0x00, 0x04, 0x09, 0xFA, 0xA6, 0x00, 0x04, 0x07, 0x08, 0xF8, 0xFB, 0x00, 0x00, 0x01, 0x16, 0xF3, 0x95, 0x04, 0x01, 0x01, 0x08, 0xF3, 0xC5, 0x04 }; + const unsigned char INSTRUMENT_KOTO[24] PROGMEM = { 0x00, 0x01, 0x08, 0xF4, 0xA4, 0x04, 0x05, 0x05, 0x25, 0xFA, 0xFB, 0x04, 0x00, 0x01, 0x18, 0xF4, 0xF5, 0x04, 0x00, 0x01, 0x08, 0xF3, 0xC5, 0x04 }; + const unsigned char INSTRUMENT_KALIMBA[24] PROGMEM = { 0x00, 0x09, 0x00, 0xF8, 0x6E, 0x04, 0x00, 0x03, 0x08, 0xF8, 0x6E, 0x04, 0x00, 0x01, 0x00, 0xF4, 0x16, 0x00, 0x01, 0x86, 0x09, 0xF7, 0xEA, 0x00 }; + const unsigned char INSTRUMENT_BAGPIPE[24] PROGMEM = { 0x00, 0x11, 0x0C, 0xD0, 0xF3, 0x00, 0x00, 0x32, 0x08, 0x80, 0x05, 0x00, 0x00, 0x31, 0xC9, 0x40, 0x09, 0x00, 0x01, 0x24, 0x0C, 0x50, 0x09, 0x04 }; + const unsigned char INSTRUMENT_FIDDLE[24] PROGMEM = { 0x00, 0x24, 0xC9, 0xAA, 0x58, 0x04, 0x00, 0x20, 0x0C, 0x95, 0x08, 0x03, 0x00, 0x24, 0xC9, 0xC7, 0x88, 0x05, 0x01, 0x20, 0x08, 0x72, 0x28, 0x03 }; + const unsigned char INSTRUMENT_SHANNAI[24] PROGMEM = { 0x00, 0x11, 0x0C, 0xD0, 0xF3, 0x00, 0x00, 0x32, 0x08, 0x80, 0x05, 0x00, 0x00, 0x31, 0xCC, 0x60, 0x06, 0x00, 0x01, 0x24, 0x0C, 0x60, 0x06, 0x04 }; + const unsigned char INSTRUMENT_TINKLBEL[24] PROGMEM = { 0x00, 0x16, 0x4F, 0xF6, 0x53, 0x00, 0x00, 0x19, 0x08, 0xF3, 0x53, 0x00, 0x00, 0x15, 0x41, 0xF1, 0x52, 0x06, 0x01, 0x14, 0x08, 0xF3, 0x52, 0x06 }; + const unsigned char INSTRUMENT_AGOGO[24] PROGMEM = { 0x00, 0x17, 0x00, 0xFA, 0x57, 0x00, 0x00, 0x12, 0x08, 0xF5, 0x58, 0x00, 0x00, 0x14, 0x40, 0xF7, 0x52, 0x06, 0x01, 0x12, 0x08, 0xF5, 0x59, 0x06 }; + const unsigned char INSTRUMENT_STEELDRM[24] PROGMEM = { 0x00, 0x08, 0x1F, 0xC6, 0x37, 0x00, 0x06, 0x01, 0x08, 0x82, 0x95, 0x00, 0x00, 0x05, 0x0F, 0x65, 0x55, 0x00, 0x01, 0x11, 0x0F, 0x52, 0x75, 0x00 }; + const unsigned char INSTRUMENT_WOODBLOK[24] PROGMEM = { 0x00, 0x02, 0x09, 0xFC, 0xD6, 0x02, 0x00, 0x01, 0x08, 0xF7, 0xF7, 0x00, 0x00, 0x07, 0x3F, 0xFA, 0x4E, 0x00, 0x01, 0x03, 0xFF, 0xF5, 0xFE, 0x00 }; + const unsigned char INSTRUMENT_TAIKO[24] PROGMEM = { 0x00, 0x1A, 0x00, 0xFB, 0x57, 0x00, 0x01, 0x30, 0x00, 0xF3, 0x54, 0x01, 0x00, 0x11, 0x48, 0xC5, 0x52, 0x01, 0x01, 0x10, 0x08, 0xC5, 0x57, 0x00 }; + const unsigned char INSTRUMENT_MELOTOM[24] PROGMEM = { 0x00, 0x12, 0x01, 0xFB, 0xA7, 0x00, 0x00, 0x30, 0x08, 0xF3, 0x53, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x52, 0x00, 0x01, 0x10, 0x08, 0xC4, 0x57, 0x00 }; + const unsigned char INSTRUMENT_SYNDRUM[24] PROGMEM = { 0x00, 0x2B, 0x00, 0xFF, 0x0E, 0x00, 0x0E, 0x0B, 0x08, 0xF7, 0xFE, 0x00, 0x00, 0x00, 0xC0, 0xF6, 0xFE, 0x02, 0x01, 0x20, 0x09, 0xFF, 0x0C, 0x00 }; + const unsigned char INSTRUMENT_REVRSCYM[24] PROGMEM = { 0x00, 0x2A, 0x00, 0xFF, 0x0E, 0x04, 0x0E, 0x0B, 0x08, 0x2F, 0x0E, 0x04, 0x00, 0x28, 0x00, 0xF9, 0x0E, 0x04, 0x01, 0x09, 0x08, 0x29, 0x0E, 0x04 }; + const unsigned char INSTRUMENT_FRETNOIS[24] PROGMEM = { 0x00, 0x0B, 0x00, 0x64, 0xF8, 0x04, 0x0E, 0x0B, 0x25, 0x77, 0xF8, 0x04, 0x00, 0x0B, 0x10, 0x56, 0xF8, 0x04, 0x01, 0x09, 0x08, 0x59, 0xE8, 0x04 }; + const unsigned char INSTRUMENT_BRTHNOIS[24] PROGMEM = { 0x00, 0x2B, 0x05, 0x79, 0x05, 0x00, 0x0E, 0x25, 0x08, 0x77, 0xA5, 0x00, 0x00, 0x26, 0x10, 0x66, 0xB9, 0x04, 0x01, 0x01, 0x0A, 0x76, 0xDE, 0x00 }; + const unsigned char INSTRUMENT_SEASHORE[24] PROGMEM = { 0x00, 0x30, 0x00, 0x11, 0x00, 0x00, 0x0E, 0x10, 0x08, 0x11, 0x32, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_BIRDS[24] PROGMEM = { 0x00, 0x0A, 0x00, 0x59, 0xFE, 0x00, 0x01, 0x09, 0x00, 0x69, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char INSTRUMENT_TELEPHON[24] PROGMEM = { 0x00, 0x0A, 0x0B, 0xE5, 0xF5, 0x05, 0x00, 0x02, 0x08, 0xE4, 0xF5, 0x00, 0x00, 0x08, 0x43, 0xF5, 0xF5, 0x03, 0x01, 0x02, 0x08, 0xF4, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_HELICOPT[24] PROGMEM = { 0x00, 0x0B, 0x00, 0x82, 0xFA, 0x00, 0x0E, 0x04, 0x88, 0x77, 0xFA, 0x05, 0x00, 0x20, 0x11, 0xF7, 0xFA, 0x00, 0x01, 0x20, 0x1D, 0xFA, 0xFB, 0x00 }; + const unsigned char INSTRUMENT_APPLAUSE[24] PROGMEM = { 0x00, 0x2B, 0x00, 0xF0, 0x01, 0x00, 0x0E, 0x27, 0x08, 0x23, 0x13, 0x05, 0x00, 0x20, 0x7F, 0xFB, 0xE5, 0x00, 0x01, 0x20, 0x3F, 0xF4, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_GUNSHOT[24] PROGMEM = { 0x00, 0x0B, 0x40, 0xF5, 0x67, 0x00, 0x0E, 0x01, 0xC8, 0xF7, 0x64, 0x00, 0x00, 0x07, 0x3F, 0xF7, 0x34, 0x04, 0x01, 0x01, 0x00, 0xFA, 0x9E, 0x04 }; + + + // Instrument pointer array to access instruments by MIDI program. + const unsigned char *midiInstruments[] = { + INSTRUMENT_PIANO1, INSTRUMENT_PIANO2, INSTRUMENT_PIANO3, INSTRUMENT_HONKTONK, INSTRUMENT_EP1, INSTRUMENT_EP2, + INSTRUMENT_HARPSIC, INSTRUMENT_CLAVIC, INSTRUMENT_CELESTA, INSTRUMENT_GLOCK, INSTRUMENT_MUSICBOX, INSTRUMENT_VIBES, + INSTRUMENT_MARIMBA, INSTRUMENT_XYLO, INSTRUMENT_TUBEBELL, INSTRUMENT_SANTUR, INSTRUMENT_ORGAN1, INSTRUMENT_ORGAN2, + INSTRUMENT_ORGAN3, INSTRUMENT_PIPEORG, INSTRUMENT_REEDORG, INSTRUMENT_ACORDIAN, INSTRUMENT_HARMONIC, INSTRUMENT_BANDNEON, + INSTRUMENT_NYLONGT, INSTRUMENT_STEELGT, INSTRUMENT_JAZZGT, INSTRUMENT_CLEANGT, INSTRUMENT_MUTEGT, INSTRUMENT_OVERDGT, + INSTRUMENT_DISTGT, INSTRUMENT_GTHARMS, INSTRUMENT_ACOUBASS, INSTRUMENT_FINGBASS, INSTRUMENT_PICKBASS, INSTRUMENT_FRETLESS, + INSTRUMENT_SLAPBAS1, INSTRUMENT_SLAPBAS2, INSTRUMENT_SYNBASS1, INSTRUMENT_SYNBASS2, INSTRUMENT_VIOLIN, INSTRUMENT_VIOLA, + INSTRUMENT_CELLO, INSTRUMENT_CONTRAB, INSTRUMENT_TREMSTR, INSTRUMENT_PIZZ, INSTRUMENT_HARP, INSTRUMENT_TIMPANI, + INSTRUMENT_STRINGS, INSTRUMENT_SLOWSTR, INSTRUMENT_SYNSTR1, INSTRUMENT_SYNSTR2, INSTRUMENT_CHOIR, INSTRUMENT_OOHS, + INSTRUMENT_SYNVOX, INSTRUMENT_ORCHIT, INSTRUMENT_TRUMPET, INSTRUMENT_TROMBONE, INSTRUMENT_TUBA, INSTRUMENT_MUTETRP, + INSTRUMENT_FRHORN, INSTRUMENT_BRASS1, INSTRUMENT_SYNBRAS1, INSTRUMENT_SYNBRAS2, INSTRUMENT_SOPSAX, INSTRUMENT_ALTOSAX, + INSTRUMENT_TENSAX, INSTRUMENT_BARISAX, INSTRUMENT_OBOE, INSTRUMENT_ENGLHORN, INSTRUMENT_BASSOON, INSTRUMENT_CLARINET, + INSTRUMENT_PICCOLO, INSTRUMENT_FLUTE1, INSTRUMENT_RECORDER, INSTRUMENT_PANFLUTE, INSTRUMENT_BOTTLEB, INSTRUMENT_SHAKU, + INSTRUMENT_WHISTLE, INSTRUMENT_OCARINA, INSTRUMENT_SQUARWAV, INSTRUMENT_SAWWAV, INSTRUMENT_SYNCALLI, INSTRUMENT_CHIFLEAD, + INSTRUMENT_CHARANG, INSTRUMENT_SOLOVOX, INSTRUMENT_FIFTHSAW, INSTRUMENT_BASSLEAD, INSTRUMENT_FANTASIA, INSTRUMENT_WARMPAD, + INSTRUMENT_POLYSYN, INSTRUMENT_SPACEVOX, INSTRUMENT_BOWEDGLS, INSTRUMENT_METALPAD, INSTRUMENT_HALOPAD, INSTRUMENT_SWEEPPAD, + INSTRUMENT_ICERAIN, INSTRUMENT_SOUNDTRK, INSTRUMENT_CRYSTAL, INSTRUMENT_ATMOSPH, INSTRUMENT_BRIGHT, INSTRUMENT_GOBLIN, + INSTRUMENT_ECHODROP, INSTRUMENT_STARTHEM, INSTRUMENT_SITAR, INSTRUMENT_BANJO, INSTRUMENT_SHAMISEN, INSTRUMENT_KOTO, + INSTRUMENT_KALIMBA, INSTRUMENT_BAGPIPE, INSTRUMENT_FIDDLE, INSTRUMENT_SHANNAI, INSTRUMENT_TINKLBEL, INSTRUMENT_AGOGO, + INSTRUMENT_STEELDRM, INSTRUMENT_WOODBLOK, INSTRUMENT_TAIKO, INSTRUMENT_MELOTOM, INSTRUMENT_SYNDRUM, INSTRUMENT_REVRSCYM, + INSTRUMENT_FRETNOIS, INSTRUMENT_BRTHNOIS, INSTRUMENT_SEASHORE, INSTRUMENT_BIRDS, INSTRUMENT_TELEPHON, INSTRUMENT_HELICOPT, + INSTRUMENT_APPLAUSE, INSTRUMENT_GUNSHOT + }; + +#endif diff --git a/src/midi_instruments_4op.h b/src/midi_instruments_4op.h new file mode 100644 index 0000000..1e0105f --- /dev/null +++ b/src/midi_instruments_4op.h @@ -0,0 +1,195 @@ +/** + * This file contains 4-operator MIDI instrument defenitions for use with the OPL2 Audio Board library. These were + * converted from the General MIDI timbres by The Fat Man(TM). This file contains the melodic instrments only. + * + * Instrument definition is based on Adlib instrument bank format. + * 0 - Rhythm mode drum channel + * Drum channels are predefined by the YM3812 and cannot be redefined. Regular instruments have their channel set + * to 0x00 and can be assigned to any channel by the setInstrument function. Rhythm mode instruments can only be + * used when rhythm mode is active (see OPL2.setPercussion). + * + * 1 - Channel c, operator 1, register 0x20 + * Tremolo(1) | Vibrato(1) | Sustain(1) | KSR(1) | Frequency multiplier (4) + * + * 2 - Channel c, operator 1, register 0x40 + * Key scale level(2) | Output level(6) + * + * 3 - Channel c, operator 1, register 0x60 + * Attack(4) | Decay(4) + * + * 4 - Channel c, operator 1, register 0x80 + * Sustain(4) | Release(4) + * + * 5 - Channel c, operator 1, register 0xE0 + * Undefined(5) | Waveform(3) + * + * 6 - Channel c, register 0xC0 + * Undefined(4) | Modulation feedback factor(3) | Synth type(1) + * + * 7 - Channel c, operator 2, register 0x20 + * 8 - Channel c, operator 2, register 0x40 + * 9 - Channel c, operator 2, register 0x60 + * 10 - Channel c, operator 2, register 0x80 + * 11 - Channel c, operator 2, register 0xE0 + */ + +#ifndef _MIDI_INST4OP_H_ + #define _MIDI_INST4OP_H_ + + const unsigned char INSTRUMENT_PIANO1[24] PROGMEM = { 0x00, 0x31, 0x8F, 0xF1, 0xB2, 0x00, 0x08, 0x11, 0x83, 0xF1, 0xAF, 0x00, 0x00, 0x31, 0x19, 0xF1, 0xB2, 0x00, 0x01, 0x31, 0x01, 0xC1, 0xD5, 0x00 }; + const unsigned char INSTRUMENT_PIANO2[24] PROGMEM = { 0x00, 0x11, 0x4C, 0xF1, 0xD2, 0x00, 0x0A, 0x11, 0x83, 0xF2, 0xE6, 0x00, 0x00, 0x11, 0x15, 0xC1, 0xD5, 0x00, 0x01, 0x31, 0x00, 0xC2, 0xE6, 0x00 }; + const unsigned char INSTRUMENT_PIANO3[24] PROGMEM = { 0x00, 0x15, 0x5F, 0xF3, 0xD4, 0x00, 0x0E, 0x15, 0x61, 0xB1, 0xE4, 0x00, 0x00, 0x11, 0x5C, 0xB1, 0xE4, 0x00, 0x00, 0x11, 0x00, 0xB1, 0xB5, 0x00 }; + const unsigned char INSTRUMENT_HONKTONK[24] PROGMEM = { 0x00, 0x11, 0x89, 0xF1, 0xD4, 0x00, 0x0D, 0x02, 0x5F, 0xC3, 0xE4, 0x00, 0x00, 0x00, 0x9B, 0xC1, 0x35, 0x00, 0x00, 0x11, 0x00, 0xC1, 0xD5, 0x00 }; + const unsigned char INSTRUMENT_EP1[24] PROGMEM = { 0x00, 0x1C, 0x6F, 0xF2, 0xE7, 0x00, 0x0C, 0x01, 0x80, 0xF2, 0xB8, 0x00, 0x00, 0x11, 0x9C, 0xB1, 0xE5, 0x00, 0x01, 0x11, 0x80, 0xF2, 0xB8, 0x00 }; + const unsigned char INSTRUMENT_EP2[24] PROGMEM = { 0x00, 0x1C, 0x3A, 0xC2, 0xE7, 0x00, 0x00, 0x01, 0x80, 0xF3, 0xB8, 0x00, 0x00, 0x11, 0x1B, 0xB1, 0xF5, 0x00, 0x01, 0x11, 0x80, 0xF2, 0xD8, 0x00 }; + const unsigned char INSTRUMENT_HARPSIC[24] PROGMEM = { 0x00, 0x31, 0x90, 0xF0, 0x31, 0x00, 0x08, 0x34, 0x9F, 0xF2, 0x37, 0x00, 0x00, 0x24, 0x1C, 0xF3, 0x51, 0x04, 0x00, 0x11, 0x00, 0xF2, 0x97, 0x04 }; + const unsigned char INSTRUMENT_CLAVIC[24] PROGMEM = { 0x00, 0x10, 0x60, 0xF2, 0x50, 0x00, 0x04, 0x31, 0x5D, 0xE1, 0xF0, 0x00, 0x00, 0x30, 0xA2, 0xB2, 0x40, 0x00, 0x00, 0x11, 0x80, 0xF1, 0xE9, 0x05 }; + const unsigned char INSTRUMENT_CELESTA[24] PROGMEM = { 0x00, 0x02, 0x25, 0xCE, 0xE6, 0x00, 0x00, 0x01, 0x00, 0xF4, 0xE6, 0x00, 0x00, 0x07, 0xA1, 0xF5, 0xE6, 0x00, 0x01, 0x41, 0x00, 0xF3, 0xE5, 0x00 }; + const unsigned char INSTRUMENT_GLOCK[24] PROGMEM = { 0x00, 0x17, 0x54, 0xF2, 0xE3, 0x00, 0x0A, 0x11, 0x06, 0xC2, 0xE2, 0x00, 0x00, 0x19, 0x2B, 0xF2, 0xC3, 0x00, 0x01, 0x91, 0x07, 0xF2, 0xD2, 0x00 }; + const unsigned char INSTRUMENT_MUSICBOX[24] PROGMEM = { 0x00, 0x17, 0x21, 0x56, 0x04, 0x00, 0x02, 0x01, 0x00, 0xF6, 0x04, 0x00, 0x00, 0x1A, 0x27, 0xA6, 0x04, 0x00, 0x01, 0x00, 0x0A, 0xF6, 0x04, 0x00 }; + const unsigned char INSTRUMENT_VIBES[24] PROGMEM = { 0x00, 0x25, 0x9A, 0x08, 0x79, 0x00, 0x0A, 0x85, 0x5B, 0xE3, 0xE6, 0x00, 0x00, 0x15, 0x62, 0xF3, 0xE6, 0x00, 0x01, 0x81, 0x00, 0xF2, 0xE6, 0x00 }; + const unsigned char INSTRUMENT_MARIMBA[24] PROGMEM = { 0x00, 0x1C, 0xA3, 0xF7, 0x55, 0x00, 0x06, 0x20, 0x0D, 0x85, 0xD8, 0x00, 0x00, 0x18, 0x23, 0xF7, 0x55, 0x00, 0x01, 0x21, 0x00, 0xE5, 0xD8, 0x00 }; + const unsigned char INSTRUMENT_XYLO[24] PROGMEM = { 0x00, 0x0A, 0x53, 0xF9, 0xD6, 0x00, 0x0A, 0x84, 0x80, 0xF7, 0xD6, 0x00, 0x00, 0x15, 0x91, 0xF6, 0xA6, 0x00, 0x01, 0x01, 0x00, 0xF6, 0xE6, 0x00 }; + const unsigned char INSTRUMENT_TUBEBELL[24] PROGMEM = { 0x00, 0x41, 0x8A, 0xD4, 0xB3, 0x00, 0x04, 0x80, 0x13, 0xC2, 0xB4, 0x00, 0x00, 0x45, 0x59, 0xD3, 0x82, 0x00, 0x01, 0x81, 0x80, 0xA3, 0xE3, 0x00 }; + const unsigned char INSTRUMENT_SANTUR[24] PROGMEM = { 0x00, 0x01, 0x84, 0xE7, 0xF7, 0x00, 0x0D, 0x03, 0x49, 0x74, 0x55, 0x01, 0x00, 0x01, 0x80, 0xB3, 0x05, 0x00, 0x01, 0x01, 0x80, 0x76, 0xF7, 0x00 }; + const unsigned char INSTRUMENT_ORGAN1[24] PROGMEM = { 0x00, 0xA0, 0x85, 0xA2, 0x2A, 0x00, 0x07, 0x22, 0x9E, 0xA5, 0x2A, 0x00, 0x00, 0xA2, 0x83, 0xA5, 0x2A, 0x00, 0x01, 0x28, 0x95, 0xA1, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_ORGAN2[24] PROGMEM = { 0x00, 0xA0, 0x85, 0x91, 0x2A, 0x00, 0x07, 0x21, 0x0B, 0xC8, 0x3A, 0x00, 0x00, 0x20, 0x81, 0xC6, 0x38, 0x00, 0x01, 0x21, 0x80, 0xF6, 0x57, 0x00 }; + const unsigned char INSTRUMENT_ORGAN3[24] PROGMEM = { 0x00, 0xE3, 0x56, 0xA6, 0x2A, 0x01, 0x08, 0x61, 0x83, 0xAF, 0x0A, 0x00, 0x00, 0xE1, 0x91, 0xAF, 0x0A, 0x00, 0x01, 0x62, 0x83, 0xAF, 0x0A, 0x00 }; + const unsigned char INSTRUMENT_PIPEORG[24] PROGMEM = { 0x00, 0x25, 0x5F, 0xB0, 0x02, 0x00, 0x0C, 0x30, 0x40, 0x70, 0x05, 0x00, 0x00, 0x31, 0x46, 0xC0, 0x02, 0x00, 0x01, 0x31, 0x80, 0x60, 0x05, 0x00 }; + const unsigned char INSTRUMENT_REEDORG[24] PROGMEM = { 0x00, 0x21, 0x93, 0xC8, 0x15, 0x00, 0x0C, 0x31, 0x00, 0x6F, 0x05, 0x00, 0x00, 0x31, 0x16, 0xCF, 0x05, 0x00, 0x01, 0x32, 0x87, 0x7F, 0x05, 0x00 }; + const unsigned char INSTRUMENT_ACORDIAN[24] PROGMEM = { 0x00, 0x23, 0xAC, 0x72, 0x1A, 0x07, 0x00, 0x21, 0x83, 0x72, 0x2A, 0x00, 0x00, 0x23, 0x22, 0x62, 0x1A, 0x04, 0x01, 0xA1, 0x00, 0x62, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_HARMONIC[24] PROGMEM = { 0x00, 0x25, 0xA1, 0xFF, 0x06, 0x00, 0x0A, 0x23, 0x2F, 0xFF, 0x05, 0x00, 0x00, 0xA1, 0x1F, 0xFF, 0x05, 0x04, 0x00, 0x22, 0x80, 0x6F, 0x09, 0x00 }; + const unsigned char INSTRUMENT_BANDNEON[24] PROGMEM = { 0x00, 0x23, 0x19, 0x62, 0x1A, 0x01, 0x0C, 0x21, 0x80, 0x72, 0x2A, 0x00, 0x00, 0x23, 0x1E, 0x62, 0x1A, 0x04, 0x01, 0x22, 0x83, 0x72, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_NYLONGT[24] PROGMEM = { 0x00, 0x02, 0x9C, 0xF3, 0x74, 0x00, 0x0A, 0x41, 0x80, 0xF3, 0xB8, 0x00, 0x00, 0x02, 0xA5, 0xD3, 0x74, 0x02, 0x01, 0x82, 0x40, 0xD3, 0xB8, 0x00 }; + const unsigned char INSTRUMENT_STEELGT[24] PROGMEM = { 0x00, 0x34, 0x5B, 0xF2, 0xF6, 0x02, 0x0C, 0x31, 0x9E, 0xF2, 0xF7, 0x00, 0x00, 0x23, 0xAB, 0xF2, 0xF7, 0x00, 0x00, 0x11, 0x00, 0xF1, 0xE7, 0x00 }; + const unsigned char INSTRUMENT_JAZZGT[24] PROGMEM = { 0x00, 0x22, 0x53, 0xF3, 0xFA, 0x00, 0x0A, 0x23, 0x66, 0xF2, 0xFA, 0x00, 0x00, 0x21, 0xA7, 0xC2, 0xFA, 0x00, 0x00, 0x21, 0x00, 0xC2, 0xF7, 0x00 }; + const unsigned char INSTRUMENT_CLEANGT[24] PROGMEM = { 0x00, 0x02, 0x4C, 0xFA, 0x22, 0x00, 0x08, 0x01, 0x97, 0xF3, 0xF3, 0x00, 0x00, 0x04, 0x9D, 0xC2, 0xF3, 0x01, 0x00, 0x11, 0x00, 0xC1, 0xF7, 0x00 }; + const unsigned char INSTRUMENT_MUTEGT[24] PROGMEM = { 0x00, 0x11, 0x87, 0xC7, 0xAF, 0x00, 0x08, 0x01, 0x00, 0xF5, 0xF8, 0x00, 0x00, 0x01, 0x18, 0xC3, 0x98, 0x00, 0x01, 0x02, 0x00, 0xC3, 0xF8, 0x00 }; + const unsigned char INSTRUMENT_OVERDGT[24] PROGMEM = { 0x00, 0x13, 0x0D, 0xB9, 0xF2, 0x04, 0x0A, 0x02, 0x1A, 0x91, 0x11, 0x00, 0x00, 0x21, 0x99, 0x92, 0x4A, 0x01, 0x00, 0x22, 0x00, 0x91, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_DISTGT[24] PROGMEM = { 0x00, 0x23, 0x96, 0xF8, 0x42, 0x02, 0x00, 0x22, 0x1A, 0x91, 0xFA, 0x02, 0x00, 0x21, 0x99, 0x92, 0xBA, 0x00, 0x00, 0x22, 0x00, 0x91, 0x4A, 0x00 }; + const unsigned char INSTRUMENT_GTHARMS[24] PROGMEM = { 0x00, 0x09, 0xA1, 0x20, 0x4F, 0x00, 0x08, 0x04, 0x80, 0xD1, 0xF8, 0x00, 0x00, 0x02, 0x87, 0xF8, 0xF8, 0x02, 0x01, 0x02, 0x00, 0xF6, 0xF8, 0x00 }; + const unsigned char INSTRUMENT_ACOUBASS[24] PROGMEM = { 0x00, 0x01, 0x4D, 0xA7, 0x15, 0x00, 0x02, 0x01, 0x00, 0xA3, 0xC8, 0x00, 0x00, 0x01, 0x93, 0x71, 0x31, 0x00, 0x01, 0x01, 0x00, 0x73, 0xC8, 0x00 }; + const unsigned char INSTRUMENT_FINGBASS[24] PROGMEM = { 0x00, 0x11, 0xA8, 0xF1, 0xE5, 0x00, 0x04, 0x12, 0x57, 0xF3, 0xE5, 0x00, 0x00, 0x11, 0x97, 0xE1, 0xE5, 0x00, 0x00, 0x11, 0x00, 0xE1, 0xE6, 0x00 }; + const unsigned char INSTRUMENT_PICKBASS[24] PROGMEM = { 0x00, 0x01, 0xB3, 0xF0, 0xC7, 0x00, 0x06, 0x01, 0x16, 0xF1, 0x27, 0x00, 0x00, 0x01, 0x16, 0xF1, 0x27, 0x00, 0x00, 0x01, 0x00, 0xF1, 0x28, 0x00 }; + const unsigned char INSTRUMENT_FRETLESS[24] PROGMEM = { 0x00, 0x31, 0x5B, 0x51, 0x28, 0x00, 0x0C, 0x32, 0x00, 0x71, 0x48, 0x00, 0x00, 0x31, 0x19, 0x71, 0x48, 0x00, 0x01, 0x31, 0x00, 0x71, 0x48, 0x00 }; + const unsigned char INSTRUMENT_SLAPBAS1[24] PROGMEM = { 0x00, 0x01, 0x8B, 0xA1, 0x9A, 0x00, 0x08, 0x21, 0x40, 0xF2, 0xDF, 0x00, 0x00, 0x04, 0x0B, 0xF9, 0xDA, 0x00, 0x01, 0x01, 0x80, 0xF7, 0xDF, 0x00 }; + const unsigned char INSTRUMENT_SLAPBAS2[24] PROGMEM = { 0x00, 0x01, 0x89, 0xA1, 0x9A, 0x00, 0x06, 0x21, 0x40, 0xF2, 0xDF, 0x00, 0x00, 0x04, 0x0B, 0xF9, 0xDA, 0x00, 0x01, 0x01, 0x80, 0xF7, 0xDF, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS1[24] PROGMEM = { 0x00, 0x21, 0x1C, 0xF6, 0xC8, 0x00, 0x0A, 0x01, 0x1F, 0xF1, 0xC8, 0x00, 0x00, 0x01, 0xD8, 0xF1, 0xC8, 0x00, 0x00, 0x01, 0x00, 0xF2, 0xC8, 0x00 }; + const unsigned char INSTRUMENT_SYNBASS2[24] PROGMEM = { 0x00, 0x21, 0x1C, 0xF6, 0xC8, 0x01, 0x0A, 0x01, 0x1F, 0xF1, 0xC8, 0x00, 0x00, 0x01, 0x12, 0x54, 0x42, 0x00, 0x00, 0x01, 0x00, 0xF2, 0xC8, 0x00 }; + const unsigned char INSTRUMENT_VIOLIN[24] PROGMEM = { 0x00, 0x31, 0x15, 0xDD, 0x13, 0x01, 0x08, 0x21, 0x00, 0x56, 0x26, 0x00, 0x00, 0x12, 0x95, 0x8D, 0x03, 0x01, 0x01, 0x03, 0x8B, 0x65, 0x86, 0x00 }; + const unsigned char INSTRUMENT_VIOLA[24] PROGMEM = { 0x00, 0x31, 0x17, 0xDD, 0x13, 0x01, 0x08, 0x21, 0x00, 0x56, 0x26, 0x00, 0x00, 0x12, 0x95, 0x8D, 0x03, 0x01, 0x01, 0x03, 0x8B, 0x65, 0x86, 0x00 }; + const unsigned char INSTRUMENT_CELLO[24] PROGMEM = { 0x00, 0x31, 0x95, 0xDD, 0x13, 0x05, 0x08, 0x21, 0x00, 0x56, 0x26, 0x00, 0x00, 0x13, 0x95, 0x8D, 0x03, 0x01, 0x01, 0x05, 0x8C, 0x66, 0x86, 0x00 }; + const unsigned char INSTRUMENT_CONTRAB[24] PROGMEM = { 0x00, 0x70, 0x92, 0xCC, 0x43, 0x02, 0x0E, 0xA0, 0x03, 0x74, 0x17, 0x02, 0x00, 0x21, 0x95, 0xBF, 0x07, 0x00, 0x01, 0x21, 0x00, 0x6F, 0x07, 0x01 }; + const unsigned char INSTRUMENT_TREMSTR[24] PROGMEM = { 0x00, 0x61, 0x97, 0xC2, 0x15, 0x05, 0x06, 0xA1, 0x00, 0x6F, 0x05, 0x00, 0x00, 0x63, 0x13, 0xB5, 0x8F, 0x00, 0x01, 0xA5, 0x94, 0xB5, 0x8F, 0x00 }; + const unsigned char INSTRUMENT_PIZZ[24] PROGMEM = { 0x00, 0x23, 0xA7, 0x85, 0x84, 0x00, 0x0E, 0x12, 0xA4, 0x82, 0x74, 0x00, 0x00, 0x02, 0x27, 0x82, 0x74, 0x00, 0x00, 0x11, 0x00, 0x85, 0x35, 0x00 }; + const unsigned char INSTRUMENT_HARP[24] PROGMEM = { 0x00, 0x23, 0xA7, 0x85, 0x84, 0x00, 0x0E, 0x12, 0xA4, 0x82, 0x74, 0x00, 0x00, 0x02, 0x27, 0x82, 0x74, 0x00, 0x00, 0x11, 0x00, 0x84, 0x33, 0x00 }; + const unsigned char INSTRUMENT_TIMPANI[24] PROGMEM = { 0x00, 0x10, 0x41, 0xF5, 0x05, 0x01, 0x02, 0x11, 0x00, 0xF2, 0xC3, 0x00, 0x00, 0x11, 0x01, 0xF5, 0x05, 0x00, 0x01, 0x12, 0x1E, 0xF2, 0xC3, 0x00 }; + const unsigned char INSTRUMENT_STRINGS[24] PROGMEM = { 0x00, 0x30, 0x98, 0x61, 0x03, 0x02, 0x0E, 0xA0, 0x03, 0x64, 0x17, 0x02, 0x00, 0x61, 0x92, 0x65, 0x17, 0x01, 0x01, 0x21, 0x00, 0x65, 0x17, 0x00 }; + const unsigned char INSTRUMENT_SLOWSTR[24] PROGMEM = { 0x00, 0x30, 0x98, 0x41, 0x23, 0x02, 0x0E, 0x60, 0x01, 0x44, 0x17, 0x02, 0x00, 0xA1, 0x98, 0x7F, 0x03, 0x01, 0x01, 0x21, 0x00, 0x3F, 0x07, 0x01 }; + const unsigned char INSTRUMENT_SYNSTR1[24] PROGMEM = { 0x00, 0x21, 0x1A, 0xC1, 0x12, 0x00, 0x0C, 0x61, 0x00, 0x4F, 0x05, 0x00, 0x00, 0xA1, 0x93, 0xC1, 0x12, 0x00, 0x01, 0x21, 0x00, 0x4F, 0x05, 0x00 }; + const unsigned char INSTRUMENT_SYNSTR2[24] PROGMEM = { 0x00, 0x21, 0x18, 0xC1, 0x22, 0x00, 0x0C, 0x61, 0x00, 0x4F, 0x05, 0x00, 0x00, 0x22, 0x0B, 0xC1, 0x22, 0x00, 0x01, 0x22, 0x1C, 0x4F, 0x05, 0x00 }; + const unsigned char INSTRUMENT_CHOIR[24] PROGMEM = { 0x00, 0x06, 0x03, 0xA0, 0xF5, 0x00, 0x0E, 0xE4, 0x23, 0xA3, 0x35, 0x00, 0x00, 0xA1, 0x51, 0x7F, 0x07, 0x00, 0x01, 0x61, 0x00, 0x7F, 0x07, 0x00 }; + const unsigned char INSTRUMENT_OOHS[24] PROGMEM = { 0x00, 0x02, 0x05, 0x84, 0x57, 0x00, 0x0E, 0xE4, 0x16, 0xA7, 0x74, 0x00, 0x00, 0xA1, 0x90, 0x74, 0x39, 0x00, 0x01, 0x61, 0x00, 0x71, 0x67, 0x00 }; + const unsigned char INSTRUMENT_SYNVOX[24] PROGMEM = { 0x00, 0x0A, 0x65, 0x99, 0x54, 0x00, 0x08, 0x07, 0x60, 0x97, 0x63, 0x00, 0x00, 0xA1, 0x59, 0x5F, 0x04, 0x01, 0x00, 0x61, 0x00, 0x6F, 0x06, 0x00 }; + const unsigned char INSTRUMENT_ORCHIT[24] PROGMEM = { 0x00, 0x00, 0x00, 0x65, 0x68, 0x02, 0x0B, 0x00, 0x00, 0xC5, 0x13, 0x06, 0x00, 0x00, 0x00, 0xC8, 0x06, 0x06, 0x01, 0x00, 0x00, 0x74, 0x07, 0x03 }; + const unsigned char INSTRUMENT_TRUMPET[24] PROGMEM = { 0x00, 0x21, 0x92, 0x85, 0x17, 0x00, 0x0C, 0x21, 0x01, 0x8F, 0x09, 0x00, 0x00, 0x21, 0x15, 0x84, 0x17, 0x00, 0x01, 0x61, 0x0B, 0xAF, 0x08, 0x00 }; + const unsigned char INSTRUMENT_TROMBONE[24] PROGMEM = { 0x00, 0x21, 0x94, 0x85, 0x17, 0x00, 0x0C, 0x21, 0x05, 0x7F, 0x09, 0x00, 0x00, 0x21, 0x15, 0x84, 0x17, 0x00, 0x01, 0x61, 0x0D, 0xAF, 0x08, 0x00 }; + const unsigned char INSTRUMENT_TUBA[24] PROGMEM = { 0x00, 0x20, 0x94, 0x76, 0x15, 0x00, 0x0C, 0x61, 0x00, 0x82, 0x37, 0x00, 0x00, 0xB1, 0xD3, 0x61, 0x26, 0x00, 0x01, 0x71, 0x80, 0x61, 0x26, 0x00 }; + const unsigned char INSTRUMENT_MUTETRP[24] PROGMEM = { 0x00, 0x31, 0x15, 0x71, 0x27, 0x01, 0x0C, 0x61, 0x83, 0x91, 0x49, 0x00, 0x00, 0xB1, 0x10, 0x7D, 0x27, 0x00, 0x01, 0x21, 0x08, 0x7A, 0x29, 0x00 }; + const unsigned char INSTRUMENT_FRHORN[24] PROGMEM = { 0x00, 0x21, 0x9F, 0x63, 0x0A, 0x00, 0x0E, 0x21, 0x00, 0x7F, 0x0B, 0x00, 0x00, 0xA1, 0xA2, 0x65, 0x0A, 0x00, 0x01, 0x61, 0x00, 0x7F, 0x0B, 0x00 }; + const unsigned char INSTRUMENT_BRASS1[24] PROGMEM = { 0x00, 0x21, 0x16, 0x72, 0x25, 0x00, 0x0C, 0x21, 0x05, 0x7F, 0x0A, 0x00, 0x00, 0x21, 0x1D, 0x7A, 0x35, 0x00, 0x01, 0x21, 0x09, 0x7A, 0x3A, 0x00 }; + const unsigned char INSTRUMENT_SYNBRAS1[24] PROGMEM = { 0x00, 0x21, 0x16, 0xC2, 0x35, 0x00, 0x0E, 0x61, 0x09, 0xCF, 0x0A, 0x00, 0x00, 0xA1, 0x8A, 0x74, 0x45, 0x00, 0x01, 0x21, 0x00, 0x7F, 0x08, 0x00 }; + const unsigned char INSTRUMENT_SYNBRAS2[24] PROGMEM = { 0x00, 0xA1, 0x97, 0x52, 0x1A, 0x00, 0x0C, 0x61, 0x00, 0x8F, 0x1B, 0x00, 0x00, 0x21, 0xA1, 0x75, 0x1A, 0x00, 0x01, 0x21, 0x00, 0x8F, 0x1B, 0x00 }; + const unsigned char INSTRUMENT_SOPSAX[24] PROGMEM = { 0x00, 0x31, 0x96, 0x93, 0x0F, 0x02, 0x08, 0xA1, 0x00, 0x72, 0x0F, 0x00, 0x00, 0x21, 0x96, 0x85, 0x07, 0x00, 0x01, 0x31, 0x00, 0x84, 0x27, 0x01 }; + const unsigned char INSTRUMENT_ALTOSAX[24] PROGMEM = { 0x00, 0x31, 0x8E, 0x93, 0x03, 0x01, 0x08, 0xA1, 0x00, 0x72, 0x09, 0x00, 0x00, 0x24, 0xA1, 0xC5, 0x06, 0x00, 0x01, 0x31, 0x00, 0x64, 0x27, 0x01 }; + const unsigned char INSTRUMENT_TENSAX[24] PROGMEM = { 0x00, 0xB1, 0x8E, 0x93, 0x06, 0x01, 0x0A, 0x71, 0x00, 0x72, 0x06, 0x00, 0x00, 0x21, 0x5D, 0x85, 0x08, 0x00, 0x01, 0xB1, 0x00, 0x84, 0x28, 0x00 }; + const unsigned char INSTRUMENT_BARISAX[24] PROGMEM = { 0x00, 0x31, 0x93, 0x93, 0x0F, 0x01, 0x0C, 0x72, 0x00, 0x72, 0x0F, 0x00, 0x00, 0x22, 0x61, 0x85, 0x06, 0x00, 0x01, 0xB1, 0x00, 0x84, 0x16, 0x00 }; + const unsigned char INSTRUMENT_OBOE[24] PROGMEM = { 0x00, 0x61, 0xA3, 0xA9, 0x2A, 0x00, 0x08, 0x23, 0x52, 0xA8, 0x36, 0x00, 0x00, 0xA1, 0x94, 0xAA, 0x16, 0x00, 0x00, 0x21, 0x80, 0x8F, 0x0A, 0x00 }; + const unsigned char INSTRUMENT_ENGLHORN[24] PROGMEM = { 0x00, 0x21, 0x21, 0x77, 0x29, 0x00, 0x02, 0x33, 0x55, 0x7A, 0x26, 0x01, 0x00, 0xA1, 0x93, 0x7A, 0x16, 0x00, 0x00, 0x22, 0x00, 0x7A, 0x19, 0x00 }; + const unsigned char INSTRUMENT_BASSOON[24] PROGMEM = { 0x00, 0x21, 0x2B, 0x7B, 0x07, 0x01, 0x0A, 0x22, 0x57, 0x7F, 0x00, 0x00, 0x00, 0x31, 0x51, 0x75, 0x19, 0x00, 0x00, 0x72, 0x00, 0x61, 0x19, 0x00 }; + const unsigned char INSTRUMENT_CLARINET[24] PROGMEM = { 0x00, 0x32, 0x90, 0x9B, 0x21, 0x00, 0x08, 0x21, 0x00, 0x72, 0x17, 0x00, 0x00, 0x32, 0x90, 0x9B, 0x21, 0x00, 0x01, 0x21, 0x13, 0x72, 0x17, 0x00 }; + const unsigned char INSTRUMENT_PICCOLO[24] PROGMEM = { 0x00, 0x25, 0x00, 0xDA, 0x11, 0x00, 0x0C, 0xE3, 0x2B, 0xA6, 0x68, 0x00, 0x00, 0xE1, 0x1F, 0x85, 0x5F, 0x00, 0x01, 0xE1, 0x00, 0x65, 0x1A, 0x00 }; + const unsigned char INSTRUMENT_FLUTE1[24] PROGMEM = { 0x00, 0x25, 0x00, 0xDA, 0x11, 0x00, 0x0C, 0xE3, 0x2B, 0xA6, 0x68, 0x00, 0x00, 0xE1, 0x46, 0x88, 0x5F, 0x00, 0x01, 0xE1, 0x00, 0x65, 0x1A, 0x00 }; + const unsigned char INSTRUMENT_RECORDER[24] PROGMEM = { 0x00, 0xA4, 0xA2, 0xC9, 0x29, 0x00, 0x0C, 0x21, 0x80, 0x6F, 0x08, 0x00, 0x00, 0xA2, 0xAA, 0xCA, 0x15, 0x00, 0x01, 0x21, 0x00, 0x6F, 0x08, 0x00 }; + const unsigned char INSTRUMENT_PANFLUTE[24] PROGMEM = { 0x00, 0x25, 0x00, 0xDA, 0x11, 0x00, 0x0C, 0x23, 0x1E, 0xA6, 0x68, 0x00, 0x00, 0x21, 0x8C, 0x88, 0x58, 0x00, 0x01, 0x21, 0x00, 0x65, 0x1A, 0x00 }; + const unsigned char INSTRUMENT_BOTTLEB[24] PROGMEM = { 0x00, 0xA1, 0x0D, 0x76, 0xC6, 0x00, 0x0F, 0x26, 0x59, 0x87, 0x86, 0x00, 0x00, 0x22, 0x56, 0x66, 0x56, 0x00, 0x00, 0xA1, 0x00, 0x65, 0x26, 0x00 }; + const unsigned char INSTRUMENT_SHAKU[24] PROGMEM = { 0x00, 0x26, 0x00, 0x9F, 0x01, 0x00, 0x0E, 0x64, 0x25, 0x76, 0x48, 0x00, 0x00, 0x22, 0xCB, 0x56, 0x46, 0x00, 0x01, 0xA1, 0x00, 0x45, 0x36, 0x00 }; + const unsigned char INSTRUMENT_WHISTLE[24] PROGMEM = { 0x00, 0xE1, 0x67, 0x67, 0x14, 0x01, 0x0C, 0x61, 0x00, 0x54, 0x17, 0x00, 0x00, 0x21, 0x6D, 0x67, 0x14, 0x01, 0x01, 0x21, 0x00, 0x44, 0x16, 0x00 }; + const unsigned char INSTRUMENT_OCARINA[24] PROGMEM = { 0x00, 0x26, 0x00, 0xDF, 0x01, 0x00, 0x0C, 0xE4, 0x2B, 0x76, 0x38, 0x00, 0x00, 0x22, 0xD8, 0x95, 0x36, 0x00, 0x01, 0xE1, 0x00, 0x76, 0x07, 0x00 }; + const unsigned char INSTRUMENT_SQUARWAV[24] PROGMEM = { 0x00, 0x21, 0x35, 0xFF, 0x0F, 0x00, 0x04, 0x21, 0xB7, 0xFF, 0x0F, 0x00, 0x00, 0x21, 0xB9, 0xFF, 0x0F, 0x00, 0x00, 0x21, 0x80, 0xFF, 0x0F, 0x06 }; + const unsigned char INSTRUMENT_SAWWAV[24] PROGMEM = { 0x00, 0x21, 0x36, 0xFF, 0x0F, 0x00, 0x0A, 0x21, 0x1B, 0xFF, 0x0F, 0x00, 0x00, 0x21, 0x1D, 0xFF, 0x0F, 0x00, 0x00, 0x61, 0x00, 0xCF, 0x09, 0x04 }; + const unsigned char INSTRUMENT_SYNCALLI[24] PROGMEM = { 0x00, 0xA3, 0x00, 0xC4, 0x87, 0x00, 0x0E, 0x26, 0x57, 0xC6, 0x76, 0x00, 0x00, 0x22, 0x46, 0x86, 0x55, 0x00, 0x01, 0x21, 0x80, 0x64, 0x18, 0x00 }; + const unsigned char INSTRUMENT_CHIFLEAD[24] PROGMEM = { 0x00, 0x21, 0x48, 0xA3, 0x4A, 0x00, 0x08, 0x21, 0x00, 0x86, 0x0A, 0x00, 0x00, 0x21, 0x45, 0x66, 0x12, 0x00, 0x01, 0x21, 0x00, 0x96, 0x0A, 0x00 }; + const unsigned char INSTRUMENT_CHARANG[24] PROGMEM = { 0x00, 0x12, 0x0D, 0xB9, 0xF2, 0x04, 0x0A, 0x01, 0x1A, 0x91, 0x11, 0x00, 0x00, 0x21, 0x99, 0x92, 0x2A, 0x01, 0x00, 0x22, 0x00, 0x91, 0x2A, 0x00 }; + const unsigned char INSTRUMENT_SOLOVOX[24] PROGMEM = { 0x00, 0x61, 0x40, 0x7D, 0x15, 0x00, 0x0E, 0xB1, 0xA3, 0x72, 0x15, 0x00, 0x00, 0xA2, 0x5D, 0xDF, 0x05, 0x00, 0x01, 0x61, 0x40, 0x7F, 0x07, 0x00 }; + const unsigned char INSTRUMENT_FIFTHSAW[24] PROGMEM = { 0x00, 0x20, 0x36, 0xFF, 0x01, 0x00, 0x08, 0x61, 0x00, 0x8F, 0x06, 0x04, 0x00, 0x21, 0x27, 0xFF, 0x0F, 0x00, 0x01, 0x61, 0x00, 0x8F, 0x07, 0x04 }; + const unsigned char INSTRUMENT_BASSLEAD[24] PROGMEM = { 0x00, 0x21, 0x8F, 0xF1, 0x29, 0x00, 0x0A, 0x21, 0x80, 0xF4, 0x09, 0x00, 0x00, 0x21, 0x1D, 0xF1, 0x09, 0x01, 0x01, 0x21, 0x80, 0xF1, 0x09, 0x01 }; + const unsigned char INSTRUMENT_FANTASIA[24] PROGMEM = { 0x00, 0x17, 0x1A, 0x53, 0x03, 0x01, 0x02, 0x08, 0x0D, 0xF6, 0x04, 0x00, 0x00, 0xA1, 0x9D, 0x41, 0x32, 0x00, 0x01, 0x61, 0x00, 0x61, 0x15, 0x00 }; + const unsigned char INSTRUMENT_WARMPAD[24] PROGMEM = { 0x00, 0x61, 0x1F, 0xA8, 0x11, 0x00, 0x0A, 0xB1, 0x80, 0x25, 0x03, 0x00, 0x00, 0x81, 0xA1, 0xA1, 0x31, 0x00, 0x01, 0x71, 0x00, 0x25, 0x03, 0x00 }; + const unsigned char INSTRUMENT_POLYSYN[24] PROGMEM = { 0x00, 0x61, 0x17, 0x11, 0x14, 0x00, 0x0C, 0x61, 0x00, 0x55, 0x16, 0x00, 0x00, 0x61, 0x14, 0xC3, 0x45, 0x04, 0x01, 0x61, 0x00, 0xC3, 0x25, 0x00 }; + const unsigned char INSTRUMENT_SPACEVOX[24] PROGMEM = { 0x00, 0x2A, 0x80, 0x54, 0x21, 0x00, 0x0E, 0x27, 0xA6, 0x6A, 0x13, 0x00, 0x00, 0x31, 0x5D, 0x54, 0x01, 0x00, 0x01, 0x72, 0x00, 0x6A, 0x03, 0x00 }; + const unsigned char INSTRUMENT_BOWEDGLS[24] PROGMEM = { 0x00, 0x21, 0x97, 0x21, 0x33, 0x00, 0x08, 0x22, 0x03, 0x42, 0x45, 0x00, 0x00, 0xA1, 0x99, 0x21, 0xD4, 0x00, 0x01, 0x21, 0x03, 0x42, 0xD5, 0x00 }; + const unsigned char INSTRUMENT_METALPAD[24] PROGMEM = { 0x00, 0x21, 0x8D, 0x61, 0x33, 0x00, 0x0A, 0x61, 0x03, 0x42, 0x35, 0x00, 0x00, 0xA1, 0x1C, 0xA1, 0x77, 0x01, 0x01, 0x21, 0x00, 0x31, 0x47, 0x01 }; + const unsigned char INSTRUMENT_HALOPAD[24] PROGMEM = { 0x00, 0x21, 0x89, 0x11, 0x33, 0x00, 0x0A, 0x61, 0x03, 0x42, 0x35, 0x00, 0x00, 0x21, 0x8C, 0x21, 0xE4, 0x00, 0x01, 0x61, 0x03, 0x42, 0xD5, 0x00 }; + const unsigned char INSTRUMENT_SWEEPPAD[24] PROGMEM = { 0x00, 0x21, 0x15, 0x11, 0x47, 0x01, 0x00, 0x21, 0x00, 0xCF, 0x07, 0x00, 0x00, 0x21, 0x8C, 0x11, 0xE4, 0x00, 0x01, 0x61, 0x00, 0x52, 0xD5, 0x00 }; + const unsigned char INSTRUMENT_ICERAIN[24] PROGMEM = { 0x00, 0x0F, 0x83, 0xFE, 0x8A, 0x05, 0x0C, 0x04, 0x85, 0xFB, 0x06, 0x00, 0x00, 0x21, 0x99, 0xA8, 0x03, 0x00, 0x01, 0x22, 0x00, 0xA7, 0x04, 0x00 }; + const unsigned char INSTRUMENT_SOUNDTRK[24] PROGMEM = { 0x00, 0x21, 0x8C, 0x21, 0x32, 0x02, 0x06, 0x20, 0x97, 0x32, 0x13, 0x00, 0x00, 0x21, 0x0E, 0x11, 0x03, 0x01, 0x01, 0x21, 0x00, 0x31, 0x13, 0x00 }; + const unsigned char INSTRUMENT_CRYSTAL[24] PROGMEM = { 0x00, 0x01, 0x61, 0x75, 0x93, 0x00, 0x08, 0x02, 0x80, 0xC5, 0xB4, 0x00, 0x00, 0x06, 0x5B, 0x74, 0x95, 0x00, 0x01, 0x01, 0x00, 0xA5, 0x72, 0x00 }; + const unsigned char INSTRUMENT_ATMOSPH[24] PROGMEM = { 0x00, 0x22, 0x92, 0xB2, 0x56, 0x00, 0x0C, 0x61, 0x8A, 0xF2, 0x56, 0x00, 0x00, 0x21, 0x9D, 0x31, 0x34, 0x02, 0x01, 0xA1, 0x80, 0x32, 0x05, 0x00 }; + const unsigned char INSTRUMENT_BRIGHT[24] PROGMEM = { 0x00, 0x24, 0x40, 0xA3, 0x88, 0x00, 0x0E, 0x22, 0x5B, 0xA3, 0x87, 0x00, 0x00, 0x01, 0x13, 0xF1, 0x51, 0x01, 0x01, 0x41, 0x00, 0xF2, 0xF5, 0x00 }; + const unsigned char INSTRUMENT_GOBLIN[24] PROGMEM = { 0x00, 0xA1, 0x10, 0x11, 0x42, 0x00, 0x0A, 0x61, 0x92, 0x11, 0x73, 0x00, 0x00, 0x61, 0x98, 0x11, 0x21, 0x00, 0x01, 0xA1, 0x80, 0x1D, 0x03, 0x00 }; + const unsigned char INSTRUMENT_ECHODROP[24] PROGMEM = { 0x00, 0x62, 0x57, 0x7D, 0x16, 0x00, 0x04, 0xA2, 0x80, 0x72, 0x16, 0x00, 0x00, 0x61, 0x5B, 0x9F, 0x06, 0x00, 0x01, 0xA1, 0x00, 0x9F, 0x04, 0x00 }; + const unsigned char INSTRUMENT_STARTHEM[24] PROGMEM = { 0x00, 0x38, 0x9F, 0xA2, 0x24, 0x00, 0x06, 0x31, 0x9C, 0xF2, 0x24, 0x00, 0x00, 0x23, 0x9F, 0xF1, 0x14, 0x00, 0x00, 0x61, 0x00, 0x81, 0x23, 0x00 }; + const unsigned char INSTRUMENT_SITAR[24] PROGMEM = { 0x00, 0x01, 0x46, 0xF3, 0x53, 0x00, 0x00, 0x01, 0x80, 0xF1, 0xF6, 0x01, 0x00, 0x01, 0x43, 0xF2, 0x53, 0x00, 0x01, 0x08, 0x40, 0xF2, 0xF6, 0x00 }; + const unsigned char INSTRUMENT_BANJO[24] PROGMEM = { 0x00, 0x11, 0x10, 0xA5, 0x35, 0x01, 0x00, 0x17, 0xA4, 0xA5, 0x33, 0x01, 0x00, 0x11, 0x0D, 0xF6, 0x41, 0x01, 0x00, 0x11, 0x00, 0xF2, 0xE5, 0x02 }; + const unsigned char INSTRUMENT_SHAMISEN[24] PROGMEM = { 0x00, 0x55, 0x92, 0xF7, 0xF8, 0x00, 0x0E, 0x52, 0x9F, 0xF7, 0xE4, 0x01, 0x00, 0x41, 0x13, 0xF3, 0xE4, 0x00, 0x00, 0x51, 0x00, 0xF3, 0xE5, 0x01 }; + const unsigned char INSTRUMENT_KOTO[24] PROGMEM = { 0x00, 0x93, 0x91, 0xD4, 0x32, 0x00, 0x08, 0x11, 0x00, 0xEB, 0x11, 0x01, 0x00, 0x53, 0x91, 0xD4, 0x32, 0x00, 0x01, 0x13, 0x0D, 0xEB, 0x12, 0x01 }; + const unsigned char INSTRUMENT_KALIMBA[24] PROGMEM = { 0x00, 0x04, 0x4F, 0xFA, 0x56, 0x00, 0x0C, 0x01, 0x00, 0xC2, 0x05, 0x00, 0x00, 0x20, 0x00, 0xF7, 0xE5, 0x03, 0x01, 0x21, 0x0C, 0xF5, 0xE5, 0x00 }; + const unsigned char INSTRUMENT_BAGPIPE[24] PROGMEM = { 0x00, 0x21, 0x49, 0x7C, 0x20, 0x00, 0x06, 0x22, 0x00, 0x6F, 0x0C, 0x01, 0x00, 0x21, 0x09, 0x7C, 0x20, 0x00, 0x01, 0x22, 0x09, 0x6F, 0x0C, 0x01 }; + const unsigned char INSTRUMENT_FIDDLE[24] PROGMEM = { 0x00, 0x31, 0x85, 0xDD, 0x33, 0x01, 0x0A, 0x21, 0x00, 0x56, 0x16, 0x00, 0x00, 0x02, 0x83, 0xDD, 0x33, 0x01, 0x01, 0x01, 0x80, 0x66, 0x16, 0x00 }; + const unsigned char INSTRUMENT_SHANNAI[24] PROGMEM = { 0x00, 0x61, 0x33, 0x89, 0x29, 0x00, 0x06, 0xA3, 0xA4, 0xD8, 0x06, 0x04, 0x00, 0x21, 0x17, 0xDA, 0x05, 0x00, 0x00, 0x22, 0x80, 0x8F, 0x0B, 0x00 }; + const unsigned char INSTRUMENT_TINKLBEL[24] PROGMEM = { 0x00, 0x05, 0x6A, 0xF1, 0xE5, 0x00, 0x06, 0x03, 0x80, 0xC3, 0xE5, 0x00, 0x00, 0x01, 0x71, 0xC6, 0x53, 0x00, 0x01, 0x83, 0x40, 0xF5, 0xD5, 0x00 }; + const unsigned char INSTRUMENT_AGOGO[24] PROGMEM = { 0x00, 0x08, 0x15, 0xEC, 0x26, 0x00, 0x0A, 0x04, 0x00, 0xF8, 0x16, 0x00, 0x00, 0x07, 0x15, 0xEC, 0x26, 0x00, 0x01, 0x02, 0x00, 0xF8, 0x16, 0x00 }; + const unsigned char INSTRUMENT_STEELDRM[24] PROGMEM = { 0x00, 0x2C, 0xAB, 0x68, 0x24, 0x00, 0x00, 0x01, 0x00, 0xDF, 0x35, 0x00, 0x00, 0x05, 0x9D, 0x67, 0x35, 0x00, 0x01, 0x01, 0x00, 0xDF, 0x05, 0x00 }; + const unsigned char INSTRUMENT_WOODBLOK[24] PROGMEM = { 0x00, 0x15, 0x11, 0xFA, 0xFC, 0x04, 0x0A, 0x12, 0x80, 0xFA, 0xEC, 0x00, 0x00, 0x18, 0x9D, 0xFA, 0xFC, 0x00, 0x01, 0x12, 0x00, 0xF8, 0xE5, 0x00 }; + const unsigned char INSTRUMENT_TAIKO[24] PROGMEM = { 0x00, 0x10, 0x86, 0xA8, 0x07, 0x00, 0x06, 0x00, 0x03, 0xFA, 0x03, 0x00, 0x00, 0x01, 0x5C, 0xA8, 0x07, 0x00, 0x01, 0x00, 0x03, 0xF6, 0x83, 0x00 }; + const unsigned char INSTRUMENT_MELOTOM[24] PROGMEM = { 0x00, 0x11, 0x8F, 0xF8, 0x58, 0x04, 0x0E, 0x10, 0x00, 0xF3, 0xE5, 0x00, 0x00, 0x10, 0x92, 0xF6, 0x54, 0x01, 0x01, 0x10, 0x00, 0xF4, 0xE4, 0x00 }; + const unsigned char INSTRUMENT_SYNDRUM[24] PROGMEM = { 0x00, 0x11, 0x86, 0xF8, 0x55, 0x04, 0x0E, 0x10, 0x00, 0xF4, 0xE5, 0x00, 0x00, 0x11, 0x9C, 0xF3, 0x55, 0x01, 0x01, 0x10, 0x00, 0xF4, 0xE5, 0x00 }; + const unsigned char INSTRUMENT_REVRSCYM[24] PROGMEM = { 0x00, 0x0F, 0x00, 0x1F, 0x00, 0x00, 0x0E, 0xC0, 0x00, 0x1F, 0xF0, 0x03, 0x00, 0x0F, 0x3F, 0x1F, 0x00, 0x00, 0x01, 0xC0, 0x3F, 0x1F, 0xF1, 0x03 }; + const unsigned char INSTRUMENT_FRETNOIS[24] PROGMEM = { 0x00, 0x06, 0x80, 0xF8, 0x24, 0x00, 0x0E, 0x03, 0x88, 0x56, 0x84, 0x07, 0x00, 0x03, 0x1E, 0xD8, 0x24, 0x00, 0x01, 0x04, 0x08, 0x66, 0x84, 0x07 }; + const unsigned char INSTRUMENT_BRTHNOIS[24] PROGMEM = { 0x00, 0x06, 0x00, 0xFF, 0x01, 0x00, 0x0E, 0x14, 0x00, 0x34, 0x04, 0x03, 0x00, 0x01, 0x3F, 0x00, 0xF1, 0x00, 0x01, 0x01, 0x3F, 0x00, 0xF1, 0x00 }; + const unsigned char INSTRUMENT_SEASHORE[24] PROGMEM = { 0x00, 0x26, 0x00, 0xFF, 0x01, 0x00, 0x0E, 0x04, 0x00, 0x12, 0x84, 0x01, 0x00, 0x01, 0x3F, 0x00, 0xF1, 0x00, 0x01, 0x01, 0x3F, 0x00, 0xF1, 0x00 }; + const unsigned char INSTRUMENT_BIRDS[24] PROGMEM = { 0x00, 0x48, 0x00, 0x68, 0xF8, 0x00, 0x05, 0x01, 0x3F, 0x00, 0xF1, 0x00, 0x00, 0x47, 0x00, 0x67, 0xF8, 0x00, 0x01, 0x4C, 0x00, 0x46, 0xF8, 0x00 }; + const unsigned char INSTRUMENT_TELEPHON[24] PROGMEM = { 0x00, 0x35, 0x1C, 0xB2, 0x61, 0x02, 0x0A, 0x14, 0x08, 0xF4, 0x15, 0x00, 0x00, 0x11, 0x20, 0xFE, 0x15, 0x07, 0x01, 0x87, 0xC0, 0xF4, 0x19, 0x00 }; + const unsigned char INSTRUMENT_HELICOPT[24] PROGMEM = { 0x00, 0xF0, 0x00, 0x2E, 0x11, 0x01, 0x08, 0xE2, 0xC0, 0x21, 0x16, 0x01, 0x00, 0xF0, 0x00, 0x2E, 0x11, 0x07, 0x01, 0xE2, 0xC0, 0x21, 0x16, 0x01 }; + const unsigned char INSTRUMENT_APPLAUSE[24] PROGMEM = { 0x00, 0x26, 0x00, 0xFF, 0x01, 0x00, 0x0E, 0xE4, 0x00, 0x12, 0x16, 0x07, 0x00, 0x01, 0x3F, 0x00, 0xF1, 0x00, 0x01, 0x01, 0x3F, 0x00, 0xF1, 0x00 }; + const unsigned char INSTRUMENT_GUNSHOT[24] PROGMEM = { 0x00, 0x00, 0x00, 0xF2, 0x59, 0x00, 0x0E, 0x01, 0x00, 0xF7, 0x00, 0x00, 0x00, 0x01, 0x00, 0xF3, 0xF0, 0x00, 0x00, 0x01, 0x00, 0xF6, 0xC9, 0x06 }; + + + // Instrument pointer array to access instruments by MIDI program. + const unsigned char *midiInstruments[] = { + INSTRUMENT_PIANO1, INSTRUMENT_PIANO2, INSTRUMENT_PIANO3, INSTRUMENT_HONKTONK, INSTRUMENT_EP1, INSTRUMENT_EP2, + INSTRUMENT_HARPSIC, INSTRUMENT_CLAVIC, INSTRUMENT_CELESTA, INSTRUMENT_GLOCK, INSTRUMENT_MUSICBOX, INSTRUMENT_VIBES, + INSTRUMENT_MARIMBA, INSTRUMENT_XYLO, INSTRUMENT_TUBEBELL, INSTRUMENT_SANTUR, INSTRUMENT_ORGAN1, INSTRUMENT_ORGAN2, + INSTRUMENT_ORGAN3, INSTRUMENT_PIPEORG, INSTRUMENT_REEDORG, INSTRUMENT_ACORDIAN, INSTRUMENT_HARMONIC, INSTRUMENT_BANDNEON, + INSTRUMENT_NYLONGT, INSTRUMENT_STEELGT, INSTRUMENT_JAZZGT, INSTRUMENT_CLEANGT, INSTRUMENT_MUTEGT, INSTRUMENT_OVERDGT, + INSTRUMENT_DISTGT, INSTRUMENT_GTHARMS, INSTRUMENT_ACOUBASS, INSTRUMENT_FINGBASS, INSTRUMENT_PICKBASS, INSTRUMENT_FRETLESS, + INSTRUMENT_SLAPBAS1, INSTRUMENT_SLAPBAS2, INSTRUMENT_SYNBASS1, INSTRUMENT_SYNBASS2, INSTRUMENT_VIOLIN, INSTRUMENT_VIOLA, + INSTRUMENT_CELLO, INSTRUMENT_CONTRAB, INSTRUMENT_TREMSTR, INSTRUMENT_PIZZ, INSTRUMENT_HARP, INSTRUMENT_TIMPANI, + INSTRUMENT_STRINGS, INSTRUMENT_SLOWSTR, INSTRUMENT_SYNSTR1, INSTRUMENT_SYNSTR2, INSTRUMENT_CHOIR, INSTRUMENT_OOHS, + INSTRUMENT_SYNVOX, INSTRUMENT_ORCHIT, INSTRUMENT_TRUMPET, INSTRUMENT_TROMBONE, INSTRUMENT_TUBA, INSTRUMENT_MUTETRP, + INSTRUMENT_FRHORN, INSTRUMENT_BRASS1, INSTRUMENT_SYNBRAS1, INSTRUMENT_SYNBRAS2, INSTRUMENT_SOPSAX, INSTRUMENT_ALTOSAX, + INSTRUMENT_TENSAX, INSTRUMENT_BARISAX, INSTRUMENT_OBOE, INSTRUMENT_ENGLHORN, INSTRUMENT_BASSOON, INSTRUMENT_CLARINET, + INSTRUMENT_PICCOLO, INSTRUMENT_FLUTE1, INSTRUMENT_RECORDER, INSTRUMENT_PANFLUTE, INSTRUMENT_BOTTLEB, INSTRUMENT_SHAKU, + INSTRUMENT_WHISTLE, INSTRUMENT_OCARINA, INSTRUMENT_SQUARWAV, INSTRUMENT_SAWWAV, INSTRUMENT_SYNCALLI, INSTRUMENT_CHIFLEAD, + INSTRUMENT_CHARANG, INSTRUMENT_SOLOVOX, INSTRUMENT_FIFTHSAW, INSTRUMENT_BASSLEAD, INSTRUMENT_FANTASIA, INSTRUMENT_WARMPAD, + INSTRUMENT_POLYSYN, INSTRUMENT_SPACEVOX, INSTRUMENT_BOWEDGLS, INSTRUMENT_METALPAD, INSTRUMENT_HALOPAD, INSTRUMENT_SWEEPPAD, + INSTRUMENT_ICERAIN, INSTRUMENT_SOUNDTRK, INSTRUMENT_CRYSTAL, INSTRUMENT_ATMOSPH, INSTRUMENT_BRIGHT, INSTRUMENT_GOBLIN, + INSTRUMENT_ECHODROP, INSTRUMENT_STARTHEM, INSTRUMENT_SITAR, INSTRUMENT_BANJO, INSTRUMENT_SHAMISEN, INSTRUMENT_KOTO, + INSTRUMENT_KALIMBA, INSTRUMENT_BAGPIPE, INSTRUMENT_FIDDLE, INSTRUMENT_SHANNAI, INSTRUMENT_TINKLBEL, INSTRUMENT_AGOGO, + INSTRUMENT_STEELDRM, INSTRUMENT_WOODBLOK, INSTRUMENT_TAIKO, INSTRUMENT_MELOTOM, INSTRUMENT_SYNDRUM, INSTRUMENT_REVRSCYM, + INSTRUMENT_FRETNOIS, INSTRUMENT_BRTHNOIS, INSTRUMENT_SEASHORE, INSTRUMENT_BIRDS, INSTRUMENT_TELEPHON, INSTRUMENT_HELICOPT, + INSTRUMENT_APPLAUSE, INSTRUMENT_GUNSHOT + }; + +#endif diff --git a/src/midi_instruments_win31.h b/src/midi_instruments_win31.h deleted file mode 100644 index c776fbf..0000000 --- a/src/midi_instruments_win31.h +++ /dev/null @@ -1,190 +0,0 @@ -/** - * This file contains MIDI instrument defenitions for use with the OPL2 Audio Board library. These were converted from - * the Windows 3.1 MIDI driver for Sound Blaster 16. This file contains the melodic instrments only. - * - * Instrument definition is based on Adlib instrument bank format. - * 0 - Rhythm mode drum channel - * Drum channels are predefined by the YM3812 and cannot be redefined. Regular instruments have their channel set - * to 0x00 and can be assigned to any channel by the setInstrument function. Rhythm mode instruments can only be - * used when rhythm mode is active (see OPL2.setPercussion). - * - * 1 - Channel c, operator 1, register 0x20 - * Tremolo(1) | Vibrato(1) | Sustain(1) | KSR(1) | Frequency multiplier (4) - * - * 2 - Channel c, operator 1, register 0x40 - * Key scale level(2) | Output level(6) - * - * 3 - Channel c, operator 1, register 0x60 - * Attack(4) | Decay(4) - * - * 4 - Channel c, operator 1, register 0x80 - * Sustain(4) | Release(4) - * - * 5 - Channel c, operator 1, register 0xE0 - * Undefined(5) | Waveform(3) - * - * 6 - Channel c, register 0xC0 - * Undefined(4) | Modulation feedback factor(3) | Synth type(1) - * - * 7 - Channel c, operator 2, register 0x20 - * 8 - Channel c, operator 2, register 0x40 - * 9 - Channel c, operator 2, register 0x60 - * 10 - Channel c, operator 2, register 0x80 - * 11 - Channel c, operator 2, register 0xE0 - */ - -const unsigned char INSTRUMENT_PIANO1[12] PROGMEM = { 0x00, 0x01, 0x8F, 0xF2, 0xF4, 0x38, 0x00, 0x01, 0x0D, 0xF2, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_PIANO2[12] PROGMEM = { 0x00, 0x01, 0x4B, 0xF2, 0xF4, 0x38, 0x00, 0x01, 0x07, 0xF2, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_PIANO3[12] PROGMEM = { 0x00, 0x01, 0x49, 0xF2, 0xF4, 0x38, 0x00, 0x01, 0x07, 0xF2, 0xF6, 0x00 }; -const unsigned char INSTRUMENT_HONKTONK[12] PROGMEM = { 0x00, 0x81, 0x12, 0xF2, 0xF7, 0x00, 0x00, 0x41, 0x07, 0xF2, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_EP1[12] PROGMEM = { 0x00, 0x01, 0x57, 0xF1, 0xF7, 0x00, 0x00, 0x01, 0x07, 0xF2, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_EP2[12] PROGMEM = { 0x00, 0x01, 0x93, 0xF1, 0xF7, 0x00, 0x00, 0x01, 0x07, 0xF2, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_HARPSIC[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CLAVIC[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CELESTA[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_GLOCK[12] PROGMEM = { 0x00, 0x07, 0x97, 0xF3, 0xF2, 0x32, 0x00, 0x11, 0x87, 0xF2, 0xF1, 0x00 }; -const unsigned char INSTRUMENT_MUSICBOX[12] PROGMEM = { 0x00, 0x17, 0x21, 0x54, 0xF4, 0x32, 0x00, 0x01, 0x07, 0xF4, 0xF4, 0x00 }; -const unsigned char INSTRUMENT_VIBES[12] PROGMEM = { 0x00, 0x98, 0x62, 0xF3, 0xF6, 0x30, 0x00, 0x81, 0x07, 0xF2, 0xF6, 0x00 }; -const unsigned char INSTRUMENT_MARIMBA[12] PROGMEM = { 0x00, 0x18, 0x23, 0xF6, 0xF6, 0x00, 0x00, 0x01, 0x07, 0xE7, 0xF7, 0x00 }; -const unsigned char INSTRUMENT_XYLO[12] PROGMEM = { 0x00, 0x15, 0x91, 0xF6, 0xF6, 0x00, 0x00, 0x01, 0x07, 0xF6, 0xF6, 0x00 }; -const unsigned char INSTRUMENT_TUBEBELL[12] PROGMEM = { 0x00, 0x45, 0x59, 0xD3, 0xF3, 0x00, 0x00, 0x81, 0x87, 0xA3, 0xF3, 0x00 }; -const unsigned char INSTRUMENT_SANTUR[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_ORGAN1[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_ORGAN2[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_ORGAN3[12] PROGMEM = { 0x00, 0x70, 0x44, 0xAA, 0x18, 0x34, 0x00, 0xB1, 0x07, 0x8A, 0x08, 0x00 }; -const unsigned char INSTRUMENT_PIPEORG[12] PROGMEM = { 0x00, 0x23, 0x93, 0x97, 0x23, 0x34, 0x01, 0xB1, 0x07, 0x55, 0x14, 0x00 }; -const unsigned char INSTRUMENT_REEDORG[12] PROGMEM = { 0x00, 0x61, 0x13, 0x97, 0x04, 0x30, 0x01, 0xB1, 0x87, 0x55, 0x04, 0x00 }; -const unsigned char INSTRUMENT_ACORDIAN[12] PROGMEM = { 0x00, 0x24, 0x48, 0x98, 0x2A, 0x30, 0x01, 0xB1, 0x07, 0x46, 0x1A, 0x00 }; -const unsigned char INSTRUMENT_HARMONIC[12] PROGMEM = { 0x00, 0x61, 0x13, 0x91, 0x06, 0x00, 0x01, 0x21, 0x07, 0x61, 0x07, 0x00 }; -const unsigned char INSTRUMENT_BANDNEON[12] PROGMEM = { 0x00, 0x21, 0x13, 0x71, 0x06, 0x00, 0x00, 0xA1, 0x90, 0x61, 0x07, 0x00 }; -const unsigned char INSTRUMENT_NYLONGT[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_STEELGT[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_JAZZGT[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CLEANGT[12] PROGMEM = { 0x00, 0x03, 0x87, 0xF6, 0x22, 0x36, 0x01, 0x21, 0x87, 0xF3, 0xF8, 0x00 }; -const unsigned char INSTRUMENT_MUTEGT[12] PROGMEM = { 0x00, 0x03, 0x47, 0xF9, 0x54, 0x30, 0x00, 0x21, 0x07, 0xF6, 0x3A, 0x00 }; -const unsigned char INSTRUMENT_OVERDGT[12] PROGMEM = { 0x00, 0x23, 0x4A, 0x91, 0x41, 0x38, 0x01, 0x21, 0x0C, 0x84, 0x19, 0x00 }; -const unsigned char INSTRUMENT_DISTGT[12] PROGMEM = { 0x00, 0x23, 0x4A, 0x95, 0x19, 0x32, 0x01, 0x21, 0x07, 0x94, 0x19, 0x00 }; -const unsigned char INSTRUMENT_GTHARMS[12] PROGMEM = { 0x00, 0x09, 0xA1, 0x20, 0x4F, 0x00, 0x00, 0x84, 0x87, 0xD1, 0xF8, 0x00 }; -const unsigned char INSTRUMENT_ACOUBASS[12] PROGMEM = { 0x00, 0x21, 0x1E, 0x94, 0x06, 0x00, 0x00, 0xA2, 0x07, 0xC3, 0xA6, 0x00 }; -const unsigned char INSTRUMENT_FINGBASS[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_PICKBASS[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_FRETLESS[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SLAPBAS1[12] PROGMEM = { 0x00, 0x01, 0x8B, 0xA1, 0x9A, 0x38, 0x00, 0x21, 0x47, 0xF2, 0xDF, 0x00 }; -const unsigned char INSTRUMENT_SLAPBAS2[12] PROGMEM = { 0x00, 0x21, 0x8B, 0xA2, 0x16, 0x38, 0x00, 0x21, 0x0F, 0xA1, 0xDF, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS1[12] PROGMEM = { 0x00, 0x31, 0x8B, 0xF4, 0xE8, 0x3A, 0x00, 0x31, 0x07, 0xF1, 0x78, 0x00 }; -const unsigned char INSTRUMENT_SYNBASS2[12] PROGMEM = { 0x00, 0x31, 0x12, 0xF1, 0x28, 0x30, 0x00, 0x31, 0x07, 0xF1, 0x18, 0x00 }; -const unsigned char INSTRUMENT_VIOLIN[12] PROGMEM = { 0x00, 0x31, 0x15, 0xDD, 0x13, 0x00, 0x01, 0x21, 0x07, 0x56, 0x26, 0x00 }; -const unsigned char INSTRUMENT_VIOLA[12] PROGMEM = { 0x00, 0x31, 0x16, 0xDD, 0x13, 0x00, 0x01, 0x21, 0x07, 0x66, 0x06, 0x00 }; -const unsigned char INSTRUMENT_CELLO[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CONTRAB[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_TREMSTR[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_PIZZ[12] PROGMEM = { 0x00, 0x02, 0x1A, 0xF5, 0x75, 0x30, 0x01, 0x01, 0x87, 0x85, 0x35, 0x00 }; -const unsigned char INSTRUMENT_HARP[12] PROGMEM = { 0x00, 0x02, 0x1D, 0xF5, 0x75, 0x30, 0x01, 0x01, 0x87, 0xF3, 0xF4, 0x00 }; -const unsigned char INSTRUMENT_TIMPANI[12] PROGMEM = { 0x00, 0x10, 0x41, 0xF5, 0x05, 0x32, 0x01, 0x11, 0x07, 0xF2, 0xC3, 0x00 }; -const unsigned char INSTRUMENT_STRINGS[12] PROGMEM = { 0x00, 0x21, 0x9B, 0xB1, 0x25, 0x3C, 0x01, 0xA2, 0x08, 0x72, 0x08, 0x00 }; -const unsigned char INSTRUMENT_SLOWSTR[12] PROGMEM = { 0x00, 0xA1, 0x98, 0x7F, 0x03, 0x00, 0x01, 0x21, 0x07, 0x3F, 0x07, 0x01 }; -const unsigned char INSTRUMENT_SYNSTR1[12] PROGMEM = { 0x00, 0xA1, 0x93, 0xC1, 0x12, 0x00, 0x00, 0x61, 0x07, 0x4F, 0x05, 0x00 }; -const unsigned char INSTRUMENT_SYNSTR2[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CHOIR[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_OOHS[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SYNVOX[12] PROGMEM = { 0x00, 0x71, 0x57, 0x54, 0x05, 0x3C, 0x00, 0x72, 0x07, 0x7A, 0x05, 0x00 }; -const unsigned char INSTRUMENT_ORCHIT[12] PROGMEM = { 0x00, 0x90, 0x00, 0x54, 0x63, 0x38, 0x00, 0x41, 0x07, 0xA5, 0x45, 0x00 }; -const unsigned char INSTRUMENT_TRUMPET[12] PROGMEM = { 0x00, 0x21, 0x92, 0x85, 0x17, 0x3C, 0x00, 0x21, 0x08, 0x8F, 0x09, 0x00 }; -const unsigned char INSTRUMENT_TROMBONE[12] PROGMEM = { 0x00, 0x21, 0x94, 0x75, 0x17, 0x32, 0x00, 0x21, 0x0C, 0x8F, 0x09, 0x00 }; -const unsigned char INSTRUMENT_TUBA[12] PROGMEM = { 0x00, 0x21, 0x94, 0x76, 0x15, 0x00, 0x00, 0x61, 0x07, 0x82, 0x37, 0x00 }; -const unsigned char INSTRUMENT_MUTETRP[12] PROGMEM = { 0x00, 0x31, 0x43, 0x9E, 0x17, 0x00, 0x01, 0x21, 0x07, 0x62, 0x2C, 0x01 }; -const unsigned char INSTRUMENT_FRHORN[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_BRASS1[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SYNBRAS1[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SYNBRAS2[12] PROGMEM = { 0x00, 0x21, 0x4D, 0x54, 0x3C, 0x38, 0x00, 0x21, 0x07, 0xA6, 0x1C, 0x00 }; -const unsigned char INSTRUMENT_SOPSAX[12] PROGMEM = { 0x00, 0x31, 0x8F, 0x93, 0x02, 0x38, 0x01, 0x61, 0x07, 0x72, 0x0B, 0x00 }; -const unsigned char INSTRUMENT_ALTOSAX[12] PROGMEM = { 0x00, 0x31, 0x8E, 0x93, 0x03, 0x38, 0x01, 0x61, 0x07, 0x72, 0x09, 0x00 }; -const unsigned char INSTRUMENT_TENSAX[12] PROGMEM = { 0x00, 0x31, 0x91, 0x93, 0x03, 0x30, 0x01, 0x61, 0x07, 0x82, 0x09, 0x00 }; -const unsigned char INSTRUMENT_BARISAX[12] PROGMEM = { 0x00, 0x31, 0x8E, 0x93, 0x0F, 0x00, 0x01, 0x61, 0x07, 0x72, 0x0F, 0x00 }; -const unsigned char INSTRUMENT_OBOE[12] PROGMEM = { 0x00, 0x21, 0x4B, 0xAA, 0x16, 0x00, 0x01, 0x21, 0x07, 0x8F, 0x0A, 0x00 }; -const unsigned char INSTRUMENT_ENGLHORN[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_BASSOON[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CLARINET[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_PICCOLO[12] PROGMEM = { 0x00, 0xE1, 0x1F, 0x85, 0x5F, 0x30, 0x00, 0xE1, 0x07, 0x65, 0x1A, 0x00 }; -const unsigned char INSTRUMENT_FLUTE1[12] PROGMEM = { 0x00, 0xE1, 0x46, 0x88, 0x5F, 0x30, 0x00, 0xE1, 0x07, 0x65, 0x1A, 0x00 }; -const unsigned char INSTRUMENT_RECORDER[12] PROGMEM = { 0x00, 0xA1, 0x9C, 0x75, 0x1F, 0x32, 0x00, 0x21, 0x07, 0x75, 0x0A, 0x00 }; -const unsigned char INSTRUMENT_PANFLUTE[12] PROGMEM = { 0x00, 0x31, 0x8B, 0x84, 0x58, 0x30, 0x00, 0x21, 0x07, 0x65, 0x1A, 0x00 }; -const unsigned char INSTRUMENT_BOTTLEB[12] PROGMEM = { 0x00, 0xE1, 0x4C, 0x66, 0x56, 0x00, 0x00, 0xA1, 0x07, 0x65, 0x26, 0x00 }; -const unsigned char INSTRUMENT_SHAKU[12] PROGMEM = { 0x00, 0x62, 0xCB, 0x76, 0x46, 0x00, 0x00, 0xA1, 0x07, 0x55, 0x36, 0x00 }; -const unsigned char INSTRUMENT_WHISTLE[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_OCARINA[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SQUARWAV[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SAWWAV[12] PROGMEM = { 0x00, 0x21, 0x0E, 0xFF, 0x0F, 0x30, 0x01, 0x21, 0x07, 0xFF, 0x0F, 0x01 }; -const unsigned char INSTRUMENT_SYNCALLI[12] PROGMEM = { 0x00, 0x22, 0x46, 0x86, 0x55, 0x30, 0x00, 0x21, 0x87, 0x64, 0x18, 0x00 }; -const unsigned char INSTRUMENT_CHIFLEAD[12] PROGMEM = { 0x00, 0x21, 0x45, 0x66, 0x12, 0x30, 0x00, 0xA1, 0x07, 0x96, 0x0A, 0x00 }; -const unsigned char INSTRUMENT_CHARANG[12] PROGMEM = { 0x00, 0x21, 0x8B, 0x92, 0x2A, 0x34, 0x01, 0x22, 0x07, 0x91, 0x2A, 0x00 }; -const unsigned char INSTRUMENT_SOLOVOX[12] PROGMEM = { 0x00, 0xA2, 0x9E, 0xDF, 0x05, 0x00, 0x00, 0x61, 0x47, 0x6F, 0x07, 0x00 }; -const unsigned char INSTRUMENT_FIFTHSAW[12] PROGMEM = { 0x00, 0x20, 0x1A, 0xEF, 0x01, 0x00, 0x00, 0x60, 0x07, 0x8F, 0x06, 0x02 }; -const unsigned char INSTRUMENT_BASSLEAD[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_FANTASIA[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_WARMPAD[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_POLYSYN[12] PROGMEM = { 0x00, 0x61, 0x17, 0x91, 0x34, 0x3C, 0x00, 0x61, 0x07, 0x55, 0x16, 0x00 }; -const unsigned char INSTRUMENT_SPACEVOX[12] PROGMEM = { 0x00, 0x71, 0x5D, 0x54, 0x01, 0x30, 0x00, 0x72, 0x07, 0x6A, 0x03, 0x00 }; -const unsigned char INSTRUMENT_BOWEDGLS[12] PROGMEM = { 0x00, 0x21, 0x97, 0x21, 0x43, 0x38, 0x00, 0xA2, 0x07, 0x42, 0x35, 0x00 }; -const unsigned char INSTRUMENT_METALPAD[12] PROGMEM = { 0x00, 0xA1, 0x1C, 0xA1, 0x77, 0x30, 0x01, 0x21, 0x07, 0x31, 0x47, 0x01 }; -const unsigned char INSTRUMENT_HALOPAD[12] PROGMEM = { 0x00, 0x21, 0x89, 0x11, 0x33, 0x00, 0x00, 0x61, 0x0A, 0x42, 0x25, 0x00 }; -const unsigned char INSTRUMENT_SWEEPPAD[12] PROGMEM = { 0x00, 0xA1, 0x15, 0x11, 0x47, 0x00, 0x01, 0x21, 0x07, 0xCF, 0x07, 0x00 }; -const unsigned char INSTRUMENT_ICERAIN[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SOUNDTRK[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_CRYSTAL[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_ATMOSPH[12] PROGMEM = { 0x00, 0x22, 0x92, 0xB1, 0x81, 0x3C, 0x00, 0x61, 0x8A, 0xF2, 0x26, 0x00 }; -const unsigned char INSTRUMENT_BRIGHT[12] PROGMEM = { 0x00, 0x41, 0x4D, 0xF1, 0x51, 0x30, 0x01, 0x42, 0x07, 0xF2, 0xF5, 0x00 }; -const unsigned char INSTRUMENT_GOBLIN[12] PROGMEM = { 0x00, 0x61, 0x94, 0x11, 0x51, 0x36, 0x01, 0xA3, 0x87, 0x11, 0x13, 0x00 }; -const unsigned char INSTRUMENT_ECHODROP[12] PROGMEM = { 0x00, 0x61, 0x8C, 0x11, 0x31, 0x3A, 0x00, 0xA1, 0x87, 0x1D, 0x03, 0x00 }; -const unsigned char INSTRUMENT_STARTHEM[12] PROGMEM = { 0x00, 0xA4, 0x4C, 0xF3, 0x73, 0x00, 0x01, 0x61, 0x07, 0x81, 0x23, 0x00 }; -const unsigned char INSTRUMENT_SITAR[12] PROGMEM = { 0x00, 0x02, 0x85, 0xD2, 0x53, 0x00, 0x00, 0x07, 0x0A, 0xF2, 0xF6, 0x01 }; -const unsigned char INSTRUMENT_BANJO[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_SHAMISEN[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_KOTO[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_KALIMBA[12] PROGMEM = { 0x00, 0x04, 0x4F, 0xFA, 0x56, 0x3C, 0x00, 0x01, 0x07, 0xC2, 0x05, 0x00 }; -const unsigned char INSTRUMENT_BAGPIPE[12] PROGMEM = { 0x00, 0x21, 0x49, 0x7C, 0x20, 0x36, 0x00, 0x22, 0x07, 0x6F, 0x0C, 0x01 }; -const unsigned char INSTRUMENT_FIDDLE[12] PROGMEM = { 0x00, 0x31, 0x85, 0xDD, 0x33, 0x3A, 0x01, 0x21, 0x07, 0x56, 0x16, 0x00 }; -const unsigned char INSTRUMENT_SHANNAI[12] PROGMEM = { 0x00, 0x20, 0x04, 0xDA, 0x05, 0x30, 0x02, 0x21, 0x88, 0x8F, 0x0B, 0x00 }; -const unsigned char INSTRUMENT_TINKLBEL[12] PROGMEM = { 0x00, 0x05, 0x6A, 0xF1, 0xE5, 0x00, 0x00, 0x03, 0x87, 0xC3, 0xE5, 0x00 }; -const unsigned char INSTRUMENT_AGOGO[12] PROGMEM = { 0x00, 0x07, 0x15, 0xEC, 0x26, 0x00, 0x00, 0x02, 0x07, 0xF8, 0x16, 0x00 }; -const unsigned char INSTRUMENT_STEELDRM[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_WOODBLOK[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_TAIKO[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_MELOTOM[12] PROGMEM = { 0x00, 0x11, 0x41, 0xF8, 0x47, 0x34, 0x02, 0x10, 0x0A, 0xF3, 0x03, 0x00 }; -const unsigned char INSTRUMENT_SYNDRUM[12] PROGMEM = { 0x00, 0x01, 0x8E, 0xF1, 0x06, 0x3E, 0x02, 0x10, 0x07, 0xF3, 0x02, 0x00 }; -const unsigned char INSTRUMENT_REVRSCYM[12] PROGMEM = { 0x00, 0x0E, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0xC0, 0x07, 0x1F, 0xFF, 0x03 }; -const unsigned char INSTRUMENT_FRETNOIS[12] PROGMEM = { 0x00, 0x06, 0x80, 0xF8, 0x24, 0x38, 0x00, 0x03, 0x8F, 0x56, 0x84, 0x02 }; -const unsigned char INSTRUMENT_BRTHNOIS[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xD0, 0x0C, 0x34, 0x04, 0x03 }; -const unsigned char INSTRUMENT_SEASHORE[12] PROGMEM = { 0x00, 0x0E, 0x00, 0xF6, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x1F, 0x02, 0x03 }; -const unsigned char INSTRUMENT_BIRDS[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_TELEPHON[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_HELICOPT[12] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const unsigned char INSTRUMENT_APPLAUSE[12] PROGMEM = { 0x00, 0x26, 0x00, 0xFF, 0x01, 0x3E, 0x00, 0xE4, 0x07, 0x12, 0x16, 0x01 }; -const unsigned char INSTRUMENT_GUNSHOT[12] PROGMEM = { 0x00, 0x00, 0x00, 0xF3, 0xF0, 0x3E, 0x00, 0x00, 0x07, 0xF6, 0xC9, 0x02 }; - - -// Instrument pointer array to access instruments by MIDI program. -const unsigned char *midiInstruments[] = { - INSTRUMENT_PIANO1, INSTRUMENT_PIANO2, INSTRUMENT_PIANO3, INSTRUMENT_HONKTONK, INSTRUMENT_EP1, INSTRUMENT_EP2, - INSTRUMENT_HARPSIC, INSTRUMENT_CLAVIC, INSTRUMENT_CELESTA, INSTRUMENT_GLOCK, INSTRUMENT_MUSICBOX, INSTRUMENT_VIBES, - INSTRUMENT_MARIMBA, INSTRUMENT_XYLO, INSTRUMENT_TUBEBELL, INSTRUMENT_SANTUR, INSTRUMENT_ORGAN1, INSTRUMENT_ORGAN2, - INSTRUMENT_ORGAN3, INSTRUMENT_PIPEORG, INSTRUMENT_REEDORG, INSTRUMENT_ACORDIAN, INSTRUMENT_HARMONIC, INSTRUMENT_BANDNEON, - INSTRUMENT_NYLONGT, INSTRUMENT_STEELGT, INSTRUMENT_JAZZGT, INSTRUMENT_CLEANGT, INSTRUMENT_MUTEGT, INSTRUMENT_OVERDGT, - INSTRUMENT_DISTGT, INSTRUMENT_GTHARMS, INSTRUMENT_ACOUBASS, INSTRUMENT_FINGBASS, INSTRUMENT_PICKBASS, INSTRUMENT_FRETLESS, - INSTRUMENT_SLAPBAS1, INSTRUMENT_SLAPBAS2, INSTRUMENT_SYNBASS1, INSTRUMENT_SYNBASS2, INSTRUMENT_VIOLIN, INSTRUMENT_VIOLA, - INSTRUMENT_CELLO, INSTRUMENT_CONTRAB, INSTRUMENT_TREMSTR, INSTRUMENT_PIZZ, INSTRUMENT_HARP, INSTRUMENT_TIMPANI, - INSTRUMENT_STRINGS, INSTRUMENT_SLOWSTR, INSTRUMENT_SYNSTR1, INSTRUMENT_SYNSTR2, INSTRUMENT_CHOIR, INSTRUMENT_OOHS, - INSTRUMENT_SYNVOX, INSTRUMENT_ORCHIT, INSTRUMENT_TRUMPET, INSTRUMENT_TROMBONE, INSTRUMENT_TUBA, INSTRUMENT_MUTETRP, - INSTRUMENT_FRHORN, INSTRUMENT_BRASS1, INSTRUMENT_SYNBRAS1, INSTRUMENT_SYNBRAS2, INSTRUMENT_SOPSAX, INSTRUMENT_ALTOSAX, - INSTRUMENT_TENSAX, INSTRUMENT_BARISAX, INSTRUMENT_OBOE, INSTRUMENT_ENGLHORN, INSTRUMENT_BASSOON, INSTRUMENT_CLARINET, - INSTRUMENT_PICCOLO, INSTRUMENT_FLUTE1, INSTRUMENT_RECORDER, INSTRUMENT_PANFLUTE, INSTRUMENT_BOTTLEB, INSTRUMENT_SHAKU, - INSTRUMENT_WHISTLE, INSTRUMENT_OCARINA, INSTRUMENT_SQUARWAV, INSTRUMENT_SAWWAV, INSTRUMENT_SYNCALLI, INSTRUMENT_CHIFLEAD, - INSTRUMENT_CHARANG, INSTRUMENT_SOLOVOX, INSTRUMENT_FIFTHSAW, INSTRUMENT_BASSLEAD, INSTRUMENT_FANTASIA, INSTRUMENT_WARMPAD, - INSTRUMENT_POLYSYN, INSTRUMENT_SPACEVOX, INSTRUMENT_BOWEDGLS, INSTRUMENT_METALPAD, INSTRUMENT_HALOPAD, INSTRUMENT_SWEEPPAD, - INSTRUMENT_ICERAIN, INSTRUMENT_SOUNDTRK, INSTRUMENT_CRYSTAL, INSTRUMENT_ATMOSPH, INSTRUMENT_BRIGHT, INSTRUMENT_GOBLIN, - INSTRUMENT_ECHODROP, INSTRUMENT_STARTHEM, INSTRUMENT_SITAR, INSTRUMENT_BANJO, INSTRUMENT_SHAMISEN, INSTRUMENT_KOTO, - INSTRUMENT_KALIMBA, INSTRUMENT_BAGPIPE, INSTRUMENT_FIDDLE, INSTRUMENT_SHANNAI, INSTRUMENT_TINKLBEL, INSTRUMENT_AGOGO, - INSTRUMENT_STEELDRM, INSTRUMENT_WOODBLOK, INSTRUMENT_TAIKO, INSTRUMENT_MELOTOM, INSTRUMENT_SYNDRUM, INSTRUMENT_REVRSCYM, - INSTRUMENT_FRETNOIS, INSTRUMENT_BRTHNOIS, INSTRUMENT_SEASHORE, INSTRUMENT_BIRDS, INSTRUMENT_TELEPHON, INSTRUMENT_HELICOPT, - INSTRUMENT_APPLAUSE, INSTRUMENT_GUNSHOT -}; diff --git a/test/OPL2_Functions/Test_OPL2_Functions.cpp b/test/OPL2_Functions/Test_OPL2_Functions.cpp new file mode 100644 index 0000000..a879782 --- /dev/null +++ b/test/OPL2_Functions/Test_OPL2_Functions.cpp @@ -0,0 +1,372 @@ +#include +#include +#include + +OPL2 opl2; + + +/** + * Test changing wave form select enable bit. + */ +void test_register0x01() { + TEST_ASSERT_FALSE(opl2.getWaveFormSelect()); + + opl2.setWaveFormSelect(true); + TEST_ASSERT_TRUE(opl2.getWaveFormSelect()); + TEST_ASSERT_EQUAL_INT8(0x20, opl2.getChipRegister(0x01)); + + opl2.setWaveFormSelect(false); + TEST_ASSERT_FALSE(opl2.getWaveFormSelect()); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0x01)); +} + + +/** + * Test operator bits and frequency multiplier for each channel operator. + */ +void test_register0x20() { + for (int ch = 0; ch < 9; ch ++) { + for (int op = 0; op < 2; op ++) { + TEST_ASSERT_FALSE(opl2.getTremolo(ch, op)); + TEST_ASSERT_FALSE(opl2.getVibrato(ch, op)); + TEST_ASSERT_FALSE(opl2.getMaintainSustain(ch, op)); + TEST_ASSERT_FALSE(opl2.getEnvelopeScaling(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getMultiplier(ch, op)); + + opl2.setTremolo(ch, op, true); + TEST_ASSERT_TRUE(opl2.getTremolo(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x80, opl2.getOperatorRegister(0x20, ch, op)); + opl2.setTremolo(ch, op, false); + TEST_ASSERT_FALSE(opl2.getTremolo(ch, op)); + + opl2.setVibrato(ch, op, true); + TEST_ASSERT_TRUE(opl2.getVibrato(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x40, opl2.getOperatorRegister(0x20, ch, op)); + opl2.setVibrato(ch, op, false); + TEST_ASSERT_FALSE(opl2.getVibrato(ch, op)); + + opl2.setMaintainSustain(ch, op, true); + TEST_ASSERT_TRUE(opl2.getMaintainSustain(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x20, opl2.getOperatorRegister(0x20, ch, op)); + opl2.setMaintainSustain(ch, op, false); + TEST_ASSERT_FALSE(opl2.getMaintainSustain(ch, op)); + + opl2.setEnvelopeScaling(ch, op, true); + TEST_ASSERT_TRUE(opl2.getEnvelopeScaling(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x10, opl2.getOperatorRegister(0x20, ch, op)); + opl2.setEnvelopeScaling(ch, op, false); + TEST_ASSERT_FALSE(opl2.getEnvelopeScaling(ch, op)); + + opl2.setMultiplier(ch, op, 0x05); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getMultiplier(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getOperatorRegister(0x20, ch, op)); + opl2.setMultiplier(ch, op, 0x0A); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getMultiplier(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getOperatorRegister(0x20, ch, op)); + opl2.setMultiplier(ch, op, 0xFF); + TEST_ASSERT_EQUAL_INT8(0x0F, opl2.getMultiplier(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x0F, opl2.getOperatorRegister(0x20, ch, op)); + } + } +} + + +/** + * Test setting key scale level and output level on all channel operators. + */ +void test_register0x40() { + for (int ch = 0; ch < 9; ch ++) { + for (int op = 0; op < 2; op ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getScalingLevel(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getVolume(ch, op)); + + opl2.setScalingLevel(ch, op, 0x01); + opl2.setVolume(ch, op, 0x15); + + TEST_ASSERT_EQUAL_INT8(0x01, opl2.getScalingLevel(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x15, opl2.getVolume(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x55, opl2.getOperatorRegister(0x40, ch, op)); + + opl2.setScalingLevel(ch, op, 0x02); + opl2.setVolume(ch, op, 0x2A); + + TEST_ASSERT_EQUAL_INT8(0x02, opl2.getScalingLevel(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x2A, opl2.getVolume(ch, op)); + TEST_ASSERT_EQUAL_INT8(0xAA, opl2.getOperatorRegister(0x40, ch, op)); + } + } + + // Test that values over 3 are truncated on key scale level. + opl2.setOperatorRegister(0x40, 0, 0, 0x00); + opl2.setScalingLevel(0, 0, 0xFF); + TEST_ASSERT_EQUAL_INT8(0xC0, opl2.getOperatorRegister(0x40, 0, 0)); + + // Test that values over 63 are truncated on output level. + opl2.setOperatorRegister(0x40, 0, 0, 0x00); + opl2.setVolume(0, 0, 0xFF); + TEST_ASSERT_EQUAL_INT8(0x3F, opl2.getOperatorRegister(0x40, 0, 0)); +} + + +/** + * Test setting attack and decay on all channel operators. + */ +void test_register0x60() { + for (int ch = 0; ch < 9; ch ++) { + for (int op = 0; op < 2; op ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getAttack(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getDecay(ch, op)); + + opl2.setAttack(ch, op, 0x05); + opl2.setDecay(ch, op, 0x0A); + + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getAttack(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getDecay(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x5A, opl2.getOperatorRegister(0x60, ch, op)); + + opl2.setAttack(ch, op, 0x0A); + opl2.setDecay(ch, op, 0x05); + + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getAttack(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getDecay(ch, op)); + TEST_ASSERT_EQUAL_INT8(0xA5, opl2.getOperatorRegister(0x60, ch, op)); + } + } + + // Test that values over 15 are truncated on attack. + opl2.setOperatorRegister(0x60, 0, 0, 0x00); + opl2.setAttack(0, 0, 0xFA); + TEST_ASSERT_EQUAL_INT8(0xA0, opl2.getOperatorRegister(0x60, 0, 0)); + + // Test that values over 15 are truncated on decay. + opl2.setOperatorRegister(0x60, 0, 0, 0x00); + opl2.setDecay(0, 0, 0xFA); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getOperatorRegister(0x60, 0, 0)); +} + + +/** + * Test setting sustain and release on all channel operators. + */ +void test_register0x80() { + for (int ch = 0; ch < 9; ch ++) { + for (int op = 0; op < 2; op ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getSustain(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getRelease(ch, op)); + + opl2.setSustain(ch, op, 0x05); + opl2.setRelease(ch, op, 0x0A); + + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getSustain(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getRelease(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x5A, opl2.getOperatorRegister(0x80, ch, op)); + + opl2.setSustain(ch, op, 0x0A); + opl2.setRelease(ch, op, 0x05); + + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getSustain(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getRelease(ch, op)); + TEST_ASSERT_EQUAL_INT8(0xA5, opl2.getOperatorRegister(0x80, ch, op)); + } + } + + // Test that values over 15 are truncated on sustain. + opl2.setOperatorRegister(0x80, 0, 0, 0x00); + opl2.setSustain(0, 0, 0xF5); + TEST_ASSERT_EQUAL_INT8(0x50, opl2.getOperatorRegister(0x80, 0, 0)); + + // Test that values over 15 are truncated on release. + opl2.setOperatorRegister(0x80, 0, 0, 0x00); + opl2.setRelease(0, 0, 0xF5); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getOperatorRegister(0x80, 0, 0)); +} + + +/** + * Test setting the F-number on all channels. + */ +void test_register0xA0() { + for (int ch = 0; ch < 9; ch ++) { + TEST_ASSERT_EQUAL_INT16(0x00, opl2.getFNumber(ch)); + + opl2.setFNumber(ch, 0x155); + TEST_ASSERT_EQUAL_INT16(0x155, opl2.getFNumber(ch)); + TEST_ASSERT_EQUAL_INT8(0x55, opl2.getChannelRegister(0xA0, ch)); + TEST_ASSERT_EQUAL_INT8(0x01, opl2.getChannelRegister(0xB0, ch)); + + opl2.setFNumber(ch, 0x2AA); + TEST_ASSERT_EQUAL_INT16(0x2AA, opl2.getFNumber(ch)); + TEST_ASSERT_EQUAL_INT8(0xAA, opl2.getChannelRegister(0xA0, ch)); + TEST_ASSERT_EQUAL_INT8(0x02, opl2.getChannelRegister(0xB0, ch)); + + opl2.setFNumber(ch, 0xFFFF); + TEST_ASSERT_EQUAL_INT16(0x3FF, opl2.getFNumber(ch)); + TEST_ASSERT_EQUAL_INT8(0xFF, opl2.getChannelRegister(0xA0, ch)); + TEST_ASSERT_EQUAL_INT8(0x03, opl2.getChannelRegister(0xB0, ch)); + + opl2.setFNumber(ch, 0x0000); + TEST_ASSERT_EQUAL_INT16(0x000, opl2.getFNumber(ch)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xA0, ch)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xB0, ch)); + } +} + + +/** + * Test setting the block number and key on on all channels. + */ +void test_register0xB0() { + for (int ch = 0; ch < 9; ch ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getBlock(ch)); + TEST_ASSERT_FALSE(opl2.getKeyOn(ch)); + + opl2.setBlock(ch, 0x05); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getBlock(ch)); + TEST_ASSERT_EQUAL_INT8(0x14, opl2.getChannelRegister(0xB0, ch)); + + opl2.setBlock(ch, 0x02); + TEST_ASSERT_EQUAL_INT8(0x02, opl2.getBlock(ch)); + TEST_ASSERT_EQUAL_INT8(0x08, opl2.getChannelRegister(0xB0, ch)); + + opl2.setBlock(ch, 0xFF); + TEST_ASSERT_EQUAL_INT8(0x07, opl2.getBlock(ch)); + TEST_ASSERT_EQUAL_INT8(0x1C, opl2.getChannelRegister(0xB0, ch)); + + opl2.setBlock(ch, 0x00); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getBlock(ch)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xB0, ch)); + + opl2.setKeyOn(ch, true); + TEST_ASSERT_TRUE(opl2.getKeyOn(ch)); + TEST_ASSERT_EQUAL_INT8(0x20, opl2.getChannelRegister(0xB0, ch)); + + opl2.setKeyOn(ch, false); + TEST_ASSERT_FALSE(opl2.getKeyOn(ch)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xB0, ch)); + } +} + +/** + * Test the drum register + */ +void test_register0xBD() { + TEST_ASSERT_FALSE(opl2.getPercussion()); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getDrums()); + + opl2.setPercussion(true); + TEST_ASSERT_TRUE(opl2.getPercussion()); + TEST_ASSERT_EQUAL_INT8(0x20, opl2.getChipRegister(0xBD)); + + opl2.setPercussion(false); + TEST_ASSERT_FALSE(opl2.getPercussion()); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0xBD)); + + opl2.setDrums(DRUM_BITS_BASS | DRUM_BITS_TOM | DRUM_BITS_HI_HAT); + TEST_ASSERT_EQUAL_INT8(0x15, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x15, opl2.getChipRegister(0xBD)); + + opl2.setDrums(DRUM_BITS_SNARE | DRUM_BITS_CYMBAL); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getChipRegister(0xBD)); + + opl2.setDrums(0xFF); + TEST_ASSERT_EQUAL_INT8(0x1F, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x1F, opl2.getChipRegister(0xBD)); + + opl2.setDrums(0x00); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0xBD)); + + opl2.setDrums(true, false, true, false, true); + TEST_ASSERT_EQUAL_INT8(0x15, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x15, opl2.getChipRegister(0xBD)); + + opl2.setDrums(false, true, false, true, false); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getChipRegister(0xBD)); + + opl2.setDrums(true, true, true, true, true); + TEST_ASSERT_EQUAL_INT8(0x1F, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x1F, opl2.getChipRegister(0xBD)); + + opl2.setDrums(false, false, false, false, false); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getDrums()); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0xBD)); +} + + +/** + * Test setting feedback and synth mode on each channel. + */ +void test_register0xC0() { + for (int ch = 0; ch < 9; ch ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getFeedback(ch)); + TEST_ASSERT_FALSE(opl2.getSynthMode(ch)); + + opl2.setFeedback(ch, 0x05); + TEST_ASSERT_EQUAL_INT8(0x05, opl2.getFeedback(ch)); + TEST_ASSERT_EQUAL_INT8(0x0A, opl2.getChannelRegister(0xC0, ch)); + + opl2.setFeedback(ch, 0x02); + TEST_ASSERT_EQUAL_INT8(0x02, opl2.getFeedback(ch)); + TEST_ASSERT_EQUAL_INT8(0x04, opl2.getChannelRegister(0xC0, ch)); + + opl2.setFeedback(ch, 0xFF); + TEST_ASSERT_EQUAL_INT8(0x07, opl2.getFeedback(ch)); + TEST_ASSERT_EQUAL_INT8(0x0E, opl2.getChannelRegister(0xC0, ch)); + + opl2.setSynthMode(ch, true); + TEST_ASSERT_TRUE(opl2.getSynthMode(ch)); + TEST_ASSERT_EQUAL_INT8(0x0F, opl2.getChannelRegister(0xC0, ch)); + + opl2.setSynthMode(ch, false); + TEST_ASSERT_FALSE(opl2.getSynthMode(ch)); + TEST_ASSERT_EQUAL_INT8(0x0E, opl2.getChannelRegister(0xC0, ch)); + } +} + + +/** + * Test setting waveform for each channel operator. + */ +void test_register0xE0() { + for (int ch = 0; ch < 9; ch ++) { + for (int op = 0; op < 2; op ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getWaveForm(ch, op)); + + opl2.setWaveForm(ch, op, 0x01); + TEST_ASSERT_EQUAL_INT8(0x01, opl2.getWaveForm(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x01, opl2.getOperatorRegister(0xE0, ch, op)); + opl2.setWaveForm(ch, op, 0x02); + TEST_ASSERT_EQUAL_INT8(0x02, opl2.getWaveForm(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x02, opl2.getOperatorRegister(0xE0, ch, op)); + opl2.setWaveForm(ch, op, 0xFF); + TEST_ASSERT_EQUAL_INT8(0x03, opl2.getWaveForm(ch, op)); + TEST_ASSERT_EQUAL_INT8(0x03, opl2.getOperatorRegister(0xE0, ch, op)); + } + } +} + + +void setup() { + delay(2000); + UNITY_BEGIN(); + + opl2.begin(); + RUN_TEST(test_register0x01); + RUN_TEST(test_register0x20); + RUN_TEST(test_register0x40); + RUN_TEST(test_register0x60); + RUN_TEST(test_register0x80); + RUN_TEST(test_register0xA0); + RUN_TEST(test_register0xB0); + RUN_TEST(test_register0xBD); + RUN_TEST(test_register0xC0); + RUN_TEST(test_register0xE0); + + UNITY_END(); +} + + +void loop() { +} diff --git a/test/OPL2_Registers/Test_OPL2_Registers.cpp b/test/OPL2_Registers/Test_OPL2_Registers.cpp new file mode 100644 index 0000000..f4980ae --- /dev/null +++ b/test/OPL2_Registers/Test_OPL2_Registers.cpp @@ -0,0 +1,177 @@ +#include +#include +#include + +OPL2 opl2; + + +/** + * Number of reported channels should be 9 on OPL2. + */ +void test_getNumChannels() { + TEST_ASSERT_EQUAL_INT8(9, opl2.getNumChannels()); +} + + +/** + * Test for correct array offsets for chip wide registers. + */ +void test_getChipRegisterOffset() { + TEST_ASSERT_EQUAL_INT8(0, opl2.getChipRegisterOffset(0x01)); + TEST_ASSERT_EQUAL_INT8(1, opl2.getChipRegisterOffset(0x08)); + TEST_ASSERT_EQUAL_INT8(2, opl2.getChipRegisterOffset(0xBD)); + + // Test invalid register to return offset 0. + TEST_ASSERT_EQUAL_INT8(0, opl2.getChipRegisterOffset(0xFF)); +} + + +/** + * Test for correct array offsets for channel registers. + */ +void test_getChannelRegisterOffset() { + for (int i = 0; i < 9; i ++) { + TEST_ASSERT_EQUAL_INT8(i * 3 + 0, opl2.getChannelRegisterOffset(0xA0, i)); + TEST_ASSERT_EQUAL_INT8(i * 3 + 1, opl2.getChannelRegisterOffset(0xB0, i)); + TEST_ASSERT_EQUAL_INT8(i * 3 + 2, opl2.getChannelRegisterOffset(0xC0, i)); + } + + // Test wrapping of channels if channel > numChannels. + TEST_ASSERT_EQUAL_INT8(0, opl2.getChannelRegisterOffset(0xA0, 9)); + TEST_ASSERT_EQUAL_INT8(3, opl2.getChannelRegisterOffset(0xA0, 10)); + + // Test invalid base register to return offset 0. + TEST_ASSERT_EQUAL_INT8(0, opl2.getChannelRegisterOffset(0xFF, 0)); +} + + +/** + * Test for correct array offsets for operator registers. + */ +void test_getOperatorRegisterOffset() { + for (int i = 0; i < 9; i ++) { + for (int j = 0; j < 2; j ++) { + TEST_ASSERT_EQUAL_INT16((i * 10) + (j * 5) + 0, opl2.getOperatorRegisterOffset(0x20, i, j)); + TEST_ASSERT_EQUAL_INT16((i * 10) + (j * 5) + 1, opl2.getOperatorRegisterOffset(0x40, i, j)); + TEST_ASSERT_EQUAL_INT16((i * 10) + (j * 5) + 2, opl2.getOperatorRegisterOffset(0x60, i, j)); + TEST_ASSERT_EQUAL_INT16((i * 10) + (j * 5) + 3, opl2.getOperatorRegisterOffset(0x80, i, j)); + TEST_ASSERT_EQUAL_INT16((i * 10) + (j * 5) + 4, opl2.getOperatorRegisterOffset(0xE0, i, j)); + } + } + + // Test wrapping of channels if channel > numChannels. + TEST_ASSERT_EQUAL_INT16(0, opl2.getOperatorRegisterOffset(0x20, 9, 0)); + TEST_ASSERT_EQUAL_INT16(10, opl2.getOperatorRegisterOffset(0x20, 10, 0)); + + // Test wrapping of operators if operator > 1. + TEST_ASSERT_EQUAL_INT16(0, opl2.getOperatorRegisterOffset(0x20, 0, 2)); + TEST_ASSERT_EQUAL_INT16(5, opl2.getOperatorRegisterOffset(0x20, 9, 3)); + + // Test invalid base register to return offset 0. + TEST_ASSERT_EQUAL_INT16(0, opl2.getOperatorRegisterOffset(0xFF, 0, 0)); +} + + +/** + * Test write / read operations on chip wide registers. + */ +void test_chipRegisterRW() { + const byte regs[3] = { 0x01, 0x08, 0x55 }; + const byte values[2] = { 0x55, 0xAA }; + + for (int i = 0; i < 2; i ++) { + for (int reg = 0; reg < 3; reg ++) { + opl2.setChipRegister(regs[reg], values[i]); + TEST_ASSERT_EQUAL_INT8(values[i], opl2.getChipRegister(regs[reg])); + } + } +} + + +/** + * Test write / read operations on channel registers. + */ +void test_channelRegisterRW() { + const byte regs[3] = { 0xA0, 0xB0, 0xC0 }; + const byte values[2] = { 0x55, 0xAA }; + + for (int i = 0; i < 2; i ++) { + for (int ch = 0; ch < 9; ch ++) { + for (int reg = 0; reg < 3; reg ++) { + opl2.setChannelRegister(regs[reg], ch, values[i]); + TEST_ASSERT_EQUAL_INT8(values[i], opl2.getChannelRegister(regs[reg], ch)); + } + } + } +} + + +/** + * Test write / read operations on operator registers. + */ +void test_operatorRegisterRW() { + const byte regs[5] = { 0x20, 0x40, 0x60, 0x80, 0xE0 }; + const byte values[2] = { 0x55, 0xAA }; + + for (int i = 0; i < 2; i ++) { + for (int ch = 0; ch < 9; ch ++) { + for (int op = 0; op < 2; op ++) { + for (int reg = 0; reg < 3; reg ++) { + opl2.setOperatorRegister(regs[reg], ch, op, values[i]); + TEST_ASSERT_EQUAL_INT8(values[i], opl2.getOperatorRegister(regs[reg], ch, op)); + } + } + } + } +} + + +/** + * After OPL2.begin() or OPL2.reset() all registers should be set to 0. + */ +void test_OPL2Begin() { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0x01)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0x08)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChipRegister(0xBD)); + + for (int i = 0; i < 1; i ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xA0, i)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xB0, i)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getChannelRegister(0xC0, i)); + + for (int j = 0; j < 2; j ++) { + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getOperatorRegister(0x20, 0, 1)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getOperatorRegister(0x40, i, j)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getOperatorRegister(0x60, i, j)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getOperatorRegister(0x80, i, j)); + TEST_ASSERT_EQUAL_INT8(0x00, opl2.getOperatorRegister(0xE0, i, j)); + } + } +} + + +void setup() { + delay(2000); + UNITY_BEGIN(); + + RUN_TEST(test_getNumChannels); + + RUN_TEST(test_getChipRegisterOffset); + RUN_TEST(test_getChannelRegisterOffset); + RUN_TEST(test_getOperatorRegisterOffset); + + opl2.begin(); + RUN_TEST(test_OPL2Begin); + RUN_TEST(test_chipRegisterRW); + RUN_TEST(test_channelRegisterRW); + RUN_TEST(test_operatorRegisterRW); + + opl2.reset(); + RUN_TEST(test_OPL2Begin); + + UNITY_END(); +} + + +void loop() { +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html