diff options
author | Wohlstand <admin@wohlnet.ru> | 2017-11-01 20:53:42 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2017-11-01 20:53:42 +0300 |
commit | 5177f65bab98b5b72bded7594af3680c1766bdb3 (patch) | |
tree | 315b3e3b82b48e73bcf4fd546ac2e18288dc6954 /src | |
parent | 39adce26ad639f180b3cb5742215e44c322bf015 (diff) | |
download | libADLMIDI-5177f65bab98b5b72bded7594af3680c1766bdb3.tar.gz libADLMIDI-5177f65bab98b5b72bded7594af3680c1766bdb3.tar.bz2 libADLMIDI-5177f65bab98b5b72bded7594af3680c1766bdb3.zip |
Added hooks and meta-info: title, copyright, track titles and markers
Diffstat (limited to 'src')
-rw-r--r-- | src/adlmidi.cpp | 92 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 126 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 427 |
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); |