Skip to content

Commit a06094b

Browse files
committed
midi: add option to disable channel 9 to drum track
Currently, any channel 9 in a MIDI file is automatically added as a drum instead of a melodic track. Which generally is the correct thing to do, as this is how MIDI has it specified and standardized. This new option allows to disable this behaviour though. Which is especially useful when using DLS (DownLoadable Sound) as DLS has a per channel bit to specify if it is a drum or melodic track. Some extracted DLS files from N64 games, extracted via the N64 Soundbank Tool (https://github.com/jombo23/N64-Tools/tree/master/N64SoundbankTool) for instance, use a channel 9 and have the drum bit in DLS unset. So this option would be needed to play such files correctly. The ANMP media player (https://github.com/derselbst/ANMP) has a similar option. According to a disscussion on the FluidSynth issue tracker there apparently is no way to detect and fix such a conflict between DLS and MIDI automatically, hence such a manual option seems needed: FluidSynth/fluidsynth#1576 Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
1 parent f24d6a8 commit a06094b

File tree

8 files changed

+83
-1
lines changed

8 files changed

+83
-1
lines changed

src/appshell/qml/Preferences/ImportPreferencesPage.qml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ PreferencesPage {
121121
MidiSection {
122122
shortestNotes: importPreferencesModel.shortestNotes()
123123
currentShortestNote: importPreferencesModel.currentShortestNote
124+
channel9isDrum: importPreferencesModel.currentChannel9isDrum
124125

125126
navigation.section: root.navigationSection
126127
navigation.order: root.navigationOrderStart + 4
@@ -129,6 +130,10 @@ PreferencesPage {
129130
importPreferencesModel.currentShortestNote = note
130131
}
131132

133+
onCurrentChannel9isDrumChangeRequested: function(isDrum) {
134+
importPreferencesModel.currentChannel9isDrum = isDrum
135+
}
136+
132137
onFocusChanged: {
133138
if (activeFocus) {
134139
root.ensureContentVisibleRequested(Qt.rect(x, y, width, height))

src/appshell/qml/Preferences/internal/MidiSection.qml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ BaseSection {
2929
title: qsTrc("appshell/preferences", "MIDI")
3030

3131
property alias shortestNotes: shortestNotesBox.model
32+
property alias channel9isDrum: channel9isDrumBox.checked
3233
property int currentShortestNote: 0
3334

3435
signal currentShortestNoteChangeRequested(int note)
36+
signal currentChannel9isDrumChangeRequested(bool isDrum)
3537

3638
ComboBoxWithTitle {
3739
id: shortestNotesBox
@@ -52,4 +54,19 @@ BaseSection {
5254
root.currentShortestNoteChangeRequested(newValue)
5355
}
5456
}
57+
58+
CheckBox {
59+
id: channel9isDrumBox
60+
width: parent.width
61+
62+
text: qsTrc("appshell/preferences", "Channel 9 is drum")
63+
64+
navigation.name: "Channel9isDrum"
65+
navigation.panel: root.navigation
66+
navigation.row: 1
67+
68+
onClicked: {
69+
root.currentChannel9isDrumChangeRequested(!checked)
70+
}
71+
}
5572
}

src/appshell/view/preferences/importpreferencesmodel.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ void ImportPreferencesModel::load()
6464
emit currentShortestNoteChanged(val);
6565
});
6666

67+
midiImportExportConfiguration()->midiChannel9isDrumChanged().onReceive(this, [this](bool isDrum) {
68+
emit currentChannel9isDrumChanged(isDrum);
69+
});
70+
6771
meiConfiguration()->meiImportLayoutChanged().onReceive(this, [this](bool val) {
6872
emit meiImportLayoutChanged(val);
6973
});
@@ -155,6 +159,11 @@ int ImportPreferencesModel::currentShortestNote() const
155159
return midiImportExportConfiguration()->midiShortestNote();
156160
}
157161

162+
bool ImportPreferencesModel::currentChannel9isDrum() const
163+
{
164+
return midiImportExportConfiguration()->midiChannel9isDrum();
165+
}
166+
158167
bool ImportPreferencesModel::needAskAboutApplyingNewStyle() const
159168
{
160169
return musicXmlConfiguration()->needAskAboutApplyingNewStyle();
@@ -235,6 +244,16 @@ void ImportPreferencesModel::setCurrentShortestNote(int note)
235244
emit currentShortestNoteChanged(note);
236245
}
237246

247+
void ImportPreferencesModel::setCurrentChannel9isDrum(bool isDrum)
248+
{
249+
if (isDrum == currentChannel9isDrum()) {
250+
return;
251+
}
252+
253+
midiImportExportConfiguration()->setMidiChannel9isDrum(isDrum);
254+
emit currentChannel9isDrumChanged(isDrum);
255+
}
256+
238257
void ImportPreferencesModel::setNeedAskAboutApplyingNewStyle(bool value)
239258
{
240259
if (value == needAskAboutApplyingNewStyle()) {

src/appshell/view/preferences/importpreferencesmodel.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class ImportPreferencesModel : public QObject, public muse::Injectable, public m
5353

5454
Q_PROPERTY(int currentShortestNote READ currentShortestNote WRITE setCurrentShortestNote NOTIFY currentShortestNoteChanged)
5555

56+
Q_PROPERTY(bool currentChannel9isDrum READ currentChannel9isDrum WRITE setCurrentChannel9isDrum NOTIFY currentChannel9isDrumChanged)
57+
5658
Q_PROPERTY(
5759
bool needAskAboutApplyingNewStyle READ needAskAboutApplyingNewStyle WRITE setNeedAskAboutApplyingNewStyle NOTIFY needAskAboutApplyingNewStyleChanged)
5860

@@ -83,6 +85,7 @@ class ImportPreferencesModel : public QObject, public muse::Injectable, public m
8385
bool inferTextType() const;
8486

8587
int currentShortestNote() const;
88+
bool currentChannel9isDrum() const;
8689

8790
bool needAskAboutApplyingNewStyle() const;
8891

@@ -98,6 +101,7 @@ public slots:
98101
void setInferTextType(bool value);
99102

100103
void setCurrentShortestNote(int note);
104+
void setCurrentChannel9isDrum(bool isDrum);
101105

102106
void setNeedAskAboutApplyingNewStyle(bool value);
103107

@@ -111,6 +115,7 @@ public slots:
111115
void needUseDefaultFontChanged(bool needUseDefaultFont);
112116
void inferTextTypeChanged(bool inferTextType);
113117
void currentShortestNoteChanged(int currentShortestNote);
118+
void currentChannel9isDrumChanged(bool currentChannel9isDrum);
114119
void needAskAboutApplyingNewStyleChanged(bool needAskAboutApplyingNewStyle);
115120
void meiImportLayoutChanged(bool importLayout);
116121
};

src/importexport/midi/imidiconfiguration.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class IMidiImportExportConfiguration : MODULE_EXPORT_INTERFACE
4141
virtual void setMidiShortestNote(int ticks) = 0;
4242
virtual muse::async::Channel<int> midiShortestNoteChanged() const = 0;
4343

44+
virtual bool midiChannel9isDrum() const = 0;
45+
virtual void setMidiChannel9isDrum(bool isDrum) = 0;
46+
virtual muse::async::Channel<bool> midiChannel9isDrumChanged() const = 0;
47+
4448
virtual void setMidiImportOperationsFile(const std::optional<muse::io::path_t>& filePath) const = 0;
4549

4650
// export

src/importexport/midi/internal/midiconfiguration.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ using namespace muse;
3232
using namespace mu::iex::midi;
3333

3434
static const Settings::Key SHORTEST_NOTE_KEY("iex_midi", "io/midi/shortestNote");
35+
static const Settings::Key CHANNEL9_IS_DRUM_KEY("iex_midi", "io/midi/channel9isDrum");
3536
static const Settings::Key EXPORTRPNS_KEY("iex_midi", "io/midi/exportRPNs");
3637
static const Settings::Key EXPAND_REPEATS_KEY("iex_midi", "io/midi/expandRepeats");
3738

@@ -42,6 +43,11 @@ void MidiConfiguration::init()
4243
m_midiShortestNoteChanged.send(val.toInt());
4344
});
4445

46+
settings()->setDefaultValue(CHANNEL9_IS_DRUM_KEY, Val(true));
47+
settings()->valueChanged(CHANNEL9_IS_DRUM_KEY).onReceive(this, [this](const Val& val) {
48+
m_midiChannel9isDrumChanged.send(val.toBool());
49+
});
50+
4551
settings()->setDefaultValue(EXPAND_REPEATS_KEY, Val(true));
4652
settings()->setDefaultValue(EXPORTRPNS_KEY, Val(true));
4753
}
@@ -61,6 +67,21 @@ async::Channel<int> MidiConfiguration::midiShortestNoteChanged() const
6167
return m_midiShortestNoteChanged;
6268
}
6369

70+
bool MidiConfiguration::midiChannel9isDrum() const
71+
{
72+
return settings()->value(CHANNEL9_IS_DRUM_KEY).toBool();
73+
}
74+
75+
void MidiConfiguration::setMidiChannel9isDrum(bool isDrum)
76+
{
77+
settings()->setSharedValue(CHANNEL9_IS_DRUM_KEY, Val(isDrum));
78+
}
79+
80+
async::Channel<bool> MidiConfiguration::midiChannel9isDrumChanged() const
81+
{
82+
return m_midiChannel9isDrumChanged;
83+
}
84+
6485
void MidiConfiguration::setMidiImportOperationsFile(const std::optional<muse::io::path_t>& filePath) const
6586
{
6687
if (filePath) {

src/importexport/midi/internal/midiconfiguration.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class MidiConfiguration : public IMidiImportExportConfiguration, public muse::as
3737
void setMidiShortestNote(int ticks) override;
3838
muse::async::Channel<int> midiShortestNoteChanged() const override;
3939

40+
bool midiChannel9isDrum() const override;
41+
void setMidiChannel9isDrum(bool isDrum) override;
42+
muse::async::Channel<bool> midiChannel9isDrumChanged() const override;
43+
4044
void setMidiImportOperationsFile(const std::optional<muse::io::path_t>& filePath) const override;
4145

4246
// export
@@ -48,6 +52,7 @@ class MidiConfiguration : public IMidiImportExportConfiguration, public muse::as
4852

4953
private:
5054
muse::async::Channel<int> m_midiShortestNoteChanged;
55+
muse::async::Channel<bool> m_midiChannel9isDrumChanged;
5156
};
5257
}
5358

src/importexport/midi/internal/midishared/midifile.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
#include "midifile.h"
2424

25+
#include "modularity/ioc.h"
26+
#include "importexport/midi/imidiconfiguration.h"
27+
2528
#include "containers.h"
2629

2730
#include "log.h"
@@ -676,8 +679,11 @@ bool MidiFile::readEvent(MidiEvent* event)
676679

677680
void MidiTrack::setOutChannel(int n)
678681
{
682+
auto conf = muse::modularity::globalIoc()->resolve<mu::iex::midi::IMidiImportExportConfiguration>("iex_midi");
683+
679684
_outChannel = n;
680-
if (_outChannel == 9) {
685+
686+
if (conf->midiChannel9isDrum() &&_outChannel == 9) {
681687
_drumTrack = true;
682688
}
683689
}

0 commit comments

Comments
 (0)