From b4c4cefb706f9c43a54fecb18cb8ee50f0f0e19a Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Mon, 11 Nov 2019 23:38:09 +0800 Subject: New UI hook "main.seek". Fix SysExc. message sending. API documentation update. Simple visualization no longer have notes stuck after seeking. System exclusive messages longer than 256 bytes are now sent correctly. --- core/qmpmidioutfluid.cpp | 4 ++-- core/qmpmidioutfluid.hpp | 2 +- core/qmpmidioutrtmidi.cpp | 2 +- core/qmpmidioutrtmidi.hpp | 2 +- core/qmpmidiplay.cpp | 2 +- core/qmpmidiread.cpp | 4 ++-- doc/APIdoc.md | 22 +++++++--------------- include/qmpcorepublic.hpp | 2 +- qmidiplayer-desktop/qmpmainwindow.cpp | 2 ++ simple-visualization/simplevisualization.cpp | 2 ++ simple-visualization/simplevisualization.hpp | 1 + 11 files changed, 21 insertions(+), 24 deletions(-) diff --git a/core/qmpmidioutfluid.cpp b/core/qmpmidioutfluid.cpp index e9bc6b1..4fcdd21 100644 --- a/core/qmpmidioutfluid.cpp +++ b/core/qmpmidioutfluid.cpp @@ -69,10 +69,10 @@ void qmpMidiOutFluid::basicMessage(uint8_t type,uint8_t p1,uint8_t p2) break; } } -void qmpMidiOutFluid::extendedMessage(uint8_t length,const char *data) +void qmpMidiOutFluid::extendedMessage(uint32_t length,const char *data) { int rlen=0; - fluid_synth_sysex(synth,data,length,nullptr,&rlen,nullptr,0); + fluid_synth_sysex(synth,data,int(length),nullptr,&rlen,nullptr,0); } void qmpMidiOutFluid::rpnMessage(uint8_t ch,uint16_t type,uint16_t val) { diff --git a/core/qmpmidioutfluid.hpp b/core/qmpmidioutfluid.hpp index d6a62c9..6cd2058 100644 --- a/core/qmpmidioutfluid.hpp +++ b/core/qmpmidioutfluid.hpp @@ -33,7 +33,7 @@ class qmpMidiOutFluid:public qmpMidiOutDevice,public IFluidSettings void deviceDeinit(); void deviceDeinit(bool freshsettings); void basicMessage(uint8_t type,uint8_t p1,uint8_t p2); - void extendedMessage(uint8_t length,const char *data); + void extendedMessage(uint32_t length,const char *data); void rpnMessage(uint8_t ch,uint16_t type,uint16_t val); void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val); void panic(uint8_t ch); diff --git a/core/qmpmidioutrtmidi.cpp b/core/qmpmidioutrtmidi.cpp index 03b184d..6dc9ca6 100644 --- a/core/qmpmidioutrtmidi.cpp +++ b/core/qmpmidioutrtmidi.cpp @@ -201,7 +201,7 @@ void qmpMidiOutRtMidi::basicMessage(uint8_t type,uint8_t p1,uint8_t p2) msg.push_back(p2); outport->sendMessage(&msg); } -void qmpMidiOutRtMidi::extendedMessage(uint8_t length,const char *data) +void qmpMidiOutRtMidi::extendedMessage(uint32_t length,const char *data) { if(!outport||!outport->isPortOpen())return; std::vectormsg(data,data+length); diff --git a/core/qmpmidioutrtmidi.hpp b/core/qmpmidioutrtmidi.hpp index 8bb829c..2c9195c 100644 --- a/core/qmpmidioutrtmidi.hpp +++ b/core/qmpmidioutrtmidi.hpp @@ -31,7 +31,7 @@ public: void deviceInit(); void deviceDeinit(); void basicMessage(uint8_t type,uint8_t p1,uint8_t p2); - void extendedMessage(uint8_t length,const char *data); + void extendedMessage(uint32_t length,const char *data); void rpnMessage(uint8_t ch,uint16_t type,uint16_t val); void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val); void panic(uint8_t ch); diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index 2992e06..89fdf84 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -93,7 +93,7 @@ bool CMidiPlayer::processEvent(const SEvent *e) if(((e->type&0x0F)==0x00||(e->type&0x0F)==07)&&sendSysEx) for(auto& i:mididev) if(i.refcnt) - i.dev->extendedMessage(e->p1,e->str.c_str()); + i.dev->extendedMessage(uint32_t(e->str.length()),e->str.c_str()); return false; } return false; diff --git a/core/qmpmidiread.cpp b/core/qmpmidiread.cpp index 48a149d..697a5bd 100644 --- a/core/qmpmidiread.cpp +++ b/core/qmpmidiread.cpp @@ -147,7 +147,7 @@ int CSMFReader::read_event()//returns 0 if End of Track encountered str=new char[len+8]; if((type&0x0F)==0x00) { - str[0]=0xF0;++len; + str[0]=char(0xF0);++len; size_t sz=fread(str+1,1,len-1,f); if(szappendEvent(SEvent(curid,curt,type,len,0,str)); + curTrack->appendEvent(SEvent(curid,curt,type,0,0,std::string(str,len))); if(!strcmp(str,GM1SysX))ret->std=1; if(!strcmp(str,GM2SysX))ret->std=2; if(!strcmp(str,GSSysEx))ret->std=3; diff --git a/doc/APIdoc.md b/doc/APIdoc.md index 8e3a181..ec1eccb 100644 --- a/doc/APIdoc.md +++ b/doc/APIdoc.md @@ -51,7 +51,7 @@ Your plugin is expected to register handlers (hooks) and functionalities when `i and do clean-up jobs when `deinit()` is caled. Aside from the generic functionalities that you can add by implementing the class `qmpFuncBaseIntf`, -You can add these features to QMidiPlayer by implementing their corresponding classes: +You can also add these features to QMidiPlayer by implementing their corresponding classes: - MIDI File Reader (`qmpFileReader`) - MIDI Out Device (`qmpMidiOutDevice`) @@ -60,21 +60,22 @@ You can add these features to QMidiPlayer by implementing their corresponding cl - Event reader, after an event is read or after the whole file reading process is completed (via `(un)registerEventReaderIntf` and `(un)registerFileReadFinishedHandlerIntf`) -- Event handler, when an event is going to be sent by the player (via `(un)registerEventHandlerIntf`) +- Event handler, when an event is going to be sent (or already sent) by the player (via `(un)registerEventHandlerIntf`) - File read finished, when the entire file has been read. (via `(un)registerFileReadFinishedHandlerIntf`) - UIHooks, which are triggered by UI events. (via `(un)registerUIHook`) The first argument defines which event shall trigger the callback. All valid events are listed below: - * `main.stop`: stop button clicked, or playback stopped because end of track reached, or (oddly) switching tracks. + * `main.stop`: stop button clicked, or playback stopped because end of track reached, or (oddly) switching tracks. * `main.start`: track started playing (includes resuming from pause and switching tracks). * `main.pause`: playback paused * `main.reset`: (odd enough) when loading a new file + * `main.seek`: seeking happened Hooks use the universal `ICallBack` interface. Some of those also accept a pointer to a function (`callback_t`). When you register a hook, you provide the core with a instance of your class that implements the `ICallBack` interface and your `userdata` to be used when the core is calling the callback. When the callback is called, it will be fed with proper `callerdata` generated by the core and the `userdata` you provided. Type of `callerdata` varies by hooks. Event -reader and handler hooks have `SEventCallBackData*` as their `callerdata`. All other callbacks at this time have `nullptr` +reader and handler hooks have `SEvent*` as their `callerdata`. All other callbacks at this time have `nullptr` as their `callerdata`. **Don't try directly modifying the members of callerdata!** # 4. Functionalities @@ -128,8 +129,7 @@ yourself in the `deinit()` function of your plugin. 3. Do not throw exceptions to the core. The core doesn't handle exceptions and they will crash the entire program. Use the return value to indicate failure of a procedure instead. 4. The core does not handle MIDI running status, nor does it send events to any component with running status either. -That is to say, the `type` parameter found in `SEvent` and `SEventCallBackData` should always be greater than or equal to -0x80. +That is to say, the `type` parameter found in `SEvent` should always be greater than or equal to 0x80. # 7. Reference @@ -157,14 +157,6 @@ fills the event with the parameters given. - `friend bool operator <(const SEvent& a,const SEvent& b)` compares events by their timestamps. Ties are broken by comparing precedence in file. -### struct `SEventCallBackData` -A stripped down version of SEvent that is used to pass event data in APIs. - -- `uint32_t time` -- `uint32_t type` -- `uint32_t p1` -- `uint32_t p2` - ### class `CMidiTrack` Describes a single MIDI track. A MIDI track consists of multiple MIDI events. The order of events in `eventList` does not matter as long as the timestamps are correct. @@ -268,7 +260,7 @@ Deinitializes the device. - `virtual void basicMessage(uint8_t type,uint8_t p1,uint8_t p2)=0` Sends a basic midi message. Note that the core doesn't make use of running status. -- `virtual void extendedMessage(uint8_t length,const char* data)=0` +- `virtual void extendedMessage(uint32_t length,const char* data)=0` Sends an extended message. ("system exclusive message"). - `virtual void rpnMessage(uint8_t ch,uint16_t type,uint16_t val)=0` Sends a registered parameter number controller message. diff --git a/include/qmpcorepublic.hpp b/include/qmpcorepublic.hpp index 35a7a70..eda8933 100644 --- a/include/qmpcorepublic.hpp +++ b/include/qmpcorepublic.hpp @@ -87,7 +87,7 @@ class qmpMidiOutDevice virtual void deviceInit()=0; virtual void deviceDeinit()=0; virtual void basicMessage(uint8_t type,uint8_t p1,uint8_t p2)=0; - virtual void extendedMessage(uint8_t length,const char* data)=0; + virtual void extendedMessage(uint32_t length,const char* data)=0; virtual void rpnMessage(uint8_t ch,uint16_t type,uint16_t val)=0; virtual void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val)=0; virtual void panic(uint8_t ch)=0; diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp index 78230be..1715539 100644 --- a/qmidiplayer-desktop/qmpmainwindow.cpp +++ b/qmidiplayer-desktop/qmpmainwindow.cpp @@ -413,6 +413,7 @@ void qmpMainWindow::on_hsTimer_sliderPressed() void qmpMainWindow::on_hsTimer_sliderReleased() { dragging=false; + invokeCallback("main.seek",nullptr); if(playing) { if(ui->hsTimer->value()==100){on_pbNext_clicked();return;} @@ -437,6 +438,7 @@ void qmpMainWindow::playerSeek(uint32_t percentage) { if(percentage>100)percentage=100; if(percentage<0)percentage=0; + invokeCallback("main.seek",nullptr); if(playing) { if(percentage==100){on_pbNext_clicked();return;} diff --git a/simple-visualization/simplevisualization.cpp b/simple-visualization/simplevisualization.cpp index d45d101..71dac7a 100644 --- a/simple-visualization/simplevisualization.cpp +++ b/simple-visualization/simplevisualization.cpp @@ -14,12 +14,14 @@ void qmpSimpleVisualization::init() } p=new qmpKeyboardWindow(api,(QWidget*)api->getMainWindow()); uihs=api->registerUIHook("main.stop",[this](const void*,void*){this->p->resetAll();},nullptr); + uihsk=api->registerUIHook("main.seek",[this](const void*,void*){this->p->resetAll();},nullptr); } void qmpSimpleVisualization::deinit() { if(!api)return;close(); api->unregisterFunctionality("Keyboard"); api->unregisterUIHook("main.stop",uihs); + api->unregisterUIHook("main.seek",uihsk); delete p; } const char* qmpSimpleVisualization::pluginGetName() diff --git a/simple-visualization/simplevisualization.hpp b/simple-visualization/simplevisualization.hpp index d79eef0..58b02ac 100644 --- a/simple-visualization/simplevisualization.hpp +++ b/simple-visualization/simplevisualization.hpp @@ -10,6 +10,7 @@ class qmpSimpleVisualization:public qmpPluginIntf,public qmpFuncBaseIntf qmpPluginAPI* api; qmpKeyboardWindow *p; int uihs; + int uihsk; public: qmpSimpleVisualization(qmpPluginAPI* _api); void show(); -- cgit v1.2.3