aboutsummaryrefslogtreecommitdiff
path: root/src/adlmidi_private.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/adlmidi_private.hpp')
-rw-r--r--src/adlmidi_private.hpp274
1 files changed, 104 insertions, 170 deletions
diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp
index 9fd6f97..2499bad 100644
--- a/src/adlmidi_private.hpp
+++ b/src/adlmidi_private.hpp
@@ -35,6 +35,9 @@
# endif
#endif
+// Require declarations of unstable API for extern "C"
+#define ADLMIDI_UNSTABLE_API
+
#ifdef _WIN32
#define NOMINMAX
#endif
@@ -88,17 +91,13 @@ typedef int32_t ssize_t;
#include <cstdarg>
#include <cstdio>
#include <cassert>
-#if !(defined(__APPLE__) && defined(__GLIBCXX__)) && !defined(__ANDROID__)
-#include <cinttypes> //PRId32, PRIu32, etc.
-#else
-#include <inttypes.h>
-#endif
#include <vector> // vector
#include <deque> // deque
#include <cmath> // exp, log, ceil
#if defined(__WATCOMC__)
#include <math.h> // round, sqrt
#endif
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits> // numeric_limit
@@ -110,11 +109,26 @@ typedef int32_t ssize_t;
#include <deque>
#include <algorithm>
-#ifdef _MSC_VER
-#pragma warning(disable:4319)
-#pragma warning(disable:4267)
-#pragma warning(disable:4244)
-#pragma warning(disable:4146)
+/*
+ * Workaround for some compilers are has no those macros in their headers!
+ */
+#ifndef INT8_MIN
+#define INT8_MIN (-0x7f - 1)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-0x7fff - 1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-0x7fffffff - 1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX 0x7f
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX 0x7fff
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
#endif
#include "fraction.hpp"
@@ -127,6 +141,8 @@ typedef int32_t ssize_t;
#ifndef ADLMIDI_DISABLE_CPP_EXTRAS
#include "adlmidi.hpp" //Extra C++ API
#endif
+#include "adlmidi_ptr.hpp"
+#include "adlmidi_bankmap.h"
#define ADL_UNUSED(x) (void)x
@@ -144,12 +160,14 @@ inline Real adl_cvtReal(int32_t x)
{
return x * ((Real)1 / INT16_MAX);
}
+
inline int32_t adl_cvtS16(int32_t x)
{
- x = (x < INT16_MIN) ? INT16_MIN : x;
- x = (x > INT16_MAX) ? INT16_MAX : x;
+ x = (x < INT16_MIN) ? (INT16_MIN) : x;
+ x = (x > INT16_MAX) ? (INT16_MAX) : x;
return x;
}
+
inline int32_t adl_cvtS8(int32_t x)
{
return adl_cvtS16(x) / 256;
@@ -181,117 +199,6 @@ inline int32_t adl_cvtU32(int32_t x)
return (uint32_t)adl_cvtS32(x) - (uint32_t)INT32_MIN;
}
-/*
- Smart pointer for C heaps, created with malloc() call.
- FAQ: Why not std::shared_ptr? Because of Android NDK now doesn't supports it
-*/
-template<class PTR>
-class AdlMIDI_CPtr
-{
- PTR *m_p;
-public:
- AdlMIDI_CPtr() : m_p(NULL) {}
- ~AdlMIDI_CPtr()
- {
- reset(NULL);
- }
-
- void reset(PTR *p = NULL)
- {
- if(p != m_p) {
- if(m_p)
- free(m_p);
- m_p = p;
- }
- }
-
- PTR *get()
- {
- return m_p;
- }
- PTR &operator*()
- {
- return *m_p;
- }
- PTR *operator->()
- {
- return m_p;
- }
-private:
- AdlMIDI_CPtr(const AdlMIDI_CPtr &);
- AdlMIDI_CPtr &operator=(const AdlMIDI_CPtr &);
-};
-
-/*
- Shared pointer with non-atomic counter
- FAQ: Why not std::shared_ptr? Because of Android NDK now doesn't supports it
-*/
-template<class VALUE>
-class AdlMIDI_SPtr
-{
- VALUE *m_p;
- size_t *m_counter;
-public:
- AdlMIDI_SPtr() : m_p(NULL), m_counter(NULL) {}
- ~AdlMIDI_SPtr()
- {
- reset(NULL);
- }
-
- AdlMIDI_SPtr(const AdlMIDI_SPtr &other)
- : m_p(other.m_p), m_counter(other.m_counter)
- {
- if(m_counter)
- ++*m_counter;
- }
-
- AdlMIDI_SPtr &operator=(const AdlMIDI_SPtr &other)
- {
- if(this == &other)
- return *this;
- reset();
- m_p = other.m_p;
- m_counter = other.m_counter;
- if(m_counter)
- ++*m_counter;
- return *this;
- }
-
- void reset(VALUE *p = NULL)
- {
- if(p != m_p) {
- if(m_p && --*m_counter == 0)
- delete m_p;
- m_p = p;
- if(!p) {
- if(m_counter) {
- delete m_counter;
- m_counter = NULL;
- }
- }
- else
- {
- if(!m_counter)
- m_counter = new size_t;
- *m_counter = 1;
- }
- }
- }
-
- VALUE *get()
- {
- return m_p;
- }
- VALUE &operator*()
- {
- return *m_p;
- }
- VALUE *operator->()
- {
- return m_p;
- }
-};
-
class MIDIplay;
struct ADL_MIDIPlayer;
class OPL3
@@ -306,27 +213,23 @@ public:
std::vector<AdlMIDI_SPtr<OPLChipBase > > cardsOP2;
#endif
private:
- std::vector<size_t> ins; // index to adl[], cached, needed by Touch()
+ std::vector<adldata> ins; // patch data, cached, needed by Touch()
std::vector<uint8_t> pit; // value poked to B0, cached, needed by NoteOff)(
std::vector<uint8_t> regBD;
friend int adlRefreshNumCards(ADL_MIDIPlayer *device);
- //! Meta information about every instrument
- std::vector<adlinsdata> dynamic_metainstruments; // Replaces adlins[] when CMF file
- //! Raw instrument data ready to be sent to the chip
- std::vector<adldata> dynamic_instruments; // Replaces adl[] when CMF file
- size_t dynamic_percussion_offset;
-
- typedef std::map<uint16_t, size_t> BankMap;
- BankMap dynamic_melodic_banks;
- BankMap dynamic_percussion_banks;
- const unsigned DynamicInstrumentTag /* = 0x8000u*/,
- DynamicMetaInstrumentTag /* = 0x4000000u*/;
- const adlinsdata &GetAdlMetaIns(size_t n);
- size_t GetAdlMetaNumber(size_t midiins);
- const adldata &GetAdlIns(size_t insno);
+public:
+ struct Bank
+ {
+ adlinsdata2 ins[128];
+ };
+ typedef BasicBankMap<Bank> BankMap;
+ BankMap dynamic_banks;
+ AdlBankSetup dynamic_bank_setup;
public:
void setEmbeddedBank(unsigned int bank);
+ static const adlinsdata2 emptyInstrument;
+ enum { PercussionTag = 1 << 15 };
//! Total number of running concurrent emulated chips
unsigned int NumCards;
@@ -342,8 +245,8 @@ public:
bool AdlPercussionMode;
//! Carriers-only are scaled by default by volume level. This flag will tell to scale modulators too.
bool ScaleModulators;
- //! Required to play CMF files. Can be turned on by using of "CMF" volume model
- bool LogarithmicVolumes;
+ // ! Required to play CMF files. Can be turned on by using of "CMF" volume model
+ //bool LogarithmicVolumes; //[REPLACED WITH "m_volumeScale == VOLUME_NATIVE", DEPRECATED!!!]
// ! Required to play EA-MUS files [REPLACED WITH "m_musicMode", DEPRECATED!!!]
//bool CartoonersVolumes;
enum MusicMode
@@ -359,7 +262,7 @@ public:
enum VolumesScale
{
VOLUME_Generic,
- VOLUME_CMF,
+ VOLUME_NATIVE,
VOLUME_DMX,
VOLUME_APOGEE,
VOLUME_9X
@@ -375,15 +278,14 @@ public:
// 7 = percussion Hihat
// 8 = percussion slave
- void Poke(size_t card, uint32_t index, uint32_t value);
- void PokeN(size_t card, uint16_t index, uint8_t value);
+ void Poke(size_t card, uint16_t index, uint8_t value);
void NoteOff(size_t c);
void NoteOn(unsigned c, double hertz);
void Touch_Real(unsigned c, unsigned volume, uint8_t brightness = 127);
//void Touch(unsigned c, unsigned volume)
- void Patch(uint16_t c, size_t i);
+ void Patch(uint16_t c, const adldata &adli);
void Pan(unsigned c, unsigned value);
void Silence();
void updateFlags();
@@ -578,7 +480,7 @@ public:
bool eof()
{
if(fp)
- return std::feof(fp);
+ return (std::feof(fp) != 0);
else
return mp_tell >= mp_size;
}
@@ -596,9 +498,15 @@ public:
uint8_t bank_lsb, bank_msb;
uint8_t patch;
uint8_t volume, expression;
- uint8_t panning, vibrato, sustain;
+ uint8_t panning, vibrato, aftertouch, sustain;
+ //! Per note Aftertouch values
+ uint8_t noteAftertouch[128];
+ //! Is note aftertouch has any non-zero value
+ bool noteAfterTouchInUse;
char ____padding[6];
- double bend, bendsense;
+ int bend;
+ double bendsense;
+ int bendsense_lsb, bendsense_msb;
double vibpos, vibspeed, vibdepth;
int64_t vibdelay;
uint8_t lastlrpn, lastmrpn;
@@ -611,14 +519,15 @@ public:
bool active;
// Current pressure
uint8_t vol;
- char ____padding[1];
+ // Note vibrato (a part of Note Aftertouch feature)
+ uint8_t vibrato;
// Tone selected on noteon:
int16_t tone;
char ____padding2[4];
- // Patch selected on noteon; index to banks[AdlBank][]
+ // Patch selected on noteon; index to bank.ins[]
size_t midiins;
- // Index to physical adlib data structure, adlins[]
- size_t insmeta;
+ // Patch selected
+ const adlinsdata2 *ains;
enum
{
MaxNumPhysChans = 2,
@@ -629,18 +538,18 @@ public:
//! Destination chip channel
uint16_t chip_chan;
//! ins, inde to adl[]
- size_t insId;
+ adldata ains;
//! Is this voice must be detunable?
bool pseudo4op;
void assign(const Phys &oth)
{
- insId = oth.insId;
+ ains = oth.ains;
pseudo4op = oth.pseudo4op;
}
bool operator==(const Phys &oth) const
{
- return (insId == oth.insId) && (pseudo4op == oth.pseudo4op);
+ return (ains == oth.ains) && (pseudo4op == oth.pseudo4op);
}
bool operator!=(const Phys &oth) const
{
@@ -660,7 +569,7 @@ public:
ph = &chip_channels[i];
return ph;
}
- Phys *phys_find_or_create(unsigned chip_chan)
+ Phys *phys_find_or_create(uint16_t chip_chan)
{
Phys *ph = phys_find(chip_chan);
if(!ph) {
@@ -671,7 +580,7 @@ public:
}
return ph;
}
- Phys *phys_ensure_find_or_create(unsigned chip_chan)
+ Phys *phys_ensure_find_or_create(uint16_t chip_chan)
{
Phys *ph = phys_find_or_create(chip_chan);
assert(ph);
@@ -679,9 +588,9 @@ public:
}
void phys_erase_at(const Phys *ph)
{
- unsigned pos = ph - chip_channels;
- assert(pos < chip_channels_count);
- for(unsigned i = pos + 1; i < chip_channels_count; ++i)
+ intptr_t pos = ph - chip_channels;
+ assert(pos < static_cast<intptr_t>(chip_channels_count));
+ for(intptr_t i = pos + 1; i < static_cast<intptr_t>(chip_channels_count); ++i)
chip_channels[i - 1] = chip_channels[i];
--chip_channels_count;
}
@@ -707,7 +616,7 @@ public:
for(++ptr; ptr && !ptr->active;)
ptr = (ptr->note == 127) ? 0 : (ptr + 1);
return *this;
- };
+ }
activenoteiterator operator++(int)
{
activenoteiterator pos = *this;
@@ -770,7 +679,7 @@ public:
void activenotes_clear()
{
- for(unsigned i = 0; i < 128; ++i) {
+ for(uint8_t i = 0; i < 128; ++i) {
activenotes[i].note = i;
activenotes[i].active = false;
}
@@ -790,12 +699,17 @@ public:
}
void resetAllControllers()
{
- bend = 0.0;
- bendsense = 2 / 8192.0;
+ bend = 0;
+ bendsense_msb = 2;
+ bendsense_lsb = 0;
+ updateBendSensitivity();
volume = 100;
expression = 127;
sustain = 0;
vibrato = 0;
+ aftertouch = 0;
+ std::memset(noteAftertouch, 0, 128);
+ noteAfterTouchInUse = false;
vibspeed = 2 * 3.141592653 * 5.0;
vibdepth = 0.5 / 127;
vibdelay = 0;
@@ -803,6 +717,15 @@ public:
portamento = 0;
brightness = 127;
}
+ bool hasVibrato()
+ {
+ return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse;
+ }
+ void updateBendSensitivity()
+ {
+ int cent = bendsense_msb * 128 + bendsense_lsb;
+ bendsense = cent * (1.0 / (128 * 8192));
+ }
MIDIchannel()
{
activenotes_clear();
@@ -829,6 +752,9 @@ public:
bool sustained;
char ____padding[7];
MIDIchannel::NoteInfo::Phys ins; // a copy of that in phys[]
+ //! Has fixed sustain, don't iterate "on" timeout
+ bool fixed_sustain;
+ //! Timeout until note will be allowed to be killed by channel manager while it is on
int64_t kon_time_until_neglible;
int64_t vibdelay;
};
@@ -858,15 +784,21 @@ public:
AdlChannel(const AdlChannel &oth): koff_time_until_neglible(oth.koff_time_until_neglible)
{
- users_assign(oth.users_first, oth.users_size);
+ if(oth.users_first)
+ {
+ users_first = NULL;
+ users_assign(oth.users_first, oth.users_size);
+ }
+ else
+ users_clear();
}
AdlChannel &operator=(const AdlChannel &oth)
- {
- koff_time_until_neglible = oth.koff_time_until_neglible;
- users_assign(oth.users_first, oth.users_size);
- return *this;
- }
+ {
+ koff_time_until_neglible = oth.koff_time_until_neglible;
+ users_assign(oth.users_first, oth.users_size);
+ return *this;
+ }
void AddAge(int64_t ms);
};
@@ -1049,6 +981,8 @@ private:
char ____padding[7];
std::vector<AdlChannel> ch;
+ //! Counter of arpeggio processing
+ size_t m_arpeggioCounter;
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
std::vector<std::vector<uint8_t> > TrackData;
@@ -1272,7 +1206,7 @@ private:
// Determine how good a candidate this adlchannel
// would be for playing a note from this instrument.
- int64_t CalculateAdlChannelGoodness(unsigned c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t /*MidCh*/) const;
+ int64_t CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t /*MidCh*/) const;
// A new note will be played on this channel using this instrument.
// Kill existing notes on this channel (or don't, if we do arpeggio)