diff options
-rw-r--r-- | include/adlmidi.h | 65 | ||||
-rw-r--r-- | libADLMIDI-test.pro | 1 | ||||
-rw-r--r-- | src/adlmidi.cpp | 92 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 126 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 427 | ||||
-rw-r--r-- | utils/midiplay/adlmidiplay.cpp | 32 |
6 files changed, 511 insertions, 232 deletions
diff --git a/include/adlmidi.h b/include/adlmidi.h index 634a22a..2c3abf4 100644 --- a/include/adlmidi.h +++ b/include/adlmidi.h @@ -28,6 +28,21 @@ extern "C" { #endif +#include <stddef.h> + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#include <stdint.h> +typedef uint8_t ADL_UInt8; +typedef uint16_t ADL_Uint16; +typedef int8_t ADL_Sint8; +typedef int16_t ADL_Sint16; +#else +typedef unsigned char ADL_UInt8; +typedef unsigned short ADL_Uint16; +typedef char ADL_Sint8; +typedef short ADL_Sint16; +#endif + enum ADLMIDI_VolumeModels { ADLMIDI_VolumeModel_AUTO = 0, @@ -128,8 +143,56 @@ extern void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo); /*Close and delete ADLMIDI device*/ extern void adl_close(struct ADL_MIDIPlayer *device); + + +/**META**/ + +/*Returns string which contains a music title*/ +extern const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device); + +/*Returns string which contains a copyright string*/ +extern const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device); + +/*Returns count of available track titles: NOTE: there are CAN'T be associated with channel in any of event or note hooks */ +extern size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device); + +/*Get track title by index*/ +extern const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index); + +struct Adl_MarkerEntry +{ + const char *label; + double pos_time; + unsigned long pos_ticks; +}; + +/*Returns count of available markers*/ +extern size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device); + +/*Returns the marker entry*/ +extern const struct Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index); + + + + /*Take a sample buffer*/ -extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short out[]); +extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short out[]); + + +/**Hooks**/ + +typedef void (*ADL_RawEventHook)(void *userdata, ADL_UInt8 type, ADL_UInt8 subtype, ADL_UInt8 channel, ADL_UInt8 *data, size_t len); +typedef void (*ADL_NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); +typedef void (*ADL_DebugMessageHook)(void *userdata, const char *fmt, ...); + +/* Set raw MIDI event hook */ +extern void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData); + +/* Set note hook */ +extern void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook, void *userData); + +/* Set debug message hook */ +extern void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData); #ifdef __cplusplus } diff --git a/libADLMIDI-test.pro b/libADLMIDI-test.pro index 45313b4..9545a7b 100644 --- a/libADLMIDI-test.pro +++ b/libADLMIDI-test.pro @@ -18,6 +18,7 @@ LIBS += -lSDL2 -lpthread -ldl #DEFINES += DISABLE_EMBEDDED_BANKS #DEFINES += ADLMIDI_USE_DOSBOX_OPL #DEFINES += ENABLE_BEGIN_SILENCE_SKIPPING +#DEFINES += DEBUG_TRACE_ALL_EVENTS QMAKE_CFLAGS += -std=c90 -pedantic QMAKE_CXXFLAGS += -std=c++98 -pedantic 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); diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp index 8a94761..9719532 100644 --- a/utils/midiplay/adlmidiplay.cpp +++ b/utils/midiplay/adlmidiplay.cpp @@ -7,6 +7,7 @@ #include <cstdlib> #include <cstring> #include <deque> +#include <cstdarg> #include <signal.h> #define SDL_MAIN_HANDLED #include <SDL2/SDL.h> @@ -83,6 +84,29 @@ static void sighandler(int dum) stop = 1; } + +static void debugPrint(void * /*userdata*/, const char *fmt, ...) +{ + char buffer[4096]; + std::va_list args; + va_start(args, fmt); + int rc = std::vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + if(rc > 0) + { + std::fprintf(stdout, " - Debug: %s\n", buffer); + std::fflush(stdout); + } +} + +#ifdef DEBUG_TRACE_ALL_EVENTS +static void debugPrintEvent(void * /*userdata*/, ADL_UInt8 type, ADL_UInt8 subtype, ADL_UInt8 channel, ADL_UInt8 * /*data*/, size_t len) +{ + std::fprintf(stdout, " - E: 0x%02X 0x%02X %02d (%d)\n", type, subtype, channel, (int)len); + std::fflush(stdout); +} +#endif + int main(int argc, char **argv) { std::fprintf(stdout, "==========================================\n" @@ -168,6 +192,8 @@ int main(int argc, char **argv) return 1; } + adl_setDebugMessageHook(myDevice, debugPrint, NULL); + bool recordWave = false; int loopEnabled = 1; @@ -196,6 +222,10 @@ int main(int argc, char **argv) //Turn loop on/off (for WAV recording loop must be disabled!) adl_setLoopEnabled(myDevice, recordWave ? 0 : loopEnabled); + #ifdef DEBUG_TRACE_ALL_EVENTS + if(!recordWave) + adl_setRawEventHook(myDevice, debugPrintEvent, NULL); + #endif std::fprintf(stdout, " - %s OPL3 Emulator in use\n", adl_emulatorName()); @@ -306,9 +336,11 @@ int main(int argc, char **argv) if(got <= 0) break; + #ifndef DEBUG_TRACE_ALL_EVENTS std::fprintf(stdout, " \r"); std::fprintf(stdout, "Time position: %10f / %10f\r", adl_positionTell(myDevice), total); std::fflush(stdout); + #endif AudioBuffer_lock.Lock(); size_t pos = AudioBuffer.size(); |