gzdoom-gles/libraries/adlmidi/wopl/wopl_file.c

589 lines
16 KiB
C
Raw Normal View History

Upgrade libADLMIDI and libOPNMIDI Added ability to switch emulator and it's accuracy level ("enabling of 'run at PCM rate' reduces accuracy, and also reduces CPU usage") Added draft code for future external banks support (WOPL format for ADLMIDI and WOPN format for OPNMIDI) ADLMIDI 1.3.3 2018-06-19 * Fixed an inability to load another custom bank without of library re-initialization * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect 4-op counter which is still catch 4-op instruments on 2-op banks * Fixed an incorrect processing of auto-flags * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Updated DosBox OPL3 emulator up to r4111 of official DosBox trunk (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * The automatical choosing of 4 operator channels count has been improved (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) ADLMIDI 1.3.2 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.3.0 2018-06-19 * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Fixed an incorrect processing of auto-flags * MAME YM2612 now results a more accurate sound as internal using of native sample rate makes more correct sound generation * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.2.0 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for MAME YM2612 Emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!)
2018-06-19 21:48:42 +00:00
/*
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
*
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* 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:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* 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.
*/
#include "wopl_file.h"
#include <string.h>
#include <stdlib.h>
static const char *wopl3_magic = "WOPL3-BANK\0";
static const char *wopli_magic = "WOPL3-INST\0";
static const uint16_t wopl_latest_version = 3;
#define WOPL_INST_SIZE_V2 62
#define WOPL_INST_SIZE_V3 66
static uint16_t toUint16LE(const uint8_t *arr)
{
uint16_t num = arr[0];
num |= ((arr[1] << 8) & 0xFF00);
return num;
}
static uint16_t toUint16BE(const uint8_t *arr)
{
uint16_t num = arr[1];
num |= ((arr[0] << 8) & 0xFF00);
return num;
}
static int16_t toSint16BE(const uint8_t *arr)
{
int16_t num = *(const int8_t *)(&arr[0]);
num *= 1 << 8;
num |= arr[1];
return num;
}
static void fromUint16LE(uint16_t in, uint8_t *arr)
{
arr[0] = in & 0x00FF;
arr[1] = (in >> 8) & 0x00FF;
}
static void fromUint16BE(uint16_t in, uint8_t *arr)
{
arr[1] = in & 0x00FF;
arr[0] = (in >> 8) & 0x00FF;
}
static void fromSint16BE(int16_t in, uint8_t *arr)
{
arr[1] = in & 0x00FF;
arr[0] = ((uint16_t)in >> 8) & 0x00FF;
}
WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks)
{
WOPLFile *file = NULL;
if(melodic_banks == 0)
return NULL;
if(percussive_banks == 0)
return NULL;
file = (WOPLFile*)calloc(1, sizeof(WOPLFile));
if(!file)
return NULL;
file->banks_count_melodic = melodic_banks;
file->banks_count_percussion = percussive_banks;
file->banks_melodic = (WOPLBank*)calloc(1, sizeof(WOPLBank) * melodic_banks );
file->banks_percussive = (WOPLBank*)calloc(1, sizeof(WOPLBank) * percussive_banks );
return file;
}
void WOPL_Free(WOPLFile *file)
{
if(file)
{
if(file->banks_melodic)
free(file->banks_melodic);
if(file->banks_percussive)
free(file->banks_percussive);
free(file);
}
}
int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2)
{
int res = 1;
res &= (bank1->version == bank2->version);
res &= (bank1->opl_flags == bank2->opl_flags);
res &= (bank1->volume_model == bank2->volume_model);
res &= (bank1->banks_count_melodic == bank2->banks_count_melodic);
res &= (bank1->banks_count_percussion == bank2->banks_count_percussion);
if(res)
{
int i;
for(i = 0; i < bank1->banks_count_melodic; i++)
res &= (memcmp(&bank1->banks_melodic[i], &bank2->banks_melodic[i], sizeof(WOPLBank)) == 0);
if(res)
{
for(i = 0; i < bank1->banks_count_percussion; i++)
res &= (memcmp(&bank1->banks_percussive[i], &bank2->banks_percussive[i], sizeof(WOPLBank)) == 0);
}
}
return res;
}
static void WOPL_parseInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays)
{
int l;
strncpy(ins->inst_name, (const char*)cursor, 32);
ins->inst_name[32] = '\0';
ins->note_offset1 = toSint16BE(cursor + 32);
ins->note_offset2 = toSint16BE(cursor + 34);
ins->midi_velocity_offset = (int8_t)cursor[36];
ins->second_voice_detune = (int8_t)cursor[37];
ins->percussion_key_number = cursor[38];
ins->inst_flags = cursor[39];
ins->fb_conn1_C0 = cursor[40];
ins->fb_conn2_C0 = cursor[41];
for(l = 0; l < 4; l++)
{
size_t off = 42 + (size_t)(l) * 5;
ins->operators[l].avekf_20 = cursor[off + 0];
ins->operators[l].ksl_l_40 = cursor[off + 1];
ins->operators[l].atdec_60 = cursor[off + 2];
ins->operators[l].susrel_80 = cursor[off + 3];
ins->operators[l].waveform_E0 = cursor[off + 4];
}
if((version >= 3) && has_sounding_delays)
{
ins->delay_on_ms = toUint16BE(cursor + 62);
ins->delay_off_ms = toUint16BE(cursor + 64);
}
}
static void WOPL_writeInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays)
{
int l;
strncpy((char*)cursor, ins->inst_name, 32);
fromSint16BE(ins->note_offset1, cursor + 32);
fromSint16BE(ins->note_offset2, cursor + 34);
cursor[36] = (uint8_t)ins->midi_velocity_offset;
cursor[37] = (uint8_t)ins->second_voice_detune;
cursor[38] = ins->percussion_key_number;
cursor[39] = ins->inst_flags;
cursor[40] = ins->fb_conn1_C0;
cursor[41] = ins->fb_conn2_C0;
for(l = 0; l < 4; l++)
{
size_t off = 42 + (size_t)(l) * 5;
cursor[off + 0] = ins->operators[l].avekf_20;
cursor[off + 1] = ins->operators[l].ksl_l_40;
cursor[off + 2] = ins->operators[l].atdec_60;
cursor[off + 3] = ins->operators[l].susrel_80;
cursor[off + 4] = ins->operators[l].waveform_E0;
}
if((version >= 3) && has_sounding_delays)
{
fromUint16BE(ins->delay_on_ms, cursor + 62);
fromUint16BE(ins->delay_off_ms, cursor + 64);
}
}
WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error)
{
WOPLFile *outFile = NULL;
uint16_t i = 0, j = 0, k = 0;
uint16_t version = 0;
uint16_t count_melodic_banks = 1;
uint16_t count_percusive_banks = 1;
uint8_t *cursor = (uint8_t *)mem;
WOPLBank *bankslots[2];
uint16_t bankslots_sizes[2];
#define SET_ERROR(err) \
{\
WOPL_Free(outFile);\
if(error)\
{\
*error = err;\
}\
}
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
if(!cursor)
{
SET_ERROR(WOPL_ERR_NULL_POINTER);
return NULL;
}
{/* Magic number */
if(length < 11)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
if(memcmp(cursor, wopl3_magic, 11) != 0)
{
SET_ERROR(WOPL_ERR_BAD_MAGIC);
return NULL;
}
GO_FORWARD(11);
}
{/* Version code */
if(length < 2)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
version = toUint16LE(cursor);
if(version > wopl_latest_version)
{
SET_ERROR(WOPL_ERR_NEWER_VERSION);
return NULL;
}
GO_FORWARD(2);
}
{/* Header of WOPL */
uint8_t head[6];
if(length < 6)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
memcpy(head, cursor, 6);
count_melodic_banks = toUint16BE(head);
count_percusive_banks = toUint16BE(head + 2);
GO_FORWARD(6);
outFile = WOPL_Init(count_melodic_banks, count_percusive_banks);
if(!outFile)
{
SET_ERROR(WOPL_ERR_OUT_OF_MEMORY);
return NULL;
}
outFile->version = version;
outFile->opl_flags = head[4];
outFile->volume_model = head[5];
}
bankslots_sizes[0] = count_melodic_banks;
bankslots[0] = outFile->banks_melodic;
bankslots_sizes[1] = count_percusive_banks;
bankslots[1] = outFile->banks_percussive;
if(version >= 2) /* Bank names and LSB/MSB titles */
{
for(i = 0; i < 2; i++)
{
for(j = 0; j < bankslots_sizes[i]; j++)
{
if(length < 34)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
strncpy(bankslots[i][j].bank_name, (const char*)cursor, 32);
bankslots[i][j].bank_name[32] = '\0';
bankslots[i][j].bank_midi_lsb = cursor[32];
bankslots[i][j].bank_midi_msb = cursor[33];
GO_FORWARD(34);
}
}
}
{/* Read instruments data */
uint16_t insSize = 0;
if(version > 2)
insSize = WOPL_INST_SIZE_V3;
else
insSize = WOPL_INST_SIZE_V2;
for(i = 0; i < 2; i++)
{
if(length < (insSize * 128) * (size_t)bankslots_sizes[i])
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
for(j = 0; j < bankslots_sizes[i]; j++)
{
for(k = 0; k < 128; k++)
{
WOPLInstrument *ins = &bankslots[i][j].ins[k];
WOPL_parseInstrument(ins, cursor, version, 1);
GO_FORWARD(insSize);
}
}
}
}
#undef GO_FORWARD
#undef SET_ERROR
return outFile;
}
int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length)
{
uint16_t version = 0;
uint8_t *cursor = (uint8_t *)mem;
uint16_t ins_size;
if(!cursor)
return WOPL_ERR_NULL_POINTER;
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
{/* Magic number */
if(length < 11)
return WOPL_ERR_UNEXPECTED_ENDING;
if(memcmp(cursor, wopli_magic, 11) != 0)
return WOPL_ERR_BAD_MAGIC;
GO_FORWARD(11);
}
{/* Version code */
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
version = toUint16LE(cursor);
if(version > wopl_latest_version)
return WOPL_ERR_NEWER_VERSION;
GO_FORWARD(2);
}
Upgrade libADLMIDI and libOPNMIDI Added full-panning stereo, improvement of channel management, and many other things. Also, I have implemented an ability to use custom WOPL (for libADLMIDI) and WOPN (for libOPNMIDI) banks from the same path as "soundfonts", but also, in the same environment, the "fm_banks" folder was added for WOPL/WOPN storing purposes. To toggle usage of embedded or custom bank, I have added togglable booleans. When bank fails to be loaded, the default embedded bank is getting to be used as fallback. ADLMIDI 1.4.0 2018-10-01 * Implemented a full support for Portamento! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for SysEx event handling! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for GS way of custom drum channels (through SysEx events) * Ignore some NRPN events and lsb bank number when using GS standard (after catching of GS Reset SysEx call) * Added support for CC66-Sostenuto controller (Pedal hold of currently-pressed notes only while CC64 holds also all next notes) * Added support for CC67-SoftPedal controller (SoftPedal lowers the volume of notes played) * Fixed correctness of CMF files playing * Fixed unnecessary overuse of chip channels by blank notes * Added API to disable specific MIDI tracks or play one of MIDI tracks solo * Added support for more complex loop (loopStart=XX, loopEnd=0). Where XX - count of loops, or 0 - infinite. Nested loops are supported without of any limits. * Added working implementation of TMB's velocity offset * Added support for full-panning stereo option (Thanks to [Christopher Snowhill](https://github.com/kode54) for a work!) * Fixed inability to play high notes due physical tone frequency out of range on the OPL3 chip OPNMIDI 1.4.0 2018-10-01 * Implemented a full support for Portamento! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for SysEx event handling! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for GS way of custom drum channels (through SysEx events) * Ignore some NRPN events and lsb bank number when using GS standard (after catching of GS Reset SysEx call) * Added support for CC66-Sostenuto controller (Pedal hold of currently-pressed notes only while CC64 holds also all next notes) * Added support for CC67-SoftPedal controller (SoftPedal lowers the volume of notes played) * Resolved a trouble which sometimes makes a junk noise sound and unnecessary overuse of chip channels * Volume models support taken from libADLMIDI has been adapted to OPN2's chip speficis * Fixed inability to play high notes due physical tone frequency out of range on the OPN2 chip * Added support for full-panning stereo option ADL&OPN Hotfix: re-calculated default banks The fix on side of measurer of OPL3-BE and OPN2-BE where some instruments getting zero releasing time.
2018-10-01 21:07:05 +00:00
file->version = version;
Upgrade libADLMIDI and libOPNMIDI Added ability to switch emulator and it's accuracy level ("enabling of 'run at PCM rate' reduces accuracy, and also reduces CPU usage") Added draft code for future external banks support (WOPL format for ADLMIDI and WOPN format for OPNMIDI) ADLMIDI 1.3.3 2018-06-19 * Fixed an inability to load another custom bank without of library re-initialization * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect 4-op counter which is still catch 4-op instruments on 2-op banks * Fixed an incorrect processing of auto-flags * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Updated DosBox OPL3 emulator up to r4111 of official DosBox trunk (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * The automatical choosing of 4 operator channels count has been improved (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) ADLMIDI 1.3.2 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.3.0 2018-06-19 * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Fixed an incorrect processing of auto-flags * MAME YM2612 now results a more accurate sound as internal using of native sample rate makes more correct sound generation * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.2.0 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for MAME YM2612 Emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!)
2018-06-19 21:48:42 +00:00
{/* is drum flag */
if(length < 1)
return WOPL_ERR_UNEXPECTED_ENDING;
file->is_drum = *cursor;
GO_FORWARD(1);
}
if(version > 2)
/* Skip sounding delays are not part of single-instrument file
* two sizes of uint16_t will be subtracted */
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
else
ins_size = WOPL_INST_SIZE_V2;
if(length < ins_size)
return WOPL_ERR_UNEXPECTED_ENDING;
WOPL_parseInstrument(&file->inst, cursor, version, 0);
GO_FORWARD(ins_size);
return WOPL_ERR_OK;
#undef GO_FORWARD
}
size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version)
{
size_t final_size = 0;
size_t ins_size = 0;
if(version == 0)
version = wopl_latest_version;
if(!file)
return 0;
final_size += 11 + 2 + 2 + 2 + 1 + 1;
/*
* Magic number,
* Version,
* Count of melodic banks,
* Count of percussive banks,
* Chip specific flags
* Volume Model
*/
if(version >= 2)
{
/* Melodic banks meta-data */
final_size += (32 + 1 + 1) * file->banks_count_melodic;
/* Percussive banks meta-data */
final_size += (32 + 1 + 1) * file->banks_count_percussion;
}
if(version >= 3)
ins_size = WOPL_INST_SIZE_V3;
else
ins_size = WOPL_INST_SIZE_V2;
/* Melodic instruments */
final_size += (ins_size * 128) * file->banks_count_melodic;
/* Percusive instruments */
final_size += (ins_size * 128) * file->banks_count_percussion;
return final_size;
}
size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version)
{
size_t final_size = 0;
size_t ins_size = 0;
if(version == 0)
version = wopl_latest_version;
if(!file)
return 0;
final_size += 11 + 2 + 1;
/*
* Magic number,
* version,
* is percussive instrument
*/
Upgrade libADLMIDI and libOPNMIDI Added full-panning stereo, improvement of channel management, and many other things. Also, I have implemented an ability to use custom WOPL (for libADLMIDI) and WOPN (for libOPNMIDI) banks from the same path as "soundfonts", but also, in the same environment, the "fm_banks" folder was added for WOPL/WOPN storing purposes. To toggle usage of embedded or custom bank, I have added togglable booleans. When bank fails to be loaded, the default embedded bank is getting to be used as fallback. ADLMIDI 1.4.0 2018-10-01 * Implemented a full support for Portamento! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for SysEx event handling! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for GS way of custom drum channels (through SysEx events) * Ignore some NRPN events and lsb bank number when using GS standard (after catching of GS Reset SysEx call) * Added support for CC66-Sostenuto controller (Pedal hold of currently-pressed notes only while CC64 holds also all next notes) * Added support for CC67-SoftPedal controller (SoftPedal lowers the volume of notes played) * Fixed correctness of CMF files playing * Fixed unnecessary overuse of chip channels by blank notes * Added API to disable specific MIDI tracks or play one of MIDI tracks solo * Added support for more complex loop (loopStart=XX, loopEnd=0). Where XX - count of loops, or 0 - infinite. Nested loops are supported without of any limits. * Added working implementation of TMB's velocity offset * Added support for full-panning stereo option (Thanks to [Christopher Snowhill](https://github.com/kode54) for a work!) * Fixed inability to play high notes due physical tone frequency out of range on the OPL3 chip OPNMIDI 1.4.0 2018-10-01 * Implemented a full support for Portamento! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for SysEx event handling! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for GS way of custom drum channels (through SysEx events) * Ignore some NRPN events and lsb bank number when using GS standard (after catching of GS Reset SysEx call) * Added support for CC66-Sostenuto controller (Pedal hold of currently-pressed notes only while CC64 holds also all next notes) * Added support for CC67-SoftPedal controller (SoftPedal lowers the volume of notes played) * Resolved a trouble which sometimes makes a junk noise sound and unnecessary overuse of chip channels * Volume models support taken from libADLMIDI has been adapted to OPN2's chip speficis * Fixed inability to play high notes due physical tone frequency out of range on the OPN2 chip * Added support for full-panning stereo option ADL&OPN Hotfix: re-calculated default banks The fix on side of measurer of OPL3-BE and OPN2-BE where some instruments getting zero releasing time.
2018-10-01 21:07:05 +00:00
if(version > 2)
/* Skip sounding delays are not part of single-instrument file
* two sizes of uint16_t will be subtracted */
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
Upgrade libADLMIDI and libOPNMIDI Added ability to switch emulator and it's accuracy level ("enabling of 'run at PCM rate' reduces accuracy, and also reduces CPU usage") Added draft code for future external banks support (WOPL format for ADLMIDI and WOPN format for OPNMIDI) ADLMIDI 1.3.3 2018-06-19 * Fixed an inability to load another custom bank without of library re-initialization * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect 4-op counter which is still catch 4-op instruments on 2-op banks * Fixed an incorrect processing of auto-flags * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Updated DosBox OPL3 emulator up to r4111 of official DosBox trunk (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * The automatical choosing of 4 operator channels count has been improved (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) ADLMIDI 1.3.2 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.3.0 2018-06-19 * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Fixed an incorrect processing of auto-flags * MAME YM2612 now results a more accurate sound as internal using of native sample rate makes more correct sound generation * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.2.0 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for MAME YM2612 Emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!)
2018-06-19 21:48:42 +00:00
else
ins_size = WOPL_INST_SIZE_V2;
Upgrade libADLMIDI and libOPNMIDI Added full-panning stereo, improvement of channel management, and many other things. Also, I have implemented an ability to use custom WOPL (for libADLMIDI) and WOPN (for libOPNMIDI) banks from the same path as "soundfonts", but also, in the same environment, the "fm_banks" folder was added for WOPL/WOPN storing purposes. To toggle usage of embedded or custom bank, I have added togglable booleans. When bank fails to be loaded, the default embedded bank is getting to be used as fallback. ADLMIDI 1.4.0 2018-10-01 * Implemented a full support for Portamento! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for SysEx event handling! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for GS way of custom drum channels (through SysEx events) * Ignore some NRPN events and lsb bank number when using GS standard (after catching of GS Reset SysEx call) * Added support for CC66-Sostenuto controller (Pedal hold of currently-pressed notes only while CC64 holds also all next notes) * Added support for CC67-SoftPedal controller (SoftPedal lowers the volume of notes played) * Fixed correctness of CMF files playing * Fixed unnecessary overuse of chip channels by blank notes * Added API to disable specific MIDI tracks or play one of MIDI tracks solo * Added support for more complex loop (loopStart=XX, loopEnd=0). Where XX - count of loops, or 0 - infinite. Nested loops are supported without of any limits. * Added working implementation of TMB's velocity offset * Added support for full-panning stereo option (Thanks to [Christopher Snowhill](https://github.com/kode54) for a work!) * Fixed inability to play high notes due physical tone frequency out of range on the OPL3 chip OPNMIDI 1.4.0 2018-10-01 * Implemented a full support for Portamento! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for SysEx event handling! (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added support for GS way of custom drum channels (through SysEx events) * Ignore some NRPN events and lsb bank number when using GS standard (after catching of GS Reset SysEx call) * Added support for CC66-Sostenuto controller (Pedal hold of currently-pressed notes only while CC64 holds also all next notes) * Added support for CC67-SoftPedal controller (SoftPedal lowers the volume of notes played) * Resolved a trouble which sometimes makes a junk noise sound and unnecessary overuse of chip channels * Volume models support taken from libADLMIDI has been adapted to OPN2's chip speficis * Fixed inability to play high notes due physical tone frequency out of range on the OPN2 chip * Added support for full-panning stereo option ADL&OPN Hotfix: re-calculated default banks The fix on side of measurer of OPL3-BE and OPN2-BE where some instruments getting zero releasing time.
2018-10-01 21:07:05 +00:00
final_size += ins_size;
Upgrade libADLMIDI and libOPNMIDI Added ability to switch emulator and it's accuracy level ("enabling of 'run at PCM rate' reduces accuracy, and also reduces CPU usage") Added draft code for future external banks support (WOPL format for ADLMIDI and WOPN format for OPNMIDI) ADLMIDI 1.3.3 2018-06-19 * Fixed an inability to load another custom bank without of library re-initialization * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect 4-op counter which is still catch 4-op instruments on 2-op banks * Fixed an incorrect processing of auto-flags * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Updated DosBox OPL3 emulator up to r4111 of official DosBox trunk (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * The automatical choosing of 4 operator channels count has been improved (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) ADLMIDI 1.3.2 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.3.0 2018-06-19 * Optimizing the MIDI banks management system for MultiBanks (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event * Fixed an incorrect processing of auto-flags * MAME YM2612 now results a more accurate sound as internal using of native sample rate makes more correct sound generation * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! * Added optional HQ resampler for Nuked OPL3 emulators which does usage of Zita-Resampler library (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) OPNMIDI 1.2.0 2018-04-24 * Added ability to disable MUS and XMI converters * Added ability to disable embedded MIDI sequencer to use library as RealTime synthesizer only or use any custom MIDI sequencer plugins. * Fixed blank instruments fallback in multi-bank support. When using non-zero bank, if instrument is blank, then, instrument will be taken from a root (I.e. zero bank). * Added support for real-time switching the emulator * Added support for MAME YM2612 Emulator * Added support for CC-120 - "All sound off" on the MIDI channel * Changed logic of CC-74 Brightness to affect sound only between 0 and 64 like real XG synthesizers. Ability to turn on a full-ranged brightness (to use full 0...127 range) is kept. * Added support for different output sample formats (PCM8, PCM8U, PCM16, PCM16U, PCM32, PCM32U, Float32, and Float64) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked MIDI channels management to avoid any memory reallocations while music processing for a hard real time. (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!)
2018-06-19 21:48:42 +00:00
return final_size;
}
int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm)
{
uint8_t *cursor = (uint8_t *)dest_mem;
uint16_t ins_size = 0;
uint16_t i, j, k;
uint16_t banks_melodic = force_gm ? 1 : file->banks_count_melodic;
uint16_t banks_percusive = force_gm ? 1 : file->banks_count_percussion;
WOPLBank *bankslots[2];
uint16_t bankslots_sizes[2];
if(version == 0)
version = wopl_latest_version;
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
if(length < 11)
return WOPL_ERR_UNEXPECTED_ENDING;
memcpy(cursor, wopl3_magic, 11);
GO_FORWARD(11);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16LE(version, cursor);
GO_FORWARD(2);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16BE(banks_melodic, cursor);
GO_FORWARD(2);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16BE(banks_percusive, cursor);
GO_FORWARD(2);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
cursor[0] = file->opl_flags;
cursor[1] = file->volume_model;
GO_FORWARD(2);
bankslots[0] = file->banks_melodic;
bankslots_sizes[0] = banks_melodic;
bankslots[1] = file->banks_percussive;
bankslots_sizes[1] = banks_percusive;
if(version >= 2)
{
for(i = 0; i < 2; i++)
{
for(j = 0; j < bankslots_sizes[i]; j++)
{
if(length < 34)
return WOPL_ERR_UNEXPECTED_ENDING;
strncpy((char*)cursor, bankslots[i][j].bank_name, 32);
cursor[32] = bankslots[i][j].bank_midi_lsb;
cursor[33] = bankslots[i][j].bank_midi_msb;
GO_FORWARD(34);
}
}
}
{/* Write instruments data */
if(version >= 3)
ins_size = WOPL_INST_SIZE_V3;
else
ins_size = WOPL_INST_SIZE_V2;
for(i = 0; i < 2; i++)
{
if(length < (ins_size * 128) * (size_t)bankslots_sizes[i])
return WOPL_ERR_UNEXPECTED_ENDING;
for(j = 0; j < bankslots_sizes[i]; j++)
{
for(k = 0; k < 128; k++)
{
WOPLInstrument *ins = &bankslots[i][j].ins[k];
WOPL_writeInstrument(ins, cursor, version, 1);
GO_FORWARD(ins_size);
}
}
}
}
return WOPL_ERR_OK;
#undef GO_FORWARD
}
int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version)
{
uint8_t *cursor = (uint8_t *)dest_mem;
uint16_t ins_size;
if(!cursor)
return WOPL_ERR_NULL_POINTER;
if(version == 0)
version = wopl_latest_version;
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
{/* Magic number */
if(length < 11)
return WOPL_ERR_UNEXPECTED_ENDING;
memcpy(cursor, wopli_magic, 11);
GO_FORWARD(11);
}
{/* Version code */
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16LE(version, cursor);
GO_FORWARD(2);
}
{/* is drum flag */
if(length < 1)
return WOPL_ERR_UNEXPECTED_ENDING;
*cursor = file->is_drum;
GO_FORWARD(1);
}
if(version > 2)
/* Skip sounding delays are not part of single-instrument file
* two sizes of uint16_t will be subtracted */
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
else
ins_size = WOPL_INST_SIZE_V2;
if(length < ins_size)
return WOPL_ERR_UNEXPECTED_ENDING;
WOPL_writeInstrument(&file->inst, cursor, version, 0);
GO_FORWARD(ins_size);
return WOPL_ERR_OK;
#undef GO_FORWARD
}