Subversion Repositories svn.mios32

Rev

Rev 1502 | Rev 1759 | 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 1724 2013-03-28 20:23:40Z 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
49
void MidiMonitor::scanMidiDevices()
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);
917 tk 74
        bool enabled = midiPorts[i] == selectedPort;
877 tk 75
 
76
        if( enabled )
77
            current = i + 1;
917 tk 78
 
920 tk 79
        monitorLogBox->addEntry(Colours::blue, "[" + String(i+1) + "] " + midiPorts[i] + (enabled ? " (*)" : ""));
917 tk 80
 
81
        if( inPort )
82
            miosStudio->audioDeviceManager.setMidiInputEnabled(midiPorts[i], enabled);
83
        else if( enabled )
84
            miosStudio->audioDeviceManager.setDefaultMidiOutput(midiPorts[i]);
877 tk 85
    }
86
    midiPortSelector->setSelectedId(current, true);
917 tk 87
    midiPortSelector->setEnabled(true);
877 tk 88
 
1502 tk 89
    if( current == -1 ) {
90
        if( inPort ) {
917 tk 91
            miosStudio->setMidiInput(String::empty);
1502 tk 92
        } else {
917 tk 93
            miosStudio->setMidiOutput(String::empty);
1502 tk 94
        }
95
    }
877 tk 96
 
920 tk 97
    monitorLogBox->addEntry(Colours::grey, T("MIDI Monitor ready."));
877 tk 98
}
99
 
100
//==============================================================================
101
void MidiMonitor::paint (Graphics& g)
102
{
103
    g.fillAll(Colours::white);
104
}
105
 
106
void MidiMonitor::resized()
107
{
1033 tk 108
    midiPortLabel->setBounds(4, 4, 60, 22);
109
    midiPortSelector->setBounds(4+60, 4, getWidth()-8-60, 22);
894 tk 110
    monitorLogBox->setBounds(4, 4+22+4, getWidth()-8, getHeight()-(4+22+4+4));
877 tk 111
}
112
 
113
 
114
//==============================================================================
115
void MidiMonitor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
116
{
117
    if( comboBoxThatHasChanged == midiPortSelector ) {
917 tk 118
        String portName = midiPortSelector->getText();
119
        if( portName == T("<< none >>") )
120
            portName = String::empty;
121
 
878 tk 122
        if( inPort )
917 tk 123
            miosStudio->setMidiInput(portName);
878 tk 124
        else
917 tk 125
            miosStudio->setMidiOutput(portName);
877 tk 126
    }
127
}
128
 
1463 tk 129
 
877 tk 130
//==============================================================================
1465 tk 131
String MidiMonitor::getNoteString(uint8 note)
1463 tk 132
{
1465 tk 133
    String strBuffer;
1463 tk 134
    const char note_tab[12][3] = { "c-", "c#", "d-", "d#", "e-", "f-", "f#", "g-", "g#", "a-", "a#", "b-" };
135
 
1465 tk 136
    // determine octave, note contains semitone number thereafter
137
    uint8 octave = note / 12;
138
    note %= 12;
1463 tk 139
 
1465 tk 140
    // octave
141
    char octaveChr;
142
    switch( octave ) {
143
        case 0:  octaveChr = '2'; break; // -2
144
        case 1:  octaveChr = '1'; break; // -1
145
        default: octaveChr = '0' + (octave-2); // 0..7
1463 tk 146
    }
1465 tk 147
 
148
    // semitone (capital letter if octave >= 2)
149
    strBuffer = String::formatted(T("%c%c%c"), octave >= 2 ? (note_tab[note][0] + 'A'-'a') : note_tab[note][0],
150
                                  note_tab[note][1],
151
                                  octaveChr);
1463 tk 152
 
153
    return strBuffer;
154
}
155
 
156
//==============================================================================
878 tk 157
void MidiMonitor::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
877 tk 158
{
886 tk 159
    uint32 size = message.getRawDataSize();
1724 tk 160
    uint8 *data = (uint8 *)message.getRawData();
877 tk 161
 
878 tk 162
    bool isMidiClock = data[0] == 0xf8;
163
    bool isActiveSense = data[0] == 0xfe;
886 tk 164
    bool isMiosTerminalMessage = SysexHelper::isValidMios32DebugMessage(data, size, -1);
878 tk 165
 
166
    if( !(isMidiClock && filterMidiClock) &&
167
        !(isActiveSense && filterActiveSense) &&
168
        !(isMiosTerminalMessage && filterMiosTerminalMessage) ) {
169
 
912 tk 170
        double timeStamp = message.getTimeStamp() ? message.getTimeStamp() : ((double)Time::getMillisecondCounter() / 1000.0);
878 tk 171
        String timeStampStr = (timeStamp > 0)
172
            ? String::formatted(T("%8.3f"), timeStamp)
173
            : T("now");
174
 
908 tk 175
        String hexStr = String::toHexString(data, size);
176
 
1463 tk 177
        String descStr;
178
        switch( data[0] & 0xf0 ) {
179
            case 0x80:
1465 tk 180
                descStr = String::formatted(T("   Chn#%2d  Note Off "), (data[0] & 0x0f) + 1);
181
                descStr += getNoteString(data[1]);
182
                descStr += String::formatted(T("  Vel:%d"), data[2]);
1463 tk 183
                break;
184
 
185
            case 0x90:
186
                if( data[2] == 0 ) {
1465 tk 187
                    descStr = String::formatted(T("   Chn#%2d  Note Off "), (data[0] & 0x0f) + 1);
188
                    descStr += getNoteString(data[1]) + " (optimized)";
1463 tk 189
                } else {
1465 tk 190
                    descStr = String::formatted(T("   Chn#%2d  Note On  "), (data[0] & 0x0f) + 1);
191
                    descStr += getNoteString(data[1]);
192
                    descStr += String::formatted(T("  Vel:%d"), data[2]);
1463 tk 193
                }
194
                break;
195
 
196
            case 0xa0:
1465 tk 197
                descStr = String::formatted(T("   Chn#%2d  Aftertouch "), (data[0] & 0x0f) + 1);
198
                descStr += getNoteString(data[1]);
199
                descStr += String::formatted(T(" %d"), data[2]);
1463 tk 200
                break;
201
 
202
            case 0xb0:
203
                descStr = String::formatted(T("   Chn#%2d  CC#%3d = %d"),
204
                                            (data[0] & 0x0f) + 1,
205
                                            data[1],
206
                                            data[2]);
207
                break;
208
 
209
            case 0xc0:
210
                descStr = String::formatted(T("   Chn#%2d  Program Change %d"),
211
                                            (data[0] & 0x0f) + 1,
212
                                            data[1]);
213
                break;
214
 
215
            case 0xd0:
1465 tk 216
                descStr = String::formatted(T("   Chn#%2d  Aftertouch "), (data[0] & 0x0f) + 1);
217
                descStr += getNoteString(data[1]);
1463 tk 218
                break;
219
 
220
            case 0xe0:
221
                descStr = String::formatted(T("   Chn#%2d  Pitchbend %d"),
222
                                            (data[0] & 0x0f) + 1,
223
                                            (int)((data[1] & 0x7f) | ((data[2] & 0x7f) << 7)) - 8192);
224
                break;
225
 
226
            default:
227
                descStr = String::formatted(T("")); // nothing to add here
228
        }
229
 
230
        monitorLogBox->addEntry(Colours::black, "[" + timeStampStr + "] " + hexStr + descStr);
878 tk 231
    }
877 tk 232
}