Subversion Repositories svn.mios32

Rev

Rev 1724 | Rev 1764 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
877 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: MidiMonitor.cpp 1759 2013-04-26 22:25:16Z tk $
3
/*
4
 * MIDI Monitor Component
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2010 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
#include "MidiMonitor.h"
878 tk 16
#include "MiosStudio.h"
877 tk 17
 
18
 
19
//==============================================================================
878 tk 20
MidiMonitor::MidiMonitor(MiosStudio *_miosStudio, const bool _inPort)
21
    : miosStudio(_miosStudio)
877 tk 22
    , inPort(_inPort)
878 tk 23
    , filterMidiClock(1)
24
    , filterActiveSense(1)
25
    , filterMiosTerminalMessage(1)
886 tk 26
    , cutLongMessages(1)
877 tk 27
{
28
    addAndMakeVisible(midiPortSelector = new ComboBox(String::empty));
29
    midiPortSelector->addListener(this);
30
    midiPortSelector->clear();
917 tk 31
    midiPortSelector->addItem (TRANS("<< device scan running >>"), -1);
32
    midiPortSelector->setSelectedId(-1, true);
33
    midiPortSelector->setEnabled(false);
34
    midiPortLabel = new Label("", inPort ? T("MIDI IN: ") : T("MIDI OUT: "));
35
    midiPortLabel->attachToComponent(midiPortSelector, true);
36
 
37
    addAndMakeVisible(monitorLogBox = new LogBox(T("Midi Monitor")));
920 tk 38
    monitorLogBox->addEntry(Colours::red, T("Connecting to MIDI driver - be patient!"));
917 tk 39
 
40
    setSize(400, 200);
41
}
42
 
43
MidiMonitor::~MidiMonitor()
44
{
45
}
46
 
47
//==============================================================================
48
// Should be called after startup once window is visible
1759 tk 49
void MidiMonitor::scanMidiDevices(const String& searchPort)
917 tk 50
{
51
    monitorLogBox->clear();
52
 
53
    midiPortSelector->setEnabled(false);
54
    midiPortSelector->clear();
877 tk 55
    midiPortSelector->addItem (TRANS("<< none >>"), -1);
56
    midiPortSelector->addSeparator();
57
 
917 tk 58
    // restore settings
59
    String selectedPort;
60
    StringArray midiPorts;
61
    if( inPort ) {
920 tk 62
        monitorLogBox->addEntry(Colours::red, T("Scanning for MIDI Inputs..."));
917 tk 63
        selectedPort = miosStudio->getMidiInput();
64
        midiPorts = MidiInput::getDevices();
65
    } else {
920 tk 66
        monitorLogBox->addEntry(Colours::red, T("Scanning for MIDI Outputs..."));
917 tk 67
        selectedPort = miosStudio->getMidiOutput();
68
        midiPorts = MidiOutput::getDevices();
69
    }
70
 
877 tk 71
    int current = -1;
908 tk 72
    for(int i=0; i<midiPorts.size(); ++i) {
73
        midiPortSelector->addItem(midiPorts[i], i+1);
1759 tk 74
        bool enabled = false;
877 tk 75
 
1759 tk 76
        if( current < 0 ) {
77
            if( searchPort.length() ) {
78
                enabled = midiPorts[i].containsIgnoreCase(searchPort);
79
            } else {
80
                enabled = midiPorts[i] == selectedPort;
81
            }
82
        }
83
 
877 tk 84
        if( enabled )
85
            current = i + 1;
917 tk 86
 
920 tk 87
        monitorLogBox->addEntry(Colours::blue, "[" + String(i+1) + "] " + midiPorts[i] + (enabled ? " (*)" : ""));
917 tk 88
 
89
        if( inPort )
90
            miosStudio->audioDeviceManager.setMidiInputEnabled(midiPorts[i], enabled);
91
        else if( enabled )
92
            miosStudio->audioDeviceManager.setDefaultMidiOutput(midiPorts[i]);
877 tk 93
    }
94
    midiPortSelector->setSelectedId(current, true);
917 tk 95
    midiPortSelector->setEnabled(true);
877 tk 96
 
1502 tk 97
    if( current == -1 ) {
98
        if( inPort ) {
917 tk 99
            miosStudio->setMidiInput(String::empty);
1759 tk 100
 
101
            if( searchPort.length() ) {
102
                std::cout << "ERROR: MIDI IN Port '" << searchPort << "' not found!" << std::endl;
103
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
104
                                            T("Unknown MIDI IN Port"),
105
                                            String("MIDI IN Port '") + searchPort + String("' not found!"),
106
                                            String::empty);
107
            }
1502 tk 108
        } else {
917 tk 109
            miosStudio->setMidiOutput(String::empty);
1759 tk 110
 
111
            if( searchPort.length() ) {
112
                std::cout << "ERROR: MIDI OUT Port '" << searchPort << "' not found!" << std::endl;
113
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
114
                                            T("Unknown MIDI OUT Port"),
115
                                            String("MIDI OUT Port '") + searchPort + String("' not found!"),
116
                                            String::empty);
117
            }
1502 tk 118
        }
119
    }
877 tk 120
 
920 tk 121
    monitorLogBox->addEntry(Colours::grey, T("MIDI Monitor ready."));
877 tk 122
}
123
 
124
//==============================================================================
125
void MidiMonitor::paint (Graphics& g)
126
{
127
    g.fillAll(Colours::white);
128
}
129
 
130
void MidiMonitor::resized()
131
{
1033 tk 132
    midiPortLabel->setBounds(4, 4, 60, 22);
133
    midiPortSelector->setBounds(4+60, 4, getWidth()-8-60, 22);
894 tk 134
    monitorLogBox->setBounds(4, 4+22+4, getWidth()-8, getHeight()-(4+22+4+4));
877 tk 135
}
136
 
137
 
138
//==============================================================================
139
void MidiMonitor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
140
{
141
    if( comboBoxThatHasChanged == midiPortSelector ) {
917 tk 142
        String portName = midiPortSelector->getText();
143
        if( portName == T("<< none >>") )
144
            portName = String::empty;
145
 
878 tk 146
        if( inPort )
917 tk 147
            miosStudio->setMidiInput(portName);
878 tk 148
        else
917 tk 149
            miosStudio->setMidiOutput(portName);
877 tk 150
    }
151
}
152
 
1463 tk 153
 
877 tk 154
//==============================================================================
1465 tk 155
String MidiMonitor::getNoteString(uint8 note)
1463 tk 156
{
1465 tk 157
    String strBuffer;
1463 tk 158
    const char note_tab[12][3] = { "c-", "c#", "d-", "d#", "e-", "f-", "f#", "g-", "g#", "a-", "a#", "b-" };
159
 
1465 tk 160
    // determine octave, note contains semitone number thereafter
161
    uint8 octave = note / 12;
162
    note %= 12;
1463 tk 163
 
1465 tk 164
    // octave
165
    char octaveChr;
166
    switch( octave ) {
167
        case 0:  octaveChr = '2'; break; // -2
168
        case 1:  octaveChr = '1'; break; // -1
169
        default: octaveChr = '0' + (octave-2); // 0..7
1463 tk 170
    }
1465 tk 171
 
172
    // semitone (capital letter if octave >= 2)
173
    strBuffer = String::formatted(T("%c%c%c"), octave >= 2 ? (note_tab[note][0] + 'A'-'a') : note_tab[note][0],
174
                                  note_tab[note][1],
175
                                  octaveChr);
1463 tk 176
 
177
    return strBuffer;
178
}
179
 
180
//==============================================================================
878 tk 181
void MidiMonitor::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
877 tk 182
{
886 tk 183
    uint32 size = message.getRawDataSize();
1724 tk 184
    uint8 *data = (uint8 *)message.getRawData();
877 tk 185
 
878 tk 186
    bool isMidiClock = data[0] == 0xf8;
187
    bool isActiveSense = data[0] == 0xfe;
886 tk 188
    bool isMiosTerminalMessage = SysexHelper::isValidMios32DebugMessage(data, size, -1);
878 tk 189
 
190
    if( !(isMidiClock && filterMidiClock) &&
191
        !(isActiveSense && filterActiveSense) &&
192
        !(isMiosTerminalMessage && filterMiosTerminalMessage) ) {
193
 
912 tk 194
        double timeStamp = message.getTimeStamp() ? message.getTimeStamp() : ((double)Time::getMillisecondCounter() / 1000.0);
878 tk 195
        String timeStampStr = (timeStamp > 0)
196
            ? String::formatted(T("%8.3f"), timeStamp)
197
            : T("now");
198
 
908 tk 199
        String hexStr = String::toHexString(data, size);
200
 
1463 tk 201
        String descStr;
202
        switch( data[0] & 0xf0 ) {
203
            case 0x80:
1465 tk 204
                descStr = String::formatted(T("   Chn#%2d  Note Off "), (data[0] & 0x0f) + 1);
205
                descStr += getNoteString(data[1]);
206
                descStr += String::formatted(T("  Vel:%d"), data[2]);
1463 tk 207
                break;
208
 
209
            case 0x90:
210
                if( data[2] == 0 ) {
1465 tk 211
                    descStr = String::formatted(T("   Chn#%2d  Note Off "), (data[0] & 0x0f) + 1);
212
                    descStr += getNoteString(data[1]) + " (optimized)";
1463 tk 213
                } else {
1465 tk 214
                    descStr = String::formatted(T("   Chn#%2d  Note On  "), (data[0] & 0x0f) + 1);
215
                    descStr += getNoteString(data[1]);
216
                    descStr += String::formatted(T("  Vel:%d"), data[2]);
1463 tk 217
                }
218
                break;
219
 
220
            case 0xa0:
1465 tk 221
                descStr = String::formatted(T("   Chn#%2d  Aftertouch "), (data[0] & 0x0f) + 1);
222
                descStr += getNoteString(data[1]);
223
                descStr += String::formatted(T(" %d"), data[2]);
1463 tk 224
                break;
225
 
226
            case 0xb0:
227
                descStr = String::formatted(T("   Chn#%2d  CC#%3d = %d"),
228
                                            (data[0] & 0x0f) + 1,
229
                                            data[1],
230
                                            data[2]);
231
                break;
232
 
233
            case 0xc0:
234
                descStr = String::formatted(T("   Chn#%2d  Program Change %d"),
235
                                            (data[0] & 0x0f) + 1,
236
                                            data[1]);
237
                break;
238
 
239
            case 0xd0:
1465 tk 240
                descStr = String::formatted(T("   Chn#%2d  Aftertouch "), (data[0] & 0x0f) + 1);
241
                descStr += getNoteString(data[1]);
1463 tk 242
                break;
243
 
244
            case 0xe0:
245
                descStr = String::formatted(T("   Chn#%2d  Pitchbend %d"),
246
                                            (data[0] & 0x0f) + 1,
247
                                            (int)((data[1] & 0x7f) | ((data[2] & 0x7f) << 7)) - 8192);
248
                break;
249
 
250
            default:
251
                descStr = String::formatted(T("")); // nothing to add here
252
        }
253
 
254
        monitorLogBox->addEntry(Colours::black, "[" + timeStampStr + "] " + hexStr + descStr);
878 tk 255
    }
877 tk 256
}