aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--doc/APIdoc.md62
-rw-r--r--qmidiplayer-desktop/qmpchannelswindow.cpp18
-rw-r--r--qmidiplayer-desktop/qmpchannelswindow.hpp19
4 files changed, 56 insertions, 48 deletions
diff --git a/ChangeLog b/ChangeLog
index bd1a4b7..7b5a92f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2018-10-02 0.8.6 alpha
+Fixed layout with Qt 5.11.
+Minor code cleanups in qmpchannelswindow.
+Documentation update.
+
2018-06-18 0.8.6 alpha
Precise playback (no more slowdown).
Also the visualization should now sync better.
diff --git a/doc/APIdoc.md b/doc/APIdoc.md
index 517a0fc..968aa97 100644
--- a/doc/APIdoc.md
+++ b/doc/APIdoc.md
@@ -47,39 +47,46 @@ It has 6 public members: one default constructor, one default destructor and fou
- `const char* pluginGetVersion()`
This function should return the version of the plugin, which will be shown in the plugin manager.
-Your plugin is expected to register handlers (hooks) and functionalities when init() is called by the host,
-and do clean-up jobs when deinit() is caled.
+Your plugin is expected to register handlers (hooks) and functionalities when `init()` is called by the host,
+and do clean-up jobs when `deinit()` is caled.
-Currently plugins can register handlers for these functionalities:
+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:
-- Visualization (via `(un)registerVisualizationIntf`)
-- MIDI File Reader (via `(un)registerFileReader`)
+- MIDI File Reader (`qmpFileReader`)
+- MIDI Out Device (`qmpMidiOutDevice`)
...and can hooks into the following processes:
- 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`)
+- 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.start`: track started playing (includes resuming from pause and switching tracks).
+ * `main.pause`: playback paused
+ * `main.reset`: (odd enough) when loading a new file
-Functionalities has their own interfaces you need to implement(`qmpVisualizationIntf` and `qmpFileReader`, respectively),
-while hooks uses the universal `ICallBack` interface. Functionalities are discussed later.
+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` while file read finish hook doesn't provide
-`callerdata` (`NULL`).
+reader and handler hooks have `SEventCallBackData*` as their `callerdata`. All other callbacks at this time have `NULL`
+as their `callerdata`. **Don't try directly modifying the members of callerdata!**
# 4. Functionalities
Plugins extend the host with extra functionalities. With hooks, handlers and the built-in core API, you can already do a
lot of hacking. If that cannot make you satisfied, QMidiPlayer have several vacancies that are expected to be implemented
-by plugins. And with the introduction of the general functionality API, you can now virtually add anything to QMidiPlayer!
+by plugins. And with the introduction of the generic functionality API, you can now virtually add anything to QMidiPlayer!
## 4.1 What is a functionality?
Have a look at the main window. By default there're three or four buttons at the bottom of it.
-These are functionalities. Functionalties go into two types: checkable and non-checkable.
+These are functionalities. Functionalities go into two types: checkable and non-checkable.
Checkable functionalities can be toggled on or off, while non-checkable functionalities have
-no such states. For non-checkable functionalities, only show() is called when the user invokes it.
+no such states. For non-checkable functionalities, only `show()` is called when the user invokes it.
The user can arrange functionalities shown on the toolbar and the action menu to their needs.
## 4.2 Visualization
@@ -87,26 +94,26 @@ Visualization was once a feature of QMidiPlayer's core. But you can now implemen
as a normal functionality. The code of the default visualization plugin may offer some additional help.
## 4.3 MIDI File Reader
-This is not strictly a "functionality", because its interface qmpFileReader does not inherit qmpFuncBaseIntf.
+This is not strictly a "functionality", because its interface `qmpFileReader` does not inherit `qmpFuncBaseIntf`.
When the user requests to open a file, the core tries to load the file with registered file readers and
accepts the first valid result. Therefore you can implement your own file reader, which may even add
eXtended Module support to QMidiPlayer!
## 4.4 MIDI Output Device
-This is not a functionality either. By implementing the interface qmpMidiOutDevice and registering it, you can
-add custom MIDI Devices in the built-in MIDI mapper.
+This is not a functionality either. By implementing the interface `qmpMidiOutDevice` and registering it, you can
+add custom MIDI Devices to the built-in MIDI mapper.
# 5. Interacting with the core
-Your plugin gets a pointer to the class `qmpPluginAPI` after it is initialized, which is what you should use to
-interact with the core.
+Your plugin gets a pointer to an object of the class `qmpPluginAPI` after it is initialized, which is what you
+should use to interact with the core.
This interface provides a wide range of APIs that...
- provide information on the file being played
- get/change the current state of the player
- modify events when a midi file is being read
- register custom interfaces (functionalities, output devices, file readers, handlers and hooks)
-- provide options management
+- provide options management (`<register|get|set>Option*`)
# 6. General Considerations & Notes
@@ -114,14 +121,14 @@ This interface provides a wide range of APIs that...
1. If you implemented a API that returns a pointer to an instance of some nonabstract class, you can forget about
the pointer after returning it. The core will free its memory after it is no longer used. You shouldn't extend the
class pointed to because if you do so, the core will not be able to destruct it correctly. Examples include
-qmpFileReader::readFile which returns a pointer to a CMidiFile class.
-2. However if you passed a pointer to the core through a function in qmpPluginAPI, you cannot forget about the pointer
+`qmpFileReader::readFile` which returns a pointer of the `CMidiFile` class.
+2. However if you passed a pointer to the core through a function in `qmpPluginAPI`, you cannot forget about the pointer
later. As these pointers are mostly polymorphic, the core cannot handle their destruction. You have to delete them
-yourself in the deinit() function of your plugin.
+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 components with running status either.
-That is to say, the `type` parameter found in SEvent and SEventCallBackData should be always greater than or equal to
+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.
# 7. Reference
@@ -138,7 +145,7 @@ _absolute_ timestamp of the event in MIDI tick.
- `uint32_t p1`
parameter 1 for the midi event.
- `uint32_t p2`
-parameter 2 for the midi event.
+parameter 2 for the midi event. Note that pitch wheel events use both parameters (p2 for MSB).
- `uint8_t type`
type of the event together with the channel this event goes to.
- `std::string str`
@@ -192,7 +199,7 @@ File standard of the MIDI file.
- `uint32_t div`
Ticks per quarter note. SMTPE format is not supported by QMidiPlayer.
- `~CMidiFile()`
-Frees memory occupied by the title and copyright string.
+Frees memory occupied by the file.
### class `ICallBack`
Generic callback function that can be used for hooking the core.
@@ -276,3 +283,8 @@ Called when the device is mapped. `ch` is the channel it is mapped to.
`refcnt` is the number of channels mapped to this device after the remapping.
- `virtual void onUnmapped(uint8_t ch,int refcnt)=0`
Called when the device is mapped. Parameters are the sams as `onMapped()`.
+
+### class `qmpPluginAPI`
+Main way to interact with the core.
+
+Yet to be documented.
diff --git a/qmidiplayer-desktop/qmpchannelswindow.cpp b/qmidiplayer-desktop/qmpchannelswindow.cpp
index 77560dc..c154383 100644
--- a/qmidiplayer-desktop/qmpchannelswindow.cpp
+++ b/qmidiplayer-desktop/qmpchannelswindow.cpp
@@ -45,6 +45,7 @@ qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) :
ui->twChannels->setCellWidget(i,3,new QDCComboBox());
QDCComboBox *cb=(QDCComboBox*)ui->twChannels->cellWidget(i,3);
cb->setID(i);
+ cb->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
for(size_t j=0;j<devc;++j)
{
cb->addItem(devs[j].c_str());
@@ -59,13 +60,13 @@ qmpChannelsWindow::qmpChannelsWindow(QWidget *parent) :
if(qmpSettingsWindow::getSettingsIntf()->value("Midi/DisableMapping",0).toInt())
cb->setEnabled(false);
connect(cb,SIGNAL(onChange(int,int)),this,SLOT(changeMidiMapping(int,int)));
- ui->twChannels->setCellWidget(i,4,new QDCLabel(""));
- ((QDCLabel*)ui->twChannels->cellWidget(i,4))->setID(i);
- connect(ui->twChannels->cellWidget(i,4),SIGNAL(onDoubleClick(int)),this,SLOT(showPresetWindow(int)));
+ ui->twChannels->setItem(i,4,new QTableWidgetItem(""));
+ ui->twChannels->item(i,4)->setFlags(Qt::ItemIsEnabled);
ui->twChannels->setCellWidget(i,5,new QDCPushButton("..."));
- ((QDCLabel*)ui->twChannels->cellWidget(i,5))->setID(i);
+ ((QDCPushButton*)ui->twChannels->cellWidget(i,5))->setID(i);
connect(ui->twChannels->cellWidget(i,5),SIGNAL(onClick(int)),this,SLOT(showChannelEditorWindow(int)));
}
+ connect(ui->twChannels,SIGNAL(cellDoubleClicked(int,int)),this,SLOT(showPresetWindow(int,int)));
ui->twChannels->setColumnWidth(0,24*(logicalDpiX()/96.));
ui->twChannels->setColumnWidth(1,24*(logicalDpiX()/96.));
ui->twChannels->setColumnWidth(2,24*(logicalDpiX()/96.));
@@ -130,7 +131,7 @@ void qmpChannelsWindow::channelWindowsUpdate()
if(qmpMainWindow::getInstance()->getPlayer()->isFinished())
{
for(int i=0;i<16;++i)
- ((QLabel*)ui->twChannels->cellWidget(i,4))->setText("");
+ ui->twChannels->item(i,4)->setText("");
connect(cb,SIGNAL(onNoteOn()),this,SLOT(updateChannelActivity()));
fused=0;return;
}
@@ -153,14 +154,14 @@ void qmpChannelsWindow::channelWindowsUpdate()
sprintf(data,"%03d:%03d %s",b,p,nm);
if(fused)
{
- if(strcmp(((QLabel*)ui->twChannels->cellWidget(i,4))->
+ if(strcmp((ui->twChannels->item(i,4))->
text().toStdString().c_str(),data))
{
connect(cb,SIGNAL(onNoteOn()),this,SLOT(updateChannelActivity()));
fused=0;
}
}
- ((QLabel*)ui->twChannels->cellWidget(i,4))->setText(data);
+ ui->twChannels->item(i,4)->setText(data);
ui->twChannels->item(i,0)->setIcon(
qmpMainWindow::getInstance()->getPlayer()->getChstates()[i]?*cha:*chi);
if(qmpMainWindow::getInstance()->getPlayer()->getChstates()[i])
@@ -207,8 +208,9 @@ void qmpChannelsWindow::on_pbUnsolo_clicked()
}
}
-void qmpChannelsWindow::showPresetWindow(int chid)
+void qmpChannelsWindow::showPresetWindow(int chid,int col)
{
+ if(col!=4)return;
pselectw->show();
pselectw->setupWindow(chid);
}
diff --git a/qmidiplayer-desktop/qmpchannelswindow.hpp b/qmidiplayer-desktop/qmpchannelswindow.hpp
index 008598c..9ff0cd0 100644
--- a/qmidiplayer-desktop/qmpchannelswindow.hpp
+++ b/qmidiplayer-desktop/qmpchannelswindow.hpp
@@ -17,20 +17,6 @@ namespace Ui {
class qmpChannelsWindow;
}
-class QDCLabel:public QLabel
-{
- Q_OBJECT
- private:
- int id;
- protected:
- void mouseDoubleClickEvent(QMouseEvent *event){event->accept();emit onDoubleClick(id);}
- public:
- QDCLabel(QString s):QLabel(s){id=-1;}
- void setID(int _id){id=_id;}
- signals:
- void onDoubleClick(int id);
-};
-
class QDCPushButton:public QPushButton
{
Q_OBJECT
@@ -41,6 +27,7 @@ class QDCPushButton:public QPushButton
public:
QDCPushButton(QString s):QPushButton(s){id=-1;}
void setID(int _id){id=_id;}
+ QSize sizeHint()const{return QSize();}
signals:
void onClick(int id);
};
@@ -53,6 +40,8 @@ class QDCComboBox:public QComboBox
public:
QDCComboBox():QComboBox(){id=-1;connect(this,SIGNAL(currentIndexChanged(int)),this,SLOT(indexChangedSlot(int)));}
void setID(int _id){id=_id;}
+ QSize sizeHint()const{return QSize();}
+ QSize minimumSizeHint()const{return QSize();}
signals:
void onChange(int id,int idx);
public slots:
@@ -95,7 +84,7 @@ class qmpChannelsWindow:public QWidget
void channelWindowsUpdate();
void updateChannelActivity();
void channelMSChanged();
- void showPresetWindow(int chid);
+ void showPresetWindow(int chid,int col);
void showChannelEditorWindow(int chid);
void changeMidiMapping(int chid,int idx);
void on_pbUnmute_clicked();