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
|
|
|
/*
|
|
|
|
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
|
|
|
*
|
|
|
|
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
|
|
|
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
|
|
|
*
|
|
|
|
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
|
|
|
* http://iki.fi/bisqwit/source/adlmidi.html
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "adlmidi_bankmap.h"
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline BasicBankMap<T>::BasicBankMap()
|
|
|
|
: m_freeslots(NULL),
|
|
|
|
m_size(0),
|
|
|
|
m_capacity(0)
|
|
|
|
{
|
|
|
|
m_buckets.reset(new Slot *[hash_buckets]());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline size_t BasicBankMap<T>::hash(key_type key)
|
|
|
|
{
|
|
|
|
// disregard the 0 high bit in LSB
|
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
|
|
|
key = key_type(key & 127) | key_type((key >> 8) << 7);
|
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
|
|
|
// take low part as hash value
|
|
|
|
return key & (hash_buckets - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::reserve(size_t capacity)
|
|
|
|
{
|
|
|
|
if(m_capacity >= capacity)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t need = capacity - m_capacity;
|
|
|
|
const size_t minalloc = static_cast<size_t>(minimum_allocation);
|
|
|
|
need = (need < minalloc) ? minalloc : need;
|
|
|
|
|
|
|
|
AdlMIDI_SPtrArray<Slot> slotz;
|
|
|
|
slotz.reset(new Slot[need]);
|
|
|
|
m_allocations.push_back(slotz);
|
|
|
|
m_capacity += need;
|
|
|
|
|
|
|
|
for(size_t i = need; i-- > 0;)
|
|
|
|
free_slot(&slotz[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::iterator
|
|
|
|
BasicBankMap<T>::begin() const
|
|
|
|
{
|
|
|
|
iterator it(m_buckets.get(), NULL, 0);
|
|
|
|
while(it.index < hash_buckets && !(it.slot = m_buckets[it.index]))
|
|
|
|
++it.index;
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::iterator
|
|
|
|
BasicBankMap<T>::end() const
|
|
|
|
{
|
|
|
|
iterator it(m_buckets.get(), NULL, hash_buckets);
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::iterator BasicBankMap<T>::find(key_type key)
|
|
|
|
{
|
|
|
|
size_t index = hash(key);
|
|
|
|
Slot *slot = bucket_find(index, key);
|
|
|
|
if(!slot)
|
|
|
|
return end();
|
|
|
|
return iterator(m_buckets.get(), slot, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::erase(iterator it)
|
|
|
|
{
|
|
|
|
bucket_remove(it.index, it.slot);
|
|
|
|
free_slot(it.slot);
|
|
|
|
--m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline BasicBankMap<T>::iterator::iterator()
|
|
|
|
: buckets(NULL), slot(NULL), index(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline BasicBankMap<T>::iterator::iterator(Slot **buckets, Slot *slot, size_t index)
|
|
|
|
: buckets(buckets), slot(slot), index(index)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::iterator &
|
|
|
|
BasicBankMap<T>::iterator::operator++()
|
|
|
|
{
|
|
|
|
if(slot->next)
|
|
|
|
slot = slot->next;
|
|
|
|
else {
|
|
|
|
Slot *slot = NULL;
|
|
|
|
++index;
|
|
|
|
while(index < hash_buckets && !(slot = buckets[index]))
|
|
|
|
++index;
|
|
|
|
this->slot = slot;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
bool BasicBankMap<T>::iterator::operator==(const iterator &o) const
|
|
|
|
{
|
|
|
|
return buckets == o.buckets && slot == o.slot && index == o.index;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline bool BasicBankMap<T>::iterator::operator!=(const iterator &o) const
|
|
|
|
{
|
|
|
|
return !operator==(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::iterator::to_ptrs(void *ptrs[3])
|
|
|
|
{
|
|
|
|
ptrs[0] = buckets;
|
|
|
|
ptrs[1] = slot;
|
|
|
|
ptrs[2] = (void *)index;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::iterator
|
|
|
|
BasicBankMap<T>::iterator::from_ptrs(void *const ptrs[3])
|
|
|
|
{
|
|
|
|
iterator it;
|
|
|
|
it.buckets = (Slot **)ptrs[0];
|
|
|
|
it.slot = (Slot *)ptrs[1];
|
|
|
|
it.index = (size_t)ptrs[2];
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
std::pair<typename BasicBankMap<T>::iterator, bool>
|
|
|
|
BasicBankMap<T>::insert(const value_type &value)
|
|
|
|
{
|
|
|
|
size_t index = hash(value.first);
|
|
|
|
Slot *slot = bucket_find(index, value.first);
|
|
|
|
if(slot)
|
|
|
|
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
|
|
|
|
slot = allocate_slot();
|
|
|
|
if(!slot) {
|
|
|
|
reserve(m_capacity + minimum_allocation);
|
|
|
|
slot = ensure_allocate_slot();
|
|
|
|
}
|
|
|
|
slot->value = value;
|
|
|
|
bucket_add(index, slot);
|
|
|
|
++m_size;
|
|
|
|
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
std::pair<typename BasicBankMap<T>::iterator, bool>
|
|
|
|
BasicBankMap<T>::insert(const value_type &value, do_not_expand_t)
|
|
|
|
{
|
|
|
|
size_t index = hash(value.first);
|
|
|
|
Slot *slot = bucket_find(index, value.first);
|
|
|
|
if(slot)
|
|
|
|
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
|
|
|
|
slot = allocate_slot();
|
|
|
|
if(!slot)
|
|
|
|
return std::make_pair(end(), false);
|
|
|
|
slot->value = value;
|
|
|
|
bucket_add(index, slot);
|
|
|
|
++m_size;
|
|
|
|
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::clear()
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < hash_buckets; ++i) {
|
|
|
|
Slot *slot = m_buckets[i];
|
|
|
|
while (Slot *cur = slot) {
|
|
|
|
slot = slot->next;
|
|
|
|
free_slot(cur);
|
|
|
|
}
|
|
|
|
m_buckets[i] = NULL;
|
|
|
|
}
|
|
|
|
m_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline T &BasicBankMap<T>::operator[](key_type key)
|
|
|
|
{
|
|
|
|
return insert(value_type(key, T())).first->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::Slot *
|
|
|
|
BasicBankMap<T>::allocate_slot()
|
|
|
|
{
|
|
|
|
Slot *slot = m_freeslots;
|
|
|
|
if(!slot)
|
|
|
|
return NULL;
|
|
|
|
Slot *next = slot->next;
|
|
|
|
if(next)
|
|
|
|
next->prev = NULL;
|
|
|
|
m_freeslots = next;
|
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline typename BasicBankMap<T>::Slot *
|
|
|
|
BasicBankMap<T>::ensure_allocate_slot()
|
|
|
|
{
|
|
|
|
Slot *slot = allocate_slot();
|
|
|
|
assert(slot);
|
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::free_slot(Slot *slot)
|
|
|
|
{
|
|
|
|
Slot *next = m_freeslots;
|
|
|
|
if(next)
|
|
|
|
next->prev = slot;
|
|
|
|
slot->prev = NULL;
|
|
|
|
slot->next = next;
|
|
|
|
m_freeslots = slot;
|
|
|
|
m_freeslots->value.second = T();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
typename BasicBankMap<T>::Slot *
|
|
|
|
BasicBankMap<T>::bucket_find(size_t index, key_type key)
|
|
|
|
{
|
|
|
|
Slot *slot = m_buckets[index];
|
|
|
|
while(slot && slot->value.first != key)
|
|
|
|
slot = slot->next;
|
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::bucket_add(size_t index, Slot *slot)
|
|
|
|
{
|
|
|
|
assert(slot);
|
|
|
|
Slot *next = m_buckets[index];
|
|
|
|
if(next)
|
|
|
|
next->prev = slot;
|
|
|
|
slot->next = next;
|
|
|
|
m_buckets[index] = slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void BasicBankMap<T>::bucket_remove(size_t index, Slot *slot)
|
|
|
|
{
|
|
|
|
assert(slot);
|
|
|
|
Slot *prev = slot->prev;
|
|
|
|
Slot *next = slot->next;
|
|
|
|
if(!prev)
|
|
|
|
m_buckets[index] = next;
|
|
|
|
else
|
|
|
|
prev->next = next;
|
|
|
|
if(next)
|
|
|
|
next->prev = prev;
|
|
|
|
}
|