Subversion Repositories svn.mios32

Rev

Rev 1764 | Details | Compare with Previous | Last modification | View Log | RSS feed

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