aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/adlmidi.cpp92
-rw-r--r--src/adlmidi_midiplay.cpp126
-rw-r--r--src/adlmidi_private.hpp427
3 files changed, 414 insertions, 231 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp
index 0f0353c..8f07d72 100644
--- a/src/adlmidi.cpp
+++ b/src/adlmidi.cpp
@@ -355,6 +355,98 @@ ADLMIDI_EXPORT void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo)
}
+ADLMIDI_EXPORT const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device)
+{
+ if(!device)
+ return "";
+ return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musTitle.c_str();
+}
+
+
+ADLMIDI_EXPORT const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device)
+{
+ if(!device)
+ return "";
+ return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musCopyright.c_str();
+}
+
+ADLMIDI_EXPORT size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device)
+{
+ if(!device)
+ return 0;
+ return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musTrackTitles.size();
+}
+
+ADLMIDI_EXPORT const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index)
+{
+ if(!device)
+ return 0;
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ if(index >= play->musTrackTitles.size())
+ return "INVALID";
+ return play->musTrackTitles[index].c_str();
+}
+
+
+ADLMIDI_EXPORT size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device)
+{
+ if(!device)
+ return 0;
+ return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musMarkers.size();
+}
+
+ADLMIDI_EXPORT const Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index)
+{
+ struct Adl_MarkerEntry marker;
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ if(!device || !play || (index >= play->musMarkers.size()))
+ {
+ marker.label = "INVALID";
+ marker.pos_time = 0.0;
+ marker.pos_ticks = 0;
+ return marker;
+ }
+ else
+ {
+ MIDIplay::MIDI_MarkerEntry &mk = play->musMarkers[index];
+ marker.label = mk.label.c_str();
+ marker.pos_time = mk.pos_time;
+ marker.pos_ticks = mk.pos_ticks;
+ }
+ return marker;
+}
+
+ADLMIDI_EXPORT void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData)
+{
+ if(!device)
+ return;
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->hooks.onEvent = rawEventHook;
+ play->hooks.onEvent_userData = userData;
+}
+
+/* Set note hook */
+ADLMIDI_EXPORT void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook, void *userData)
+{
+ if(!device)
+ return;
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->hooks.onNote = noteHook;
+ play->hooks.onNote_userData = userData;
+}
+
+/* Set debug message hook */
+ADLMIDI_EXPORT void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData)
+{
+ if(!device)
+ return;
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->hooks.onDebugMessage = debugMessageHook;
+ play->hooks.onDebugMessage_userData = userData;
+}
+
+
+
inline static void SendStereoAudio(MIDIplay::Setup &device,
int &samples_requested,
ssize_t &in_size,
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index 577e8b8..0b721e9 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -192,6 +192,10 @@ bool MIDIplay::buildTrackData()
loopStartTime = -1.0;
loopEndTime = -1.0;
musTitle.clear();
+ musCopyright.clear();
+ musTrackTitles.clear();
+ musMarkers.clear();
+ caugh_missing_instruments.clear();
trackDataNew.clear();
const size_t trackCount = TrackData.size();
trackDataNew.resize(trackCount, MidiTrackQueue());
@@ -429,6 +433,21 @@ bool MIDIplay::buildTrackData()
pos.time = time;
time += pos.timeDelay;
+ //Capture markers after time value calculation
+ for(size_t i = 0; i < pos.events.size(); i++)
+ {
+ MidiEvent &e = pos.events[i];
+ if((e.type == MidiEvent::T_SPECIAL) && (e.subtype == MidiEvent::ST_MARKER))
+ {
+ MIDI_MarkerEntry marker;
+ marker.label = std::string((char*)e.data.data(), e.data.size());
+ marker.pos_ticks = pos.absPos;
+ marker.pos_time = pos.time;
+ musMarkers.push_back(marker);
+ }
+ }
+
+ //Capture loop points time positions
if(!invalidLoop)
{
// Set loop points times
@@ -765,12 +784,12 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
if((opl.AdlPercussionMode == 1) && PercussionMap[midiins & 0xFF]) i[1] = i[0];
- static std::set<uint8_t> missing_warnings;
-
- if(!missing_warnings.count(static_cast<uint8_t>(midiins)) && (ains.flags & adlinsdata::Flag_NoSound))
+ if(!caugh_missing_instruments.count(static_cast<uint8_t>(midiins)) && (ains.flags & adlinsdata::Flag_NoSound))
{
- //UI.PrintLn("[%i]Playing missing instrument %i", MidCh, midiins);
- missing_warnings.insert(static_cast<uint8_t>(midiins));
+ if(hooks.onDebugMessage)
+ hooks.onDebugMessage(hooks.onDebugMessage_userData,
+ "[%i] Playing missing instrument %i", channel, midiins);
+ caugh_missing_instruments.insert(static_cast<uint8_t>(midiins));
}
// Allocate AdLib channel (the physical sound channel for the note)
@@ -837,7 +856,8 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
if(c < 0)
{
- //UI.PrintLn("ignored unplaceable note");
+ if(hooks.onDebugMessage)
+ hooks.onDebugMessage(hooks.onDebugMessage_userData, "ignored unplaceable note");
continue; // Could not play this note. Ignore it.
}
@@ -851,7 +871,9 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
return false;
}
- //UI.PrintLn("i1=%d:%d, i2=%d:%d", i[0],adlchannel[0], i[1],adlchannel[1]);
+ //if(hooks.onDebugMessage)
+ // hooks.onDebugMessage(hooks.onDebugMessage_userData, "i1=%d:%d, i2=%d:%d", i[0],adlchannel[0], i[1],adlchannel[1]);
+
// Allocate active note for MIDI channel
std::pair<MIDIchannel::activenoteiterator, bool>
ir = Ch[channel].activenotes.insert(std::make_pair(note, MIDIchannel::NoteInfo()));
@@ -1090,7 +1112,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
MIDIchannel::NoteInfo &info = i->second;
const int16_t tone = info.tone;
const uint8_t vol = info.vol;
- //const int midiins = info.midiins;
+ const int midiins = info.midiins;
const uint32_t insmeta = info.insmeta;
const adlinsdata &ains = opl.GetAdlMetaIns(insmeta);
AdlChannel::Location my_loc;
@@ -1139,7 +1161,8 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
if(k != ch[c].users.end())
ch[c].users.erase(k);
- //UI.IllustrateNote(c, tone, midiins, 0, 0.0);
+ if(hooks.onNote)
+ hooks.onNote(hooks.onNote_userData, c, tone, midiins, 0, 0.0);
if(ch[c].users.empty())
{
@@ -1154,7 +1177,8 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
// Also will avoid overwriting it very soon.
AdlChannel::LocationData &d = ch[c].users[my_loc];
d.sustained = true; // note: not erased!
- //UI.IllustrateNote(c, tone, midiins, -1, 0.0);
+ if(hooks.onNote)
+ hooks.onNote(hooks.onNote_userData, c, tone, midiins, -1, 0.0);
}
info.phys.erase(j);
@@ -1266,6 +1290,8 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
#endif
opl.NoteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (tone + bend + phase)));
#undef BEND_COEFFICIENT
+ if(hooks.onNote)
+ hooks.onNote(hooks.onNote_userData, c, tone, midiins, vol, Ch[MidCh].bend);
}
}
}
@@ -1435,28 +1461,45 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, uint8_t *end, int &statu
* by external functions (to display song title and copyright in the player) */
if(evt.subtype == MidiEvent::ST_COPYRIGHT)
{
- //TODO: Implement own field for this
- //TODO: Implement API call to retreive this
- //TODO: Implement a hook to catch this
- std::string str((const char*)evt.data.data(), evt.data.size());
- std::fprintf(stdout, "Copyright: %s\n", str.c_str());
- std::fflush(stdout);
+ if(musCopyright.empty())
+ {
+ musCopyright = std::string((const char*)evt.data.data(), evt.data.size());
+ if(hooks.onDebugMessage)
+ hooks.onDebugMessage(hooks.onDebugMessage_userData, "Music copyright: %s", musCopyright.c_str());
+ }
+ else
+ if(hooks.onDebugMessage)
+ {
+ std::string str((const char*)evt.data.data(), evt.data.size());
+ hooks.onDebugMessage(hooks.onDebugMessage_userData, "Extra copyright event: %s", str.c_str());
+ }
}
else
if(evt.subtype == MidiEvent::ST_SQTRKTITLE)
{
- //TODO: Implement API call to retreive this
- //TODO: Implement a hook to catch this
if(musTitle.empty())
+ {
musTitle = std::string((const char*)evt.data.data(), evt.data.size());
+ if(hooks.onDebugMessage)
+ hooks.onDebugMessage(hooks.onDebugMessage_userData, "Music title: %s", musTitle.c_str());
+ }
+ else
+ if(hooks.onDebugMessage)
+ {
+ //TODO: Store track titles and associate them with each track and make API to retreive them
+ std::string str((const char*)evt.data.data(), evt.data.size());
+ musTrackTitles.push_back(str);
+ hooks.onDebugMessage(hooks.onDebugMessage_userData, "Track title: %s", str.c_str());
+ }
}
else
if(evt.subtype == MidiEvent::ST_INSTRTITLE)
{
- //TODO: Implement a hook to catch this
- std::string str((const char*)evt.data.data(), evt.data.size());
- std::fprintf(stdout, "Instrument: %s\n", str.c_str());
- std::fflush(stdout);
+ if(hooks.onDebugMessage)
+ {
+ std::string str((const char*)evt.data.data(), evt.data.size());
+ hooks.onDebugMessage(hooks.onDebugMessage_userData, "Instrument: %s", str.c_str());
+ }
}
else
if(evt.subtype == MidiEvent::ST_MARKER)
@@ -1577,6 +1620,16 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, uint8_t *end, int &statu
void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
{
+ if(hooks.onEvent)
+ {
+ hooks.onEvent(hooks.onEvent_userData,
+ evt.type,
+ evt.subtype,
+ evt.channel,
+ evt.data.data(),
+ evt.data.size());
+ }
+
if(evt.type == MidiEvent::T_SYSEX || evt.type == MidiEvent::T_SYSEX2) // Ignore SysEx
{
//std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length );
@@ -1875,17 +1928,19 @@ void MIDIplay::KillOrEvacuate(size_t from_channel, AdlChannel::users_t::iterator
if(m->second.ins != j->second.ins) continue;
- // the note can be moved here!
- // UI.IllustrateNote(
- // from_channel,
- // i->second.tone,
- // i->second.midiins, 0, 0.0);
- // UI.IllustrateNote(
- // c,
- // i->second.tone,
- // i->second.midiins,
- // i->second.vol,
- // 0.0);
+ if(hooks.onNote)
+ {
+ hooks.onNote(hooks.onNote_userData,
+ from_channel,
+ i->second.tone,
+ i->second.midiins, 0, 0.0);
+ hooks.onNote(hooks.onNote_userData,
+ c,
+ i->second.tone,
+ i->second.midiins,
+ i->second.vol, 0.0);
+ }
+
i->second.phys.erase(static_cast<uint16_t>(from_channel));
i->second.phys[cs] = j->second.ins;
ch[cs].users.insert(*j);
@@ -1941,8 +1996,9 @@ void MIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn)
if((MidCh < 0 || j->first.MidCh == MidCh)
&& j->second.sustained)
{
- //int midiins = '?';
- //UI.IllustrateNote(c, j->first.note, midiins, 0, 0.0);
+ int midiins = '?';
+ if(hooks.onNote)
+ hooks.onNote(hooks.onNote_userData, c, j->first.note, midiins, 0, 0.0);
ch[c].users.erase(j);
}
}
diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp
index 622e9f2..7defa1e 100644
--- a/src/adlmidi_private.hpp
+++ b/src/adlmidi_private.hpp
@@ -194,6 +194,14 @@ public:
*/
struct MIDIEventHooks
{
+ MIDIEventHooks() :
+ onEvent(NULL),
+ onEvent_userData(NULL),
+ onNote(NULL),
+ onNote_userData(NULL),
+ onDebugMessage(NULL),
+ onDebugMessage_userData(NULL)
+ {}
//! Raw MIDI event hook
typedef void (*RawEventHook)(void *userdata, uint8_t type, uint8_t subtype, uint8_t channel, uint8_t *data, size_t len);
RawEventHook onEvent;
@@ -212,8 +220,165 @@ struct MIDIEventHooks
class MIDIplay
{
- std::map<std::string, uint64_t> devices;
- std::map<uint64_t /*track*/, uint64_t /*channel begin index*/> current_device;
+public:
+ MIDIplay();
+
+ ~MIDIplay()
+ {}
+
+ /**********************Internal structures and classes**********************/
+
+ /**
+ * @brief A little class gives able to read filedata from disk and also from a memory segment
+ */
+ class fileReader
+ {
+ public:
+ enum relTo
+ {
+ SET = 0,
+ CUR = 1,
+ END = 2
+ };
+
+ fileReader()
+ {
+ fp = NULL;
+ mp = NULL;
+ mp_size = 0;
+ mp_tell = 0;
+ }
+ ~fileReader()
+ {
+ close();
+ }
+
+ void openFile(const char *path)
+ {
+ #ifndef _WIN32
+ fp = std::fopen(path, "rb");
+ #else
+ wchar_t widePath[MAX_PATH];
+ int size = MultiByteToWideChar(CP_UTF8, 0, path, (int)std::strlen(path), widePath, MAX_PATH);
+ widePath[size] = '\0';
+ fp = _wfopen(widePath, L"rb");
+ #endif
+ _fileName = path;
+ mp = NULL;
+ mp_size = 0;
+ mp_tell = 0;
+ }
+
+ void openData(void *mem, size_t lenght)
+ {
+ fp = NULL;
+ mp = mem;
+ mp_size = lenght;
+ mp_tell = 0;
+ }
+
+ void seek(long pos, int rel_to)
+ {
+ if(fp)
+ std::fseek(fp, pos, rel_to);
+ else
+ {
+ switch(rel_to)
+ {
+ case SET:
+ mp_tell = static_cast<size_t>(pos);
+ break;
+
+ case END:
+ mp_tell = mp_size - static_cast<size_t>(pos);
+ break;
+
+ case CUR:
+ mp_tell = mp_tell + static_cast<size_t>(pos);
+ break;
+ }
+
+ if(mp_tell > mp_size)
+ mp_tell = mp_size;
+ }
+ }
+
+ inline void seeku(uint64_t pos, int rel_to)
+ {
+ seek(static_cast<long>(pos), rel_to);
+ }
+
+ size_t read(void *buf, size_t num, size_t size)
+ {
+ if(fp)
+ return std::fread(buf, num, size, fp);
+ else
+ {
+ size_t pos = 0;
+ size_t maxSize = static_cast<size_t>(size * num);
+
+ while((pos < maxSize) && (mp_tell < mp_size))
+ {
+ reinterpret_cast<unsigned char *>(buf)[pos] = reinterpret_cast<unsigned char *>(mp)[mp_tell];
+ mp_tell++;
+ pos++;
+ }
+
+ return pos;
+ }
+ }
+
+ int getc()
+ {
+ if(fp)
+ return std::getc(fp);
+ else
+ {
+ if(mp_tell >= mp_size)
+ return -1;
+
+ int x = reinterpret_cast<unsigned char *>(mp)[mp_tell];
+ mp_tell++;
+ return x;
+ }
+ }
+
+ size_t tell()
+ {
+ if(fp)
+ return static_cast<size_t>(std::ftell(fp));
+ else
+ return mp_tell;
+ }
+
+ void close()
+ {
+ if(fp) std::fclose(fp);
+
+ fp = NULL;
+ mp = NULL;
+ mp_size = 0;
+ mp_tell = 0;
+ }
+
+ bool isValid()
+ {
+ return (fp) || (mp);
+ }
+
+ bool eof()
+ {
+ if(fp)
+ return std::feof(fp);
+ else
+ return mp_tell >= mp_size;
+ }
+ std::string _fileName;
+ std::FILE *fp;
+ void *mp;
+ size_t mp_size;
+ size_t mp_tell;
+ };
// Persistent settings for each MIDI channel
struct MIDIchannel
@@ -261,8 +426,6 @@ class MIDIplay
lastlrpn(0), lastmrpn(0), nrpn(false),
activenotes() { }
};
- std::vector<MIDIchannel> Ch;
- bool cmf_percussion_mode;
// Additional information about AdLib channels
struct AdlChannel
@@ -301,12 +464,6 @@ class MIDIplay
void AddAge(int64_t ms);
};
- //Padding to fix CLanc code model's warning
- char ____padding[7];
-
- std::vector<AdlChannel> ch;
- std::vector<std::vector<uint8_t> > TrackData;
-
/**
* @brief MIDI Event utility container
*/
@@ -430,7 +587,62 @@ class MIDIplay
std::vector<TrackInfo> track;
PositionNew(): began(false), wait(0.0), absTimePosition(0.0), track()
{}
- } CurrentPositionNew, LoopBeginPositionNew, trackBeginPositionNew;
+ };
+
+ struct Setup
+ {
+ unsigned int AdlBank;
+ unsigned int NumFourOps;
+ unsigned int NumCards;
+ bool HighTremoloMode;
+ bool HighVibratoMode;
+ bool AdlPercussionMode;
+ bool LogarithmicVolumes;
+ int VolumeModel;
+ unsigned int SkipForward;
+ bool loopingIsEnabled;
+ bool ScaleModulators;
+
+ double delay;
+ double carry;
+
+ /* The lag between visual content and audio content equals */
+ /* the sum of these two buffers. */
+ double mindelay;
+ double maxdelay;
+
+ /* For internal usage */
+ ssize_t stored_samples; /* num of collected samples */
+ short backup_samples[1024]; /* Backup sample storage. */
+ ssize_t backup_samples_size; /* Backup sample storage. */
+ /* For internal usage */
+
+ unsigned long PCM_RATE;
+ };
+
+ struct MIDI_MarkerEntry
+ {
+ std::string label;
+ double pos_time;
+ unsigned long pos_ticks;
+ };
+
+ std::vector<MIDIchannel> Ch;
+ bool cmf_percussion_mode;
+
+ MIDIEventHooks hooks;
+
+private:
+ std::map<std::string, uint64_t> devices;
+ std::map<uint64_t /*track*/, uint64_t /*channel begin index*/> current_device;
+
+ //Padding to fix CLanc code model's warning
+ char ____padding[7];
+
+ std::vector<AdlChannel> ch;
+ std::vector<std::vector<uint8_t> > TrackData;
+
+ PositionNew CurrentPositionNew, LoopBeginPositionNew, trackBeginPositionNew;
//! Full song length in seconds
double fullSongTimeLength;
@@ -447,6 +659,9 @@ class MIDIplay
//! Pre-processed track data storage
std::vector<MidiTrackQueue > trackDataNew;
+ //! Missing instruments catches
+ std::set<uint8_t> caugh_missing_instruments;
+
/**
* @brief Build MIDI track data from the raw track data storage
* @return true if everything successfully processed, or false on any error
@@ -463,11 +678,12 @@ class MIDIplay
MidiEvent parseEvent(uint8_t **ptr, uint8_t *end, int &status);
public:
- MIDIplay();
- ~MIDIplay()
- {}
std::string musTitle;
+ std::string musCopyright;
+ std::vector<std::string> musTrackTitles;
+ std::vector<MIDI_MarkerEntry> musMarkers;
+
fraction<uint64_t> InvDeltaTicks, Tempo;
//! Tempo multiplier
double tempoMultiplier;
@@ -481,36 +697,7 @@ public:
int16_t outBuf[1024];
- struct Setup
- {
- unsigned int AdlBank;
- unsigned int NumFourOps;
- unsigned int NumCards;
- bool HighTremoloMode;
- bool HighVibratoMode;
- bool AdlPercussionMode;
- bool LogarithmicVolumes;
- int VolumeModel;
- unsigned int SkipForward;
- bool loopingIsEnabled;
- bool ScaleModulators;
-
- double delay;
- double carry;
-
- /* The lag between visual content and audio content equals */
- /* the sum of these two buffers. */
- double mindelay;
- double maxdelay;
-
- /* For internal usage */
- ssize_t stored_samples; /* num of collected samples */
- short backup_samples[1024]; /* Backup sample storage. */
- ssize_t backup_samples_size; /* Backup sample storage. */
- /* For internal usage */
-
- unsigned long PCM_RATE;
- } m_setup;
+ Setup m_setup;
static uint64_t ReadBEint(const void *buffer, size_t nbytes);
static uint64_t ReadLEint(const void *buffer, size_t nbytes);
@@ -530,158 +717,6 @@ public:
*/
uint64_t ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok);
- /*
- * A little class gives able to read filedata from disk and also from a memory segment
- */
- class fileReader
- {
- public:
- enum relTo
- {
- SET = 0,
- CUR = 1,
- END = 2
- };
-
- fileReader()
- {
- fp = NULL;
- mp = NULL;
- mp_size = 0;
- mp_tell = 0;
- }
- ~fileReader()
- {
- close();
- }
-
- void openFile(const char *path)
- {
- #ifndef _WIN32
- fp = std::fopen(path, "rb");
- #else
- wchar_t widePath[MAX_PATH];
- int size = MultiByteToWideChar(CP_UTF8, 0, path, (int)std::strlen(path), widePath, MAX_PATH);
- widePath[size] = '\0';
- fp = _wfopen(widePath, L"rb");
- #endif
- _fileName = path;
- mp = NULL;
- mp_size = 0;
- mp_tell = 0;
- }
-
- void openData(void *mem, size_t lenght)
- {
- fp = NULL;
- mp = mem;
- mp_size = lenght;
- mp_tell = 0;
- }
-
- void seek(long pos, int rel_to)
- {
- if(fp)
- std::fseek(fp, pos, rel_to);
- else
- {
- switch(rel_to)
- {
- case SET:
- mp_tell = static_cast<size_t>(pos);
- break;
-
- case END:
- mp_tell = mp_size - static_cast<size_t>(pos);
- break;
-
- case CUR:
- mp_tell = mp_tell + static_cast<size_t>(pos);
- break;
- }
-
- if(mp_tell > mp_size)
- mp_tell = mp_size;
- }
- }
-
- inline void seeku(uint64_t pos, int rel_to)
- {
- seek(static_cast<long>(pos), rel_to);
- }
-
- size_t read(void *buf, size_t num, size_t size)
- {
- if(fp)
- return std::fread(buf, num, size, fp);
- else
- {
- size_t pos = 0;
- size_t maxSize = static_cast<size_t>(size * num);
-
- while((pos < maxSize) && (mp_tell < mp_size))
- {
- reinterpret_cast<unsigned char *>(buf)[pos] = reinterpret_cast<unsigned char *>(mp)[mp_tell];
- mp_tell++;
- pos++;
- }
-
- return pos;
- }
- }
-
- int getc()
- {
- if(fp)
- return std::getc(fp);
- else
- {
- if(mp_tell >= mp_size)
- return -1;
-
- int x = reinterpret_cast<unsigned char *>(mp)[mp_tell];
- mp_tell++;
- return x;
- }
- }
-
- size_t tell()
- {
- if(fp)
- return static_cast<size_t>(std::ftell(fp));
- else
- return mp_tell;
- }
-
- void close()
- {
- if(fp) std::fclose(fp);
-
- fp = NULL;
- mp = NULL;
- mp_size = 0;
- mp_tell = 0;
- }
-
- bool isValid()
- {
- return (fp) || (mp);
- }
-
- bool eof()
- {
- if(fp)
- return std::feof(fp);
- else
- return mp_tell >= mp_size;
- }
- std::string _fileName;
- std::FILE *fp;
- void *mp;
- size_t mp_size;
- size_t mp_tell;
- };
-
bool LoadBank(const std::string &filename);
bool LoadBank(void *data, unsigned long size);
bool LoadBank(fileReader &fr);