Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
1131 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: MbCvTool.cpp 936 2010-02-28 01:27:18Z tk $
3
/*
4
 * MBHP_MF Tool Window
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 "MbhpMfTool.h"
16
#include "MiosStudio.h"
17
 
18
 
19
MbhpMfToolConfigGlobals::MbhpMfToolConfigGlobals(MbhpMfTool* _mbhpMfTool)
20
    : mbhpMfTool(_mbhpMfTool)
21
{
22
    addAndMakeVisible(nameLabel = new Label(String::empty, T("Patch Name:")));
23
    nameLabel->setJustificationType(Justification::right);
24
    addAndMakeVisible(nameEditor = new TextEditor(String::empty));
25
    nameEditor->setTextToShowWhenEmpty(T("<No Name>"), Colours::grey);
26
    nameEditor->setInputRestrictions(16);
27
 
28
    addAndMakeVisible(numberFadersLabel = new Label(String::empty, T("Number of Faders:")));
29
    numberFadersLabel->setJustificationType(Justification::right);
30
    addAndMakeVisible(numberFadersSlider = new Slider(T("Number of Faders")));
31
    numberFadersSlider->setWantsKeyboardFocus(true);
32
    numberFadersSlider->setSliderStyle(Slider::LinearHorizontal);
33
    numberFadersSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 80, 20);
34
    numberFadersSlider->setRange(1, 8, 1);
35
    numberFadersSlider->setValue(8);
36
    numberFadersSlider->addListener(this);
37
 
38
    addAndMakeVisible(operationModeLabel = new Label(String::empty, T("Operation Mode:")));
39
    operationModeLabel->setJustificationType(Justification::right);
40
    addAndMakeVisible(operationModeComboBox = new ComboBox(String::empty));
41
    operationModeComboBox->setWantsKeyboardFocus(true);
42
    operationModeComboBox->addItem(T("PitchBender Chn#1..#8"), 1);
43
    operationModeComboBox->addItem(T("PitchBender Chn#9..#16"), 2);
1464 tk 44
    operationModeComboBox->addItem(T("CC#7 Chn#1..#8"), 3);
45
    operationModeComboBox->addItem(T("CC#7 Chn#9..#16"), 4);
46
    operationModeComboBox->addItem(T("CC#0..#7 Chn#1"), 5);
47
    operationModeComboBox->addItem(T("CC#8..#15 Chn#1"), 6);
48
    operationModeComboBox->addItem(T("CC#16..#23 Chn#1"), 7);
49
    operationModeComboBox->addItem(T("CC#24..#31 Chn#1"), 8);
50
    operationModeComboBox->addItem(T("CC#32..#39 Chn#1"), 9);
51
    operationModeComboBox->addItem(T("CC#40..#47 Chn#1"), 10);
52
    operationModeComboBox->addItem(T("CC#48..#55 Chn#1"), 11);
53
    operationModeComboBox->addItem(T("CC#56..#63 Chn#1"), 12);
54
    operationModeComboBox->addItem(T("CC#64..#71 Chn#1"), 13);
55
    operationModeComboBox->addItem(T("CC#72..#79 Chn#1"), 14);
56
    operationModeComboBox->addItem(T("CC#80..#87 Chn#1"), 15);
57
    operationModeComboBox->addItem(T("CC#88..#95 Chn#1"), 16);
58
    operationModeComboBox->addItem(T("CC#96..#103 Chn#1"), 17);
59
    operationModeComboBox->addItem(T("CC#104..#111 Chn#1"), 18);
60
    operationModeComboBox->addItem(T("CC#112..#119 Chn#1"), 19);
61
    operationModeComboBox->addItem(T("CC#120..#127 Chn#1"), 20);
1481 tk 62
    operationModeComboBox->addItem(T("Emulated Logic Control"), 21);
63
    operationModeComboBox->addItem(T("Emulated Logic Control Extension"), 22);
64
    operationModeComboBox->addItem(T("Emulated Mackie Control"), 23);
65
    operationModeComboBox->addItem(T("Emulated Mackie Control Extension"), 24);
66
    operationModeComboBox->addItem(T("Emulated Mackie HUI"), 25);
67
    operationModeComboBox->addItem(T("Emulated Motormix"), 26);
1131 tk 68
    operationModeComboBox->setSelectedId(1, true);
1133 tk 69
    operationModeComboBox->addListener(this);
1131 tk 70
 
71
    addAndMakeVisible(mergerLabel = new Label(String::empty, T("MIDI Merger:")));
72
    mergerLabel->setJustificationType(Justification::right);
73
    addAndMakeVisible(mergerComboBox = new ComboBox(String::empty));
74
    mergerComboBox->setWantsKeyboardFocus(true);
75
    mergerComboBox->addItem(T("Disabled"), 1);
76
    mergerComboBox->addItem(T("Enabled (received MIDI events forwarded to MIDI Out)"), 2);
1134 tk 77
    mergerComboBox->addItem(T("MIDIbox Link Endpoint (last core in the MIDIbox chain)"), 3);
78
    mergerComboBox->addItem(T("MIDIbox Link Forwarding Point (core in a MIDIbox chain)"), 4);
1131 tk 79
    mergerComboBox->setSelectedId(1, true);
1133 tk 80
    mergerComboBox->addListener(this);
1131 tk 81
 
82
    addAndMakeVisible(pwmStepsLabel = new Label(String::empty, T("PWM Steps:")));
83
    pwmStepsLabel->setJustificationType(Justification::right);
84
    addAndMakeVisible(pwmStepsSlider = new Slider(T("PWM Period")));
85
    pwmStepsSlider->setWantsKeyboardFocus(true);
86
    pwmStepsSlider->setSliderStyle(Slider::LinearHorizontal);
87
    pwmStepsSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 80, 20);
88
    pwmStepsSlider->setRange(0, 255, 1);
89
    pwmStepsSlider->setValue(64);
90
    pwmStepsSlider->addListener(this);
91
 
92
    addAndMakeVisible(ainDeadbandLabel = new Label(String::empty, T("AIN Deadband:")));
93
    ainDeadbandLabel->setJustificationType(Justification::right);
94
    addAndMakeVisible(ainDeadbandSlider = new Slider(T("AIN Deadband")));
95
    ainDeadbandSlider->setWantsKeyboardFocus(true);
96
    ainDeadbandSlider->setSliderStyle(Slider::LinearHorizontal);
97
    ainDeadbandSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 80, 20);
98
    ainDeadbandSlider->setRange(0, 63, 1);
99
    ainDeadbandSlider->setValue(3);
100
    ainDeadbandSlider->addListener(this);
101
 
102
    addAndMakeVisible(mfDeadbandLabel = new Label(String::empty, T("MF Deadband:")));
103
    mfDeadbandLabel->setJustificationType(Justification::right);
104
    addAndMakeVisible(mfDeadbandSlider = new Slider(T("MF Deadband")));
105
    mfDeadbandSlider->setWantsKeyboardFocus(true);
106
    mfDeadbandSlider->setSliderStyle(Slider::LinearHorizontal);
107
    mfDeadbandSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 80, 20);
108
    mfDeadbandSlider->setRange(0, 63, 1);
109
    mfDeadbandSlider->setValue(3);
110
    mfDeadbandSlider->addListener(this);
111
 
112
    addAndMakeVisible(touchSensorModeLabel = new Label(String::empty, T("TouchSensor Mode:")));
113
    touchSensorModeLabel->setJustificationType(Justification::right);
114
    addAndMakeVisible(touchSensorModeComboBox = new ComboBox(String::empty));
115
    touchSensorModeComboBox->setWantsKeyboardFocus(true);
116
    touchSensorModeComboBox->addItem(T("Disabled"), 1);
117
    touchSensorModeComboBox->addItem(T("Pressed/Depressed Events forwarded to MIDI Out"), 2);
118
    touchSensorModeComboBox->addItem(T("Like previous, but additionally motors will be suspended"), 3);
119
    touchSensorModeComboBox->addItem(T("Like previous, but additionally no fader event as long as sensor not pressed"), 4);
120
    touchSensorModeComboBox->setSelectedId(2, true);
1133 tk 121
    touchSensorModeComboBox->addListener(this);
1131 tk 122
 
123
    addAndMakeVisible(touchSensorSensitivityLabel = new Label(String::empty, T("Touchsensor Sensitivity:")));
124
    touchSensorSensitivityLabel->setJustificationType(Justification::right);
125
    addAndMakeVisible(touchSensorSensitivitySlider = new Slider(T("Touchsensor Sensitivity")));
126
    touchSensorSensitivitySlider->setWantsKeyboardFocus(true);
127
    touchSensorSensitivitySlider->setSliderStyle(Slider::LinearHorizontal);
128
    touchSensorSensitivitySlider->setTextBoxStyle(Slider::TextBoxLeft, false, 80, 20);
129
    touchSensorSensitivitySlider->setRange(1, 32, 1);
130
    touchSensorSensitivitySlider->setValue(3);
131
    touchSensorSensitivitySlider->addListener(this);
132
 
133
}
134
 
135
 
136
MbhpMfToolConfigGlobals::~MbhpMfToolConfigGlobals()
137
{
138
}
139
 
140
//==============================================================================
141
void MbhpMfToolConfigGlobals::resized()
142
{
143
    int labelX = 10;
144
    int labelY0 = 10;
145
    int labelYOffset = 28;
146
    int labelWidth = 250;
147
    int labelHeight = 24;
148
 
149
    int controlX = labelX + labelWidth + 20;
150
    int controlY0 = labelY0;
151
    int controlYOffset = labelYOffset;
152
    int controlWidth = getWidth()-labelWidth-40-2*labelX;
153
    int controlHeight = labelHeight;
154
 
155
    nameLabel->setBounds(labelX, labelY0 + 0*labelYOffset, labelWidth, labelHeight);
156
    nameEditor->setBounds(controlX, controlY0 + 0*controlYOffset, controlWidth, controlHeight);
157
 
158
    numberFadersLabel->setBounds(labelX, labelY0 + 1*labelYOffset, labelWidth, labelHeight);
159
    numberFadersSlider->setBounds(controlX, controlY0 + 1*controlYOffset, controlWidth, controlHeight);
160
 
161
    operationModeLabel->setBounds(labelX, labelY0 + 2*labelYOffset, labelWidth, labelHeight);
162
    operationModeComboBox->setBounds(controlX, controlY0 + 2*controlYOffset, controlWidth, controlHeight);
163
 
164
    mergerLabel->setBounds(labelX, labelY0 + 3*labelYOffset, labelWidth, labelHeight);
165
    mergerComboBox->setBounds(controlX, controlY0 + 3*controlYOffset, controlWidth, controlHeight);
166
 
167
    pwmStepsLabel->setBounds(labelX, labelY0 + 4*labelYOffset, labelWidth, labelHeight);
168
    pwmStepsSlider->setBounds(controlX, controlY0 + 4*controlYOffset, controlWidth, controlHeight);
169
 
170
    ainDeadbandLabel->setBounds(labelX, labelY0 + 5*labelYOffset, labelWidth, labelHeight);
171
    ainDeadbandSlider->setBounds(controlX, controlY0 + 5*controlYOffset, controlWidth, controlHeight);
172
 
173
    mfDeadbandLabel->setBounds(labelX, labelY0 + 6*labelYOffset, labelWidth, labelHeight);
174
    mfDeadbandSlider->setBounds(controlX, controlY0 + 6*controlYOffset, controlWidth, controlHeight);
175
 
176
    touchSensorModeLabel->setBounds(labelX, labelY0 + 7*labelYOffset, labelWidth, labelHeight);
177
    touchSensorModeComboBox->setBounds(controlX, controlY0 + 7*controlYOffset, controlWidth, controlHeight);
178
 
179
    touchSensorSensitivityLabel->setBounds(labelX, labelY0 + 8*labelYOffset, labelWidth, labelHeight);
180
    touchSensorSensitivitySlider->setBounds(controlX, controlY0 + 8*controlYOffset, controlWidth, controlHeight);
181
 
182
}
183
 
184
 
185
//==============================================================================
186
void MbhpMfToolConfigGlobals::sliderValueChanged(Slider* slider)
187
{
188
    if( slider == pwmStepsSlider ) {
189
        pwmStepsLabel->setText(String::formatted(T("PWM Steps (resulting period: %4.2f mS):"), (float)(slider->getValue()*0.05)), true);
190
    }
1133 tk 191
 
192
    // request SysEx update
193
    if( mbhpMfTool->mbhpMfToolControl != NULL )
194
        mbhpMfTool->mbhpMfToolControl->sysexUpdateRequest();
1131 tk 195
}
196
 
1133 tk 197
void MbhpMfToolConfigGlobals::comboBoxChanged(ComboBox*)
198
{
199
    // request SysEx update
200
    if( mbhpMfTool->mbhpMfToolControl != NULL )
201
        mbhpMfTool->mbhpMfToolControl->sysexUpdateRequest();
202
}
203
 
204
 
1131 tk 205
//==============================================================================
206
void MbhpMfToolConfigGlobals::getDump(Array<uint8> &syxDump)
207
{
208
    int numberFaders = numberFadersSlider->getValue();
209
    int operationMode = operationModeComboBox->getSelectedId()-1;
210
    int merger = mergerComboBox->getSelectedId()-1;
211
    int pwmSteps = pwmStepsSlider->getValue();
212
    int ainDeadband = ainDeadbandSlider->getValue();
213
    int mfDeadband = mfDeadbandSlider->getValue();
214
    int touchSensorMode = touchSensorModeComboBox->getSelectedId()-1;
215
    int touchSensorSensitivity = touchSensorSensitivitySlider->getValue();
216
 
217
    int i;
218
    String txt = nameEditor->getText();
219
    for(i=0; i<16 && i<txt.length(); ++i)
220
        syxDump.set(i, txt[i]);
221
    while( i < 16 ) {
222
        syxDump.set(i, 0);
223
        i++;
224
    }
225
    syxDump.set(0x10, numberFaders);
226
    syxDump.set(0x11, operationMode);
227
    syxDump.set(0x12, merger);
228
    syxDump.set(0x13, pwmSteps);
229
    syxDump.set(0x14, ainDeadband);
230
    syxDump.set(0x15, mfDeadband);
231
    syxDump.set(0x16, touchSensorMode);
232
    syxDump.set(0x17, touchSensorSensitivity);
233
 
234
}
235
 
236
void MbhpMfToolConfigGlobals::setDump(const Array<uint8> &syxDump)
237
{
238
    int numberFaders = syxDump[0x10];
239
    int operationMode = syxDump[0x11];
240
    int merger = syxDump[0x12];
241
    int pwmSteps = syxDump[0x13];
242
    int ainDeadband = syxDump[0x14];
243
    int mfDeadband = syxDump[0x15];
244
    int touchSensorMode = syxDump[0x16];
245
    int touchSensorSensitivity = syxDump[0x17];
246
 
247
    String txt;
248
    for(int i=0; i<16 && syxDump[i]; ++i) {
249
        char dummy = syxDump[i];
250
        txt += String(&dummy, 1);
251
    }
252
    nameEditor->setText(txt);
253
 
254
    numberFadersSlider->setValue(numberFaders);
255
    operationModeComboBox->setSelectedId(operationMode+1);
256
    mergerComboBox->setSelectedId(merger+1);
257
    pwmStepsSlider->setValue(pwmSteps);
258
    ainDeadbandSlider->setValue(ainDeadband);
259
    mfDeadbandSlider->setValue(mfDeadband);
260
    touchSensorModeComboBox->setSelectedId(touchSensorMode+1);
261
    touchSensorSensitivitySlider->setValue(touchSensorSensitivity);
262
}
263
 
264
 
265
//==============================================================================
266
//==============================================================================
267
//==============================================================================
268
MbhpMfToolCalibrationTable::MbhpMfToolCalibrationTable(MbhpMfTool* _mbhpMfTool)
269
    : mbhpMfTool(_mbhpMfTool)
270
    , font(14.0f)
271
    , numRows(8)
272
{
273
    for(int fader=0; fader<numRows; ++fader) {
274
        mfMode.add(0x01); // enabled and not inverted
1133 tk 275
        mfMinValue.add(20); // Default Min Value
276
        mfMaxValue.add(1000); // Default Max Value
277
        mfMinDutyUp.add(48); // Default Min Duty Upward Direction
278
        mfMaxDutyUp.add(64); // Default Max Duty Upward Direction
279
        mfMinDutyDown.add(48); // Default Min Duty Upward Direction
280
        mfMaxDutyDown.add(64); // Default Max Duty Upward Direction
1131 tk 281
    }
282
 
283
    addAndMakeVisible(table = new TableListBox(T("Motorfader Table"), this));
284
    table->setColour(ListBox::outlineColourId, Colours::grey);
285
    table->setOutlineThickness(1);
286
 
1187 tk 287
    table->getHeader().addColumn(T("MF"), 1, 25);
288
    table->getHeader().addColumn(T("Use"), 2, 40);
289
    table->getHeader().addColumn(T("InvM"), 3, 40);
290
    table->getHeader().addColumn(T("MinValue"), 4, 80);
291
    table->getHeader().addColumn(T("MaxValue"), 5, 80);
292
    table->getHeader().addColumn(T("MinDutyUp"), 6, 80);
293
    table->getHeader().addColumn(T("MaxDutyUp"), 7, 80);
294
    table->getHeader().addColumn(T("MinDutyDn"), 8, 80);
295
    table->getHeader().addColumn(T("MaxDutyDn"), 9, 80);
1131 tk 296
 
1133 tk 297
    setSize(400, 200);
1131 tk 298
}
299
 
300
MbhpMfToolCalibrationTable::~MbhpMfToolCalibrationTable()
301
{
302
}
303
 
304
//==============================================================================
305
int MbhpMfToolCalibrationTable::getNumRows()
306
{
307
    return numRows;
308
}
309
 
310
void MbhpMfToolCalibrationTable::paintRowBackground(Graphics &g, int rowNumber, int width, int height, bool rowIsSelected)
311
{
312
    if( rowIsSelected )
313
        g.fillAll(Colours::lightblue);
314
}
315
 
316
void MbhpMfToolCalibrationTable::paintCell(Graphics &g, int rowNumber, int columnId, int width, int height, bool rowIsSelected)
317
{
318
    g.setColour(Colours::black);
319
    g.setFont(font);
320
 
321
    switch( columnId ) {
322
    case 1: {
323
        const String text(rowNumber);
324
        g.drawText(text, 2, 0, width - 4, height, Justification::centred, true);
325
    } break;
326
    }
327
 
328
    g.setColour(Colours::black.withAlpha (0.2f));
329
    g.fillRect(width - 1, 0, 1, height);
330
}
331
 
332
 
333
Component* MbhpMfToolCalibrationTable::refreshComponentForCell(int rowNumber, int columnId, bool isRowSelected, Component* existingComponentToUpdate)
334
{
335
    switch( columnId ) {
336
    case 2:
337
    case 3: {
338
        ConfigTableToggleButton *toggleButton = (ConfigTableToggleButton *)existingComponentToUpdate;
339
 
340
        if( toggleButton == 0 )
341
            toggleButton = new ConfigTableToggleButton(*this);
342
 
343
        toggleButton->setRowAndColumn(rowNumber, columnId);
344
        return toggleButton;
345
    } break;
346
 
1133 tk 347
    case 4: {
348
        ConfigTableSlider *slider = (ConfigTableSlider *)existingComponentToUpdate;
349
 
350
        if( slider == 0 ) {
351
            slider = new ConfigTableSlider(*this);
352
            slider->setRange(0, 255);
353
        }
354
 
355
        slider->setRowAndColumn(rowNumber, columnId);
356
        return slider;
357
    } break;
358
 
1131 tk 359
    case 5: {
360
        ConfigTableSlider *slider = (ConfigTableSlider *)existingComponentToUpdate;
361
 
362
        if( slider == 0 ) {
363
            slider = new ConfigTableSlider(*this);
1133 tk 364
            slider->setRange(768, 1023);
1131 tk 365
        }
366
 
367
        slider->setRowAndColumn(rowNumber, columnId);
368
        return slider;
369
    } break;
370
 
371
    case 6:
1133 tk 372
    case 7:
373
    case 8:
374
    case 9: {
1131 tk 375
        ConfigTableSlider *slider = (ConfigTableSlider *)existingComponentToUpdate;
376
 
377
        if( slider == 0 ) {
378
            slider = new ConfigTableSlider(*this);
379
            slider->setRange(0, 255);
380
        }
381
 
382
        slider->setRowAndColumn(rowNumber, columnId);
383
        return slider;
384
    } break;
385
    }
386
 
387
    return 0;
388
}
389
 
390
 
391
//==============================================================================
392
void MbhpMfToolCalibrationTable::resized()
393
{
394
    // position our table with a gap around its edge
395
    table->setBoundsInset(BorderSize(8));
396
}
397
 
398
 
399
//==============================================================================
400
int MbhpMfToolCalibrationTable::getTableValue(const int rowNumber, const int columnId)
401
{
402
    switch( columnId ) {
1133 tk 403
    case 1: return rowNumber + 1; // doesn't work! :-/
1131 tk 404
    case 2: return (mfMode[rowNumber] & 1) ? 1 : 0;
405
    case 3: return (mfMode[rowNumber] & 2) ? 1 : 0;
406
    case 4: return mfMinValue[rowNumber];
407
    case 5: return mfMaxValue[rowNumber];
1133 tk 408
    case 6: return mfMinDutyUp[rowNumber];
409
    case 7: return mfMaxDutyUp[rowNumber];
410
    case 8: return mfMinDutyDown[rowNumber];
411
    case 9: return mfMaxDutyDown[rowNumber];
1131 tk 412
    }
413
    return 0;
414
}
415
 
416
void MbhpMfToolCalibrationTable::setTableValue(const int rowNumber, const int columnId, const int newValue)
417
{
418
    switch( columnId ) {
419
    case 2: mfMode.set(rowNumber, (mfMode[rowNumber] & 0xfe) | (newValue ? 1 : 0)); break;
420
    case 3: mfMode.set(rowNumber, (mfMode[rowNumber] & 0xfd) | (newValue ? 2 : 0)); break;
421
    case 4: mfMinValue.set(rowNumber, newValue); break;
422
    case 5: mfMaxValue.set(rowNumber, newValue); break;
1133 tk 423
    case 6: mfMinDutyUp.set(rowNumber, newValue); break;
424
    case 7: mfMaxDutyUp.set(rowNumber, newValue); break;
425
    case 8: mfMinDutyDown.set(rowNumber, newValue); break;
426
    case 9: mfMaxDutyDown.set(rowNumber, newValue); break;
1131 tk 427
    }
428
 
429
    // request SysEx update
430
    if( mbhpMfTool->mbhpMfToolControl != NULL )
431
        mbhpMfTool->mbhpMfToolControl->sysexUpdateRequest();
432
}
433
 
434
 
435
//==============================================================================
436
//==============================================================================
437
//==============================================================================
438
MbhpMfToolCalibrationCurve::MbhpMfToolCalibrationCurve()
439
{
440
}
441
 
442
 
443
MbhpMfToolCalibrationCurve::~MbhpMfToolCalibrationCurve()
444
{
445
}
446
 
447
//==============================================================================
448
// set from MbhpMfToolControl::handleIncomingMidiMessage once trace has been received
449
void MbhpMfToolCalibrationCurve::setTrace(const Array<uint16>& newTrace)
450
{
451
    traceMem = newTrace;
452
    repaint(); // update view
453
}
454
 
455
//==============================================================================
456
void MbhpMfToolCalibrationCurve::paint(Graphics& g)
457
{
458
    unsigned X0 = 0;
459
    unsigned Y0 = getHeight();
460
 
461
    g.fillAll(Colour(0xffeeeeee));
462
 
463
    // frame around diagram
464
    {
465
        Path p;
466
        p.startNewSubPath(0, 0);
467
        p.lineTo(getWidth(), 0);
468
        p.lineTo(getWidth(), getHeight());
469
        p.lineTo(0, getHeight());
470
        //p.lineTo(0, 0);
471
        p.closeSubPath();
472
 
473
        PathStrokeType stroke(2.0f);
474
        g.setColour(Colour(0xff222222));
475
        g.strokePath (p, stroke, AffineTransform::identity);
476
    }
477
 
478
 
479
    // getWidth() usually 256, so that each traced mS can be displayed
480
    // vertical lines w/ 50 mS distance
481
    for(int x=50; x<getWidth(); x+=50) {
482
        Path p;
483
        p.startNewSubPath(x+0, Y0-0);
484
        p.lineTo(x+0, 0);
485
        //p.closeSubPath();
486
 
487
        PathStrokeType stroke(1.0f);
488
        g.setColour(Colour(0xff888888));
489
        g.strokePath (p, stroke, AffineTransform::identity);
490
    }
491
 
492
    // getHeight() usually 256 (mfValue / 4)
493
    // horizontal lines w/ 64 pixel distance
494
    for(int y=64; y<getHeight(); y+=64) {
495
        Path p;
496
        p.startNewSubPath(0, y);
497
        p.lineTo(getWidth(), y);
498
        //p.closeSubPath();
499
 
500
        PathStrokeType stroke(1.0f);
501
        g.setColour(Colour(0xff888888));
502
        g.strokePath (p, stroke, AffineTransform::identity);
503
    }
504
 
505
    // the final curve
506
    if( traceMem.size() && traceMem[0] < 0x400 ) {
507
        Path p;
508
        p.startNewSubPath(X0, Y0 - (traceMem[0] / 4));
509
 
510
        for(int i=1; i<traceMem.size(); ++i) {
511
            if( traceMem[i] >= 0x400 ) // end marker
512
                break;
513
            p.lineTo(X0+i, Y0 - (traceMem[i] / 4));
514
        }
515
        //p.closeSubPath();
516
 
517
        PathStrokeType stroke(3.0f);
518
        g.setColour(Colours::purple.withAlpha ((float)1.0));
519
        g.strokePath (p, stroke, AffineTransform::identity);
520
    }
521
 
522
}
523
 
524
 
525
//==============================================================================
526
//==============================================================================
527
//==============================================================================
528
MbhpMfToolCalibration::MbhpMfToolCalibration(MbhpMfTool* _mbhpMfTool)
529
    : mbhpMfTool(_mbhpMfTool)
530
    , timerGeneratesSineWaveform(false)
531
    , sinePhase(0.0)
532
{
533
    addAndMakeVisible(calibrationTable = new MbhpMfToolCalibrationTable(_mbhpMfTool));
534
 
535
    addAndMakeVisible(calibrationCurve = new MbhpMfToolCalibrationCurve);
536
    addAndMakeVisible(calibrationCurveLabel = new Label(String::empty, T("x=50 mS per unit, y=256 steps per unit")));
537
    calibrationCurveLabel->setJustificationType(Justification::horizontallyCentred);
538
 
539
    addAndMakeVisible(traceSliderLabel = new Label(String::empty, T("Fader which should be traced:")));
540
    traceSliderLabel->setJustificationType(Justification::left);
541
 
542
    addAndMakeVisible(traceSlider = new Slider(T("Trace Fader")));
543
    traceSlider->setRange(1, 8, 1);
544
    traceSlider->setValue(1);
545
    traceSlider->setSliderStyle(Slider::IncDecButtons);
1133 tk 546
    traceSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 50, 20);
1131 tk 547
    traceSlider->setDoubleClickReturnValue(true, 0);
548
    traceSlider->addListener(this);
549
 
550
    addAndMakeVisible(traceScaleSliderLabel = new Label(String::empty, T("Trace Scale (x * mS):")));
551
    traceScaleSliderLabel->setJustificationType(Justification::left);
552
 
553
    addAndMakeVisible(traceScaleSlider = new Slider(T("TraceScale Fader")));
554
    traceScaleSlider->setRange(1, 10, 1);
555
    traceScaleSlider->setValue(1);
556
    traceScaleSlider->setSliderStyle(Slider::IncDecButtons);
1133 tk 557
    traceScaleSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 50, 20);
1131 tk 558
    traceScaleSlider->setDoubleClickReturnValue(true, 0);
559
    traceScaleSlider->addListener(this);
560
 
1133 tk 561
    addAndMakeVisible(directMoveSliderLabel = new Label(String::empty, T("Direct Move:")));
562
    directMoveSliderLabel->setJustificationType(Justification::left);
563
 
564
    addAndMakeVisible(directMoveSlider = new Slider(T("DirectMove Fader")));
565
    directMoveSlider->setRange(0, 1023, 1);
566
    directMoveSlider->setValue(512);
567
    directMoveSlider->setSliderStyle(Slider::IncDecButtons);
568
    directMoveSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 50, 20);
569
    directMoveSlider->setDoubleClickReturnValue(true, 0);
570
    directMoveSlider->addListener(this);
571
 
1131 tk 572
    addAndMakeVisible(upperButton = new TextButton(T("Upper")));
1502 tk 573
    upperButton->addListener(this);
1131 tk 574
 
575
    addAndMakeVisible(middleButton = new TextButton(T("Middle")));
1502 tk 576
    middleButton->addListener(this);
1131 tk 577
 
578
    addAndMakeVisible(lowerButton = new TextButton(T("Lower")));
1502 tk 579
    lowerButton->addListener(this);
1131 tk 580
 
581
    addAndMakeVisible(slashButton = new TextButton(T("Slash")));
1502 tk 582
    slashButton->addListener(this);
1131 tk 583
 
584
    addAndMakeVisible(backslashButton = new TextButton(T("Backslash")));
1502 tk 585
    backslashButton->addListener(this);
1131 tk 586
 
587
    addAndMakeVisible(slowUpperButton = new TextButton(T("Slow Upper")));
1502 tk 588
    slowUpperButton->addListener(this);
1131 tk 589
 
590
    addAndMakeVisible(slowMiddleButton = new TextButton(T("Slow Middle")));
1502 tk 591
    slowMiddleButton->addListener(this);
1131 tk 592
 
593
    addAndMakeVisible(slowLowerButton = new TextButton(T("Slow Lower")));
1502 tk 594
    slowLowerButton->addListener(this);
1131 tk 595
 
596
    addAndMakeVisible(slowSineButton = new TextButton(T("Slow Sine")));
1502 tk 597
    slowSineButton->addListener(this);
1131 tk 598
 
599
    addAndMakeVisible(delayLabel = new Label(String::empty, T("Slow Delay:")));
600
    delayLabel->setJustificationType(Justification::left);
601
 
602
    addAndMakeVisible(delaySlider = new Slider(T("Delay")));
603
    delaySlider->setRange(0, 200, 1);
604
    delaySlider->setValue(10);
605
    delaySlider->setSliderStyle(Slider::IncDecButtons);
606
    delaySlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
607
    delaySlider->setDoubleClickReturnValue(true, 0);
608
 
609
    addAndMakeVisible(delayStepsLabel = new Label(String::empty, T("Slow Steps:")));
610
    delayStepsLabel->setJustificationType(Justification::left);
611
 
612
    addAndMakeVisible(delayStepsSlider = new Slider(T("DelaySteps")));
613
    delayStepsSlider->setRange(1, 100, 1);
614
    delayStepsSlider->setValue(4);
615
    delayStepsSlider->setSliderStyle(Slider::IncDecButtons);
616
    delayStepsSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
617
    delayStepsSlider->setDoubleClickReturnValue(true, 0);
618
 
619
    // for slow calibration moves
620
    for(int mf=0; mf<8; ++mf) {
621
        targetMfValues.set(mf, 0);
622
        currentMfValues.set(mf, 0xffff); // ensure that current values are invalid
623
    }
624
 
625
    setSize(800, 300);
626
}
627
 
628
MbhpMfToolCalibration::~MbhpMfToolCalibration()
629
{
630
}
631
 
632
//==============================================================================
633
void MbhpMfToolCalibration::resized()
634
{
635
    int buttonWidth = 72;
636
    int buttonHeight = 20;
637
 
638
    int tableX0 = 0;
639
    int tableY0 = 0;
1133 tk 640
    int tableWidth = 700;
1131 tk 641
    int tableHeight = 230;
642
 
643
    calibrationTable->setBounds(tableX0, tableY0, tableWidth, tableHeight);
644
 
1133 tk 645
    int curveX0 = 8;
646
    int curveY0 = tableY0 + tableHeight;
1131 tk 647
    int curveWidth = 256;
648
    int curveHeight = 256;
649
    calibrationCurve->setBounds(curveX0, curveY0, curveWidth, curveHeight);
650
    calibrationCurveLabel->setBounds(curveX0, curveY0+curveHeight, curveWidth, buttonHeight);
651
 
1133 tk 652
    int traceSliderWidth = 90;
653
    traceSliderLabel->setBounds(curveX0, curveY0+curveHeight+1*buttonHeight, curveWidth-traceSliderWidth-10, buttonHeight);
654
    traceSlider->setBounds(curveX0 + curveWidth-traceSliderWidth, curveY0+curveHeight+1*buttonHeight, traceSliderWidth, buttonHeight);
655
    traceScaleSliderLabel->setBounds(curveX0, curveY0+curveHeight+2*buttonHeight, curveWidth-traceSliderWidth-10, buttonHeight);
656
    traceScaleSlider->setBounds(curveX0 + curveWidth-traceSliderWidth, curveY0+curveHeight+2*buttonHeight, traceSliderWidth, buttonHeight);
657
    directMoveSliderLabel->setBounds(curveX0, curveY0+curveHeight+3*buttonHeight, curveWidth-traceSliderWidth-10, buttonHeight);
658
    directMoveSlider->setBounds(curveX0 + curveWidth-traceSliderWidth, curveY0+curveHeight+3*buttonHeight, traceSliderWidth, buttonHeight);
659
 
660
    int buttonX0 = curveX0 + curveWidth + 10;
661
    int buttonY0 = curveY0 + 10;
1131 tk 662
    int buttonYd = buttonHeight + 4;
663
 
664
    upperButton->setBounds(buttonX0, buttonY0 + 0*buttonYd, buttonWidth, buttonHeight);
665
    middleButton->setBounds(buttonX0, buttonY0 + 1*buttonYd, buttonWidth, buttonHeight);
666
    lowerButton->setBounds(buttonX0, buttonY0 + 2*buttonYd, buttonWidth, buttonHeight);
667
    slashButton->setBounds(buttonX0, buttonY0 + 3*buttonYd, buttonWidth, buttonHeight);
668
    backslashButton->setBounds(buttonX0, buttonY0 + 4*buttonYd, buttonWidth, buttonHeight);
669
 
670
    slowUpperButton->setBounds(buttonX0+buttonWidth+8, buttonY0 + 0*buttonYd, buttonWidth, buttonHeight);
671
    slowMiddleButton->setBounds(buttonX0+buttonWidth+8, buttonY0 + 1*buttonYd, buttonWidth, buttonHeight);
672
    slowLowerButton->setBounds(buttonX0+buttonWidth+8, buttonY0 + 2*buttonYd, buttonWidth, buttonHeight);
673
    slowSineButton->setBounds(buttonX0+buttonWidth+8, buttonY0 + 3*buttonYd, buttonWidth, buttonHeight);
674
 
675
    delayLabel->setBounds(buttonX0, buttonY0 + 6*buttonYd, buttonWidth, buttonHeight);
676
    delaySlider->setBounds(buttonX0+buttonWidth+8, buttonY0 + 6*buttonYd, buttonWidth, buttonHeight);
677
    delayStepsLabel->setBounds(buttonX0, buttonY0 + 7*buttonYd, buttonWidth, buttonHeight);
678
    delayStepsSlider->setBounds(buttonX0+buttonWidth+8, buttonY0 + 7*buttonYd, buttonWidth, buttonHeight);
679
 
680
}
681
 
682
//==============================================================================
683
void MbhpMfToolCalibration::sliderValueChanged(Slider* slider)
684
{
685
    if( slider == traceScaleSlider ) {
686
        calibrationCurveLabel->setText(String::
687
formatted(T("x=%d mS per unit, y=256 steps per unit"), (unsigned)traceScaleSlider->getValue()*50), true);
688
        Array<uint16> emptyTrace;
689
        calibrationCurve->setTrace(emptyTrace);
690
    } else if( slider == traceSlider ) {
691
        Array<uint16> emptyTrace;
692
        calibrationCurve->setTrace(emptyTrace);
1133 tk 693
    } else if( slider == directMoveSlider ) {
694
        uint8 traceFader = traceSlider->getValue() - 1;
695
        uint8 traceFaderScale = traceScaleSlider->getValue();
696
 
697
        // request trace update
698
        {
699
 
700
            Array<uint16> emptyTrace;
701
            calibrationCurve->setTrace(emptyTrace);
702
 
703
            // request values
704
            Array<uint8> requestTraceSyx = SysexHelper::createMbhpMfTraceRequest((uint8)mbhpMfTool->mbhpMfToolControl->deviceIdSlider->getValue(),
705
                                                                                 traceFader,
706
                                                                                 traceFaderScale);
707
            MidiMessage message = SysexHelper::createMidiMessage(requestTraceSyx);
708
            mbhpMfTool->miosStudio->sendMidiMessage(message);
709
        }
710
 
711
        // send new fader pos
712
        Array<uint16> faderValue;
713
        faderValue.add(directMoveSlider->getValue());
714
 
715
        Array<uint8> faderSnapshotSyx = SysexHelper::createMbhpMfFadersSet((uint8)mbhpMfTool->mbhpMfToolControl->deviceIdSlider->getValue(),
716
                                                                           traceFader,
717
                                                                           faderValue);
718
        MidiMessage message = SysexHelper::createMidiMessage(faderSnapshotSyx);
719
        mbhpMfTool->miosStudio->sendMidiMessage(message);
1131 tk 720
    }
721
}
722
 
723
//==============================================================================
724
void MbhpMfToolCalibration::buttonClicked(Button* buttonThatWasClicked)
725
{
726
    unsigned delay = 0;
727
    uint8 traceFader = traceSlider->getValue() - 1;
728
    uint8 traceFaderScale = traceScaleSlider->getValue();
729
 
730
    if( buttonThatWasClicked == upperButton ) {
731
        for(int mf=0; mf<8; ++mf)
732
            targetMfValues.set(mf, 1023);
733
    } else if( buttonThatWasClicked == middleButton ) {
734
        for(int mf=0; mf<8; ++mf)
735
            targetMfValues.set(mf, 512);
736
    } else if( buttonThatWasClicked == lowerButton ) {
737
        for(int mf=0; mf<8; ++mf)
738
            targetMfValues.set(mf, 0);
739
    } else if( buttonThatWasClicked == slashButton ) {
740
        for(int mf=0; mf<8; ++mf)
741
            targetMfValues.set(mf, mf*128 + 64);
742
    } else if( buttonThatWasClicked == backslashButton ) {
743
        for(int mf=0; mf<8; ++mf)
744
            targetMfValues.set(mf, 1024 - (mf*128 + 64));
745
    } else if( buttonThatWasClicked == slowUpperButton ) {
746
        for(int mf=0; mf<8; ++mf)
747
            targetMfValues.set(mf, 1023);
748
        delay = delaySlider->getValue();
749
    } else if( buttonThatWasClicked == slowMiddleButton ) {
750
        for(int mf=0; mf<8; ++mf)
751
            targetMfValues.set(mf, 512);
752
        delay = delaySlider->getValue();
753
    } else if( buttonThatWasClicked == slowLowerButton ) {
754
        for(int mf=0; mf<8; ++mf)
755
            targetMfValues.set(mf, 0);
756
        delay = delaySlider->getValue();
757
    } else if( buttonThatWasClicked == slowSineButton ) {
758
        for(int mf=0; mf<8; ++mf) // values generated by timer
759
            targetMfValues.set(mf, 0);
760
        delay = delaySlider->getValue();
761
    }
762
 
763
    if( targetMfValues.size() ) {
764
        timerGeneratesSineWaveform = buttonThatWasClicked == slowSineButton;
765
 
766
        // request trace update
767
        {
768
            Array<uint16> emptyTrace;
769
            calibrationCurve->setTrace(emptyTrace);
770
 
771
            // request values
772
            Array<uint8> requestTraceSyx = SysexHelper::createMbhpMfTraceRequest((uint8)mbhpMfTool->mbhpMfToolControl->deviceIdSlider->getValue(),
773
                                                                                 traceFader,
774
                                                                                 traceFaderScale);
775
            MidiMessage message = SysexHelper::createMidiMessage(requestTraceSyx);
776
            mbhpMfTool->miosStudio->sendMidiMessage(message);
777
        }
778
 
779
        if( !delay ) {
780
            // stop any timer operation
781
            stopTimer();
782
 
783
            // set fader values
784
            Array<uint8> faderSnapshotSyx = SysexHelper::createMbhpMfFadersSet((uint8)mbhpMfTool->mbhpMfToolControl->deviceIdSlider->getValue(),
785
                                                                           0x00,
786
                                                                           targetMfValues);
787
            MidiMessage message = SysexHelper::createMidiMessage(faderSnapshotSyx);
788
            mbhpMfTool->miosStudio->sendMidiMessage(message);
789
 
790
            // store new values for slow moves
791
            for(int mf=0; mf<8; ++mf)
792
                currentMfValues.set(mf, targetMfValues[mf]);
793
        } else {
794
            // initial state: if currentMfValues 0xffff, we have to initialize them somehow
795
            for(int mf=0; mf<8; ++mf)
796
                if( currentMfValues[mf] == 0xffff )
797
                    currentMfValues.set(mf, 0x3ff-targetMfValues[mf]);
798
 
799
            // start timer which moves the faders slowly
800
            startTimer(1);
801
        }
802
    }
1133 tk 803
 
804
    // update "direct move" slider
805
    directMoveSlider->setValue(currentMfValues[traceFader]);
1131 tk 806
}
807
 
808
//==============================================================================
809
void MbhpMfToolCalibration::timerCallback()
810
{
1133 tk 811
    uint8 traceFader = traceSlider->getValue() - 1;
812
 
1131 tk 813
    stopTimer(); // will be restarted if required
814
    bool targetReached = true;
815
 
816
    // move faders into target direction depending on specified range
817
    int stepRange = delayStepsSlider->getValue();
818
    if( !stepRange ) stepRange = 1;
819
 
820
    if( timerGeneratesSineWaveform ) {
821
        targetReached = false; // target never reached... endless waveform generation (until another button has been pressed)
822
        sinePhase += (float)stepRange;
823
        while( sinePhase >= 360 )
824
            sinePhase -= 360;
825
 
826
        for(int mf=0; mf<8; ++mf) {
827
            int value = 0x200 + 0x200 * sin(2*3.14159 * ((sinePhase+mf*20) / 360));
828
            if( value >= 0x400 ) value = 0x3ff;
829
            if( value < 0 ) value = 0;
830
            currentMfValues.set(mf, value);
831
        }
832
    } else {
833
        for(int mf=0; mf<8; ++mf) {
834
            int current = currentMfValues[mf];
835
            int target = targetMfValues[mf];
836
 
837
            if( current != target ) {
838
                if( target > current ) {
839
                    current += stepRange;
840
                    if( current > target )
841
                        current = target;
842
                } else {
843
                    current -= stepRange;
844
                    if( current < target )
845
                        current = target;
846
                }
847
 
848
                currentMfValues.set(mf, current);
849
            }
850
        }
851
 
852
        // restart timer if target values not reached yet
853
        for(int mf=0; mf<8 && targetReached; ++mf)
854
            if( currentMfValues[mf] != targetMfValues[mf] )
855
                targetReached = false;
856
    }
857
 
858
    // set fader values
859
    Array<uint8> faderSnapshotSyx = SysexHelper::createMbhpMfFadersSet((uint8)mbhpMfTool->mbhpMfToolControl->deviceIdSlider->getValue(),
860
                                                                           0x00,
861
                                                                           currentMfValues);
862
    MidiMessage message = SysexHelper::createMidiMessage(faderSnapshotSyx);
863
    mbhpMfTool->miosStudio->sendMidiMessage(message);
864
 
1133 tk 865
    // update "direct move" slider
866
    directMoveSlider->setValue(currentMfValues[traceFader]);
867
 
1131 tk 868
    // restart timer?
869
    if( !targetReached ) {
870
        int delay = delaySlider->getValue();
871
        if( !delay ) delay = 1;
872
        startTimer(delay);
873
    }
874
}
875
 
876
//==============================================================================
877
void MbhpMfToolCalibration::getDump(Array<uint8> &syxDump)
878
{
879
    for(int mf=0; mf<8; ++mf) {
880
        syxDump.set(0x20 + 0*8+mf, calibrationTable->mfMode[mf]);
1133 tk 881
        syxDump.set(0x20 + 1*8+mf, calibrationTable->mfMinValue[mf] & 0xff); // only low-byte will be stored (0..255)
882
        syxDump.set(0x20 + 2*8+mf, calibrationTable->mfMaxValue[mf] & 0xff); // only low-byte will be stored (768..1023)
883
        syxDump.set(0x20 + 3*8+mf, calibrationTable->mfMinDutyUp[mf]);
884
        syxDump.set(0x20 + 4*8+mf, calibrationTable->mfMaxDutyUp[mf]);
885
        syxDump.set(0x20 + 5*8+mf, calibrationTable->mfMinDutyDown[mf]);
886
        syxDump.set(0x20 + 6*8+mf, calibrationTable->mfMaxDutyDown[mf]);
1131 tk 887
    }
888
}
889
 
890
void MbhpMfToolCalibration::setDump(const Array<uint8> &syxDump)
891
{
892
    for(int mf=0; mf<8; ++mf) {
893
        calibrationTable->mfMode.set(mf, syxDump[0x20 + 0*8+mf]);
1133 tk 894
        unsigned minValue = syxDump[0x20 + 1*8+mf]; // only low-byte will be stored (0..255)
1131 tk 895
        calibrationTable->mfMinValue.set(mf, minValue);
1133 tk 896
        unsigned maxValue = syxDump[0x20 + 2*8+mf] + 768; // only low-byte will be stored (768..1023)
1131 tk 897
        calibrationTable->mfMaxValue.set(mf, maxValue);
1133 tk 898
        calibrationTable->mfMinDutyUp.set(mf, syxDump[0x20 + 3*8+mf]);
899
        calibrationTable->mfMaxDutyUp.set(mf, syxDump[0x20 + 4*8+mf]);
900
        calibrationTable->mfMinDutyDown.set(mf, syxDump[0x20 + 5*8+mf]);
901
        calibrationTable->mfMaxDutyDown.set(mf, syxDump[0x20 + 6*8+mf]);
1131 tk 902
    }
903
    calibrationTable->table->updateContent();
904
}
905
 
906
 
907
 
908
//==============================================================================
909
//==============================================================================
910
//==============================================================================
911
MbhpMfToolConfig::MbhpMfToolConfig(MbhpMfTool *_mbhpMfTool)
912
    : mbhpMfTool(_mbhpMfTool)
913
    , TabbedComponent(TabbedButtonBar::TabsAtTop)
914
{
915
    addTab(T("Global"),   Colour(0xfff0f0e0), configGlobals = new MbhpMfToolConfigGlobals(mbhpMfTool), true);
916
    addTab(T("Calibration"), Colour(0xfff0f0d0), calibration = new MbhpMfToolCalibration(mbhpMfTool), true);
917
    setSize(800, 300);
918
}
919
 
920
MbhpMfToolConfig::~MbhpMfToolConfig()
921
{
922
}
923
 
924
//==============================================================================
925
void MbhpMfToolConfig::getDump(Array<uint8> &syxDump)
926
{
927
    for(int addr=0x000; addr<0x460; ++addr)
928
        syxDump.set(addr, 0x00);
929
    for(int addr=0x460; addr<0x600; ++addr)
930
        syxDump.set(addr, 0x7f);
931
 
932
    configGlobals->getDump(syxDump);
933
    calibration->getDump(syxDump);
934
}
935
 
936
void MbhpMfToolConfig::setDump(const Array<uint8> &syxDump)
937
{
938
    configGlobals->setDump(syxDump);
939
    calibration->setDump(syxDump);
940
}
941
 
942
 
943
 
944
//==============================================================================
945
//==============================================================================
946
//==============================================================================
947
MbhpMfToolControl::MbhpMfToolControl(MiosStudio *_miosStudio, MbhpMfToolConfig *_mbhpMfToolConfig)
948
    : miosStudio(_miosStudio)
949
    , mbhpMfToolConfig(_mbhpMfToolConfig)
950
    , progress(0)
951
    , receiveDump(false)
1133 tk 952
    , sendCompleteDump(false)
953
    , sendChangedDump(false)
1131 tk 954
    , dumpRequested(false)
955
    , dumpReceived(false)
956
    , checksumError(false)
957
    , dumpSent(false)
958
{
959
    addAndMakeVisible(loadButton = new TextButton(T("Load")));
1502 tk 960
    loadButton->addListener(this);
1131 tk 961
 
962
    addAndMakeVisible(saveButton = new TextButton(T("Save")));
1502 tk 963
    saveButton->addListener(this);
1131 tk 964
 
965
    addAndMakeVisible(deviceIdLabel = new Label(T("Device ID"), T("Device ID:")));
966
    deviceIdLabel->setJustificationType(Justification::right);
967
 
968
    addAndMakeVisible(deviceIdSlider = new Slider(T("Device ID")));
969
    deviceIdSlider->setRange(0, 127, 1);
970
    deviceIdSlider->setSliderStyle(Slider::IncDecButtons);
971
    deviceIdSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
972
    deviceIdSlider->setDoubleClickReturnValue(true, 0);
973
 
974
    addAndMakeVisible(patchLabel = new Label(T("Patch"), T("Patch:")));
975
    patchLabel->setJustificationType(Justification::right);
976
    patchLabel->setVisible(false); // no patches provided by MBHP_MF
977
 
978
    addAndMakeVisible(patchSlider = new Slider(T("Patch")));
979
    patchSlider->setRange(1, 128, 1);
980
    patchSlider->setSliderStyle(Slider::IncDecButtons);
981
    patchSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
982
    patchSlider->setDoubleClickReturnValue(true, 0);
983
    patchSlider->setVisible(false); // no patches provided by MBHP_MF
984
 
985
    addAndMakeVisible(receiveButton = new TextButton(T("Receive")));
1502 tk 986
    receiveButton->addListener(this);
1131 tk 987
 
988
    addAndMakeVisible(sendButton = new TextButton(T("Send")));
1502 tk 989
    sendButton->addListener(this);
1131 tk 990
 
991
    addAndMakeVisible(progressBar = new ProgressBar(progress));
992
 
993
    // restore settings
994
    PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
995
    if( propertiesFile ) {
996
        deviceIdSlider->setValue(propertiesFile->getIntValue(T("mbhpMfDeviceId"), 0) & 0x7f);
997
        patchSlider->setValue(propertiesFile->getIntValue(T("mbhpMfPatch"), 0) & 0x7f);
998
        String syxFileName(propertiesFile->getValue(T("mbhpMfSyxFile"), String::empty));
999
        if( syxFileName != String::empty )
1000
            syxFile = File(syxFileName);
1001
    }
1002
 
1003
    // revert patch number change - no patches provided by MBHP_MF
1004
    patchSlider->setValue(0);
1005
 
1006
    setSize(800, 300);
1007
}
1008
 
1009
MbhpMfToolControl::~MbhpMfToolControl()
1010
{
1011
}
1012
 
1013
//==============================================================================
1014
void MbhpMfToolControl::paint (Graphics& g)
1015
{
1016
    g.fillAll(Colours::white);
1017
}
1018
 
1019
void MbhpMfToolControl::resized()
1020
{
1021
    int buttonX0 = 10;
1022
    int buttonXOffset = 80;
1023
    int buttonY = 8;
1024
    int buttonWidth = 72;
1025
    int buttonHeight = 24;
1026
 
1027
    loadButton->setBounds(buttonX0 + 0*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1028
    saveButton->setBounds(buttonX0 + 1*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1029
 
1030
    deviceIdLabel->setBounds(buttonX0 + 20+2*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1031
    deviceIdSlider->setBounds(buttonX0 + 20+3*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1032
 
1133 tk 1033
#if 0
1131 tk 1034
    patchLabel->setBounds(buttonX0 + 20+4*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1035
    patchSlider->setBounds(buttonX0 + 20+5*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1036
 
1037
    receiveButton->setBounds(buttonX0 + 40+6*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1038
    sendButton->setBounds(buttonX0 + 40+7*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1133 tk 1039
#else
1040
    receiveButton->setBounds(buttonX0 + 40+4*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1041
    sendButton->setBounds(buttonX0 + 40+5*buttonXOffset, buttonY, buttonWidth, buttonHeight);
1042
#endif
1131 tk 1043
 
1044
    int progressBarX = sendButton->getX() + buttonWidth + 20;
1045
    progressBar->setBounds(progressBarX, buttonY, getWidth()-progressBarX-buttonX0, buttonHeight);
1046
}
1047
 
1048
//==============================================================================
1049
void MbhpMfToolControl::buttonClicked(Button* buttonThatWasClicked)
1050
{
1051
    if( buttonThatWasClicked == loadButton ) {
1052
        FileChooser fc(T("Choose a .syx file that you want to open..."),
1053
                       syxFile,
1054
                       T("*.syx"));
1055
 
1056
        if( fc.browseForFileToOpen() ) {
1057
            syxFile = fc.getResult();
1058
            if( loadSyx(syxFile) ) {
1059
                PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
1060
                if( propertiesFile )
1061
                    propertiesFile->setValue(T("mbhpMfSyxFile"), syxFile.getFullPathName());
1062
            }
1063
        }
1064
    } else if( buttonThatWasClicked == saveButton ) {
1065
        FileChooser fc(T("Choose a .syx file that you want to save..."),
1066
                       syxFile,
1067
                       T("*.syx"));
1068
        if( fc.browseForFileToSave(true) ) {
1069
            syxFile = fc.getResult();
1070
            if( saveSyx(syxFile) ) {
1071
                PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
1072
                if( propertiesFile )
1073
                    propertiesFile->setValue(T("mbhpMfSyxFile"), syxFile.getFullPathName());
1074
            }
1075
        }
1076
    } else if( buttonThatWasClicked == sendButton || buttonThatWasClicked == receiveButton ) {
1077
        loadButton->setEnabled(false);
1078
        saveButton->setEnabled(false);
1079
        sendButton->setEnabled(false);
1080
        receiveButton->setEnabled(false);
1081
        progress = 0;
1502 tk 1082
        checksumError = false;
1131 tk 1083
        if( buttonThatWasClicked == receiveButton ) {
1084
            dumpRequested = false;
1085
            receiveDump = true;
1133 tk 1086
            sendCompleteDump = false;
1087
            sendChangedDump = false;
1131 tk 1088
            currentSyxDump.clear();
1089
        } else {
1090
            receiveDump = false;
1133 tk 1091
            sendCompleteDump = true;
1092
            sendChangedDump = false;
1131 tk 1093
            dumpSent = false;
1094
        }
1095
        startTimer(1);
1096
    }
1097
}
1098
 
1099
//==============================================================================
1100
void MbhpMfToolControl::sliderValueChanged(Slider* slider)
1101
{
1102
    if( slider == deviceIdSlider ) {
1103
        // store setting
1104
        PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
1105
        if( propertiesFile )
1106
            propertiesFile->setValue(T("mbhpMfDeviceId"), (int)slider->getValue());
1107
    } else if( slider == patchSlider ) {
1108
        // store setting
1109
        PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
1110
        if( propertiesFile )
1111
            propertiesFile->setValue(T("mbhpMfPatch"), (int)slider->getValue());
1112
    }
1113
}
1114
 
1115
 
1116
//==============================================================================
1117
void MbhpMfToolControl::sysexUpdateRequest(void)
1118
{
1133 tk 1119
    // get initial dump
1120
    // this will already happen after startup of MIOS Studio, the function is called
1121
    // from MbhpMfTool constructor as well!
1122
    if( !currentSyxDump.size() )
1123
        mbhpMfToolConfig->getDump(currentSyxDump);
1124
 
1125
    // send changed dump values within 10 mS
1131 tk 1126
    // can be called whenever a configuration value has been changed
1133 tk 1127
    if( sendButton->isEnabled() ) {
1131 tk 1128
        receiveDump = false;
1133 tk 1129
        sendCompleteDump = false;
1130
        sendChangedDump = true;
1131 tk 1131
        dumpSent = false;
1132
        loadButton->setEnabled(false);
1133
        saveButton->setEnabled(false);
1134
        sendButton->setEnabled(false);
1135
        receiveButton->setEnabled(false);
1136
        startTimer(10);
1137
    }
1138
}
1139
 
1140
//==============================================================================
1141
void MbhpMfToolControl::timerCallback()
1142
{
1143
    stopTimer(); // will be restarted if required
1144
 
1145
    bool transferFinished = false;
1146
 
1147
    if( receiveDump ) {
1148
        if( dumpRequested ) {
1149
            if( !dumpReceived ) {
1150
                transferFinished = true;
1151
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
1152
                                            T("No response from core."),
1153
                                            T("Check:\n- MIDI In/Out connections\n- Device ID\n- that MBHP_MF firmware has been uploaded"),
1154
                                            String::empty);
1155
            } else if( checksumError ) {
1156
                transferFinished = true;
1157
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
1158
                                            T("Detected checksum error!"),
1159
                                            T("Check:\n- MIDI In/Out connections\n- your MIDI interface"),
1160
                                            String::empty);
1161
            } else {
1162
                mbhpMfToolConfig->setDump(currentSyxDump);
1163
                transferFinished = true;
1164
            }
1165
        } else {
1166
            dumpReceived = false;
1167
            checksumError = false;
1168
            dumpRequested = true;
1169
            Array<uint8> data = SysexHelper::createMbhpMfReadPatch((uint8)deviceIdSlider->getValue(),
1170
                                                                 (int)patchSlider->getValue()-1);
1171
            MidiMessage message = SysexHelper::createMidiMessage(data);
1172
            miosStudio->sendMidiMessage(message);
1173
 
1174
            progress = 1.0;
1175
            startTimer(1000);
1176
        }
1133 tk 1177
    } else if( sendCompleteDump || sendChangedDump ) {
1131 tk 1178
        if( dumpSent ) {
1179
            transferFinished = true;
1133 tk 1180
            sendCompleteDump = false;
1181
            sendChangedDump = false;
1131 tk 1182
        } else {
1133 tk 1183
            bool anyValueChanged = false;
1131 tk 1184
 
1133 tk 1185
            if( sendCompleteDump ) {
1186
                mbhpMfToolConfig->getDump(currentSyxDump);
1187
                anyValueChanged = true;
1188
                Array<uint8> data = SysexHelper::createMbhpMfWritePatch((uint8)deviceIdSlider->getValue(),
1189
                                                                        (int)patchSlider->getValue()-1,
1190
                                                                        &currentSyxDump.getReference(0));
1191
                MidiMessage message = SysexHelper::createMidiMessage(data);
1192
                miosStudio->sendMidiMessage(message);
1193
            } else if( sendChangedDump ) {
1194
                Array<uint8> lastSyxDump(currentSyxDump);
1195
                mbhpMfToolConfig->getDump(currentSyxDump);
1196
 
1197
                // send only changes via direct write
1198
                for(int addr=0; addr<lastSyxDump.size(); ++addr) {
1199
                    if( currentSyxDump[addr] != lastSyxDump[addr] ) {
1200
                        anyValueChanged = true;
1201
 
1202
                        uint8 value = currentSyxDump[addr];
1203
                        Array<uint8> data = SysexHelper::createMbhpMfWriteDirect((uint8)deviceIdSlider->getValue(),
1204
                                                                                 addr,
1205
                                                                                 &value,
1206
                                                                                 1);
1207
                        MidiMessage message = SysexHelper::createMidiMessage(data);
1208
                        miosStudio->sendMidiMessage(message);
1209
                    }
1210
                }
1211
            }
1212
 
1213
            if( anyValueChanged ) {
1214
                dumpSent = true;
1215
                progress = 1.0;
1216
                startTimer(1000);
1217
            } else {
1218
                transferFinished = true;
1219
                sendCompleteDump = false;
1220
                sendChangedDump = false;
1221
            }
1131 tk 1222
        }
1223
    }
1224
 
1225
    if( transferFinished ) {
1226
        progress = 0;
1227
        loadButton->setEnabled(true);
1228
        saveButton->setEnabled(true);
1229
        sendButton->setEnabled(true);
1230
        receiveButton->setEnabled(true);
1231
    }
1232
}
1233
 
1234
//==============================================================================
1235
void MbhpMfToolControl::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
1236
{
1237
    uint8 *data = message.getRawData();
1238
    uint32 size = message.getRawDataSize();
1239
 
1240
    if( SysexHelper::isValidMbhpMfTraceDump(data, size, (int)deviceIdSlider->getValue()) ) {
1241
        Array<uint16> newTrace;
1242
 
1243
        for(int pos=7; pos<(size-1) && data[pos] != 0xf7; pos+=2)
1244
            newTrace.add(data[pos+0] | (data[pos+1] << 7));
1245
 
1246
        mbhpMfToolConfig->calibration->calibrationCurve->setTrace(newTrace);
1247
        return;
1248
    }
1249
 
1250
    if( receiveDump ) {
1251
        if( dumpRequested &&
1252
            SysexHelper::isValidMbhpMfWritePatch(data, size, (int)deviceIdSlider->getValue()) &&
1253
            data[7] == ((int)patchSlider->getValue()-1) ) {
1254
            dumpReceived = true;
1255
 
1256
            if( size != 522 ) {
1257
                checksumError = true;
1258
            } else {
1259
                uint8 checksum = 0x00;
1260
                int pos;
1261
                for(pos=8; pos<7+1+512; ++pos)
1262
                    checksum += data[pos];
1263
                if( data[pos] != (-(int)checksum & 0x7f) )
1264
                    checksumError = true;
1265
                else {
1266
                    for(pos=8; pos<7+1+512; pos+=2) {
1267
                        uint8 b = (data[pos+0] & 0x0f) | ((data[pos+1] << 4) & 0xf0);
1268
                        currentSyxDump.add(b);
1269
                    }
1270
                }
1271
            }
1272
 
1273
            // trigger timer immediately
1274
            stopTimer();
1275
            startTimer(1);
1276
        }
1277
    } else if( isTimerRunning() ) {
1278
        if( SysexHelper::isValidMbhpMfAcknowledge(data, size, (int)deviceIdSlider->getValue()) ) {
1279
            // trigger timer immediately
1280
            stopTimer();
1281
            startTimer(1);
1282
        }
1283
    }
1284
}
1285
 
1286
 
1287
//==============================================================================
1288
bool MbhpMfToolControl::loadSyx(File &syxFile)
1289
{
1290
    FileInputStream *inFileStream = syxFile.createInputStream();
1291
 
1292
    if( !inFileStream || inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
1293
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
1294
                                    T("The file ") + syxFile.getFileName(),
1295
                                    T("doesn't exist!"),
1296
                                    String::empty);
1297
        return false;
1298
    } else if( inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
1299
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
1300
                                    T("The file ") + syxFile.getFileName(),
1301
                                    T("is empty!"),
1302
                                    String::empty);
1303
        return false;
1304
    }
1305
 
1306
    int64 size = inFileStream->getTotalLength();
1307
    uint8 *buffer = (uint8 *)juce_malloc(size);
1308
    int64 readNumBytes = inFileStream->read(buffer, size);
1309
    int numValidPatches = 0;
1310
    Array<uint8> syxDump;
1311
    String errorMessage;
1312
 
1313
    if( readNumBytes != size ) {
1314
        errorMessage = String(T("cannot be read completely!"));
1315
    } else {
1316
        for(int pos=0; pos<size; ++pos) {
1317
            if( SysexHelper::isValidMbhpMfWritePatch(buffer+pos, size - pos, -1) ) {
1318
                pos += 7;
1319
 
1320
                if( pos < size ) {
1321
                    int patch = buffer[pos++]; // not relevant, will be ignored
1322
                    int patchPos = 0;
1323
                    uint8 checksum = 0x00;
1324
                    while( pos < size && buffer[pos] != 0xf7 && patchPos < 256 ) {
1325
                        uint8 bl = buffer[pos++] & 0x0f;
1326
                        checksum += bl;
1327
                        uint8 bh = buffer[pos++] & 0x0f;
1328
                        checksum += bh;
1329
 
1330
                        syxDump.set(patchPos, (bh << 4) | bl);
1331
                        ++patchPos;
1332
                    }
1333
 
1334
                    if( patchPos != 256 ) {
1335
                        errorMessage = String::formatted(T("contains invalid data: patch %d not complete (only %d bytes)"), patch, patchPos);
1336
                    } else {
1337
                        checksum = (-(int)checksum) & 0x7f;
1338
                        if( buffer[pos] != checksum ) {
1339
                            errorMessage = String::formatted(T("contains invalid checksum in patch %d (expected %02X but read %02X)!"), patch, checksum, buffer[pos]);
1340
                        } else {
1341
                            ++pos;
1342
                            ++numValidPatches;
1343
                        }
1344
                    }
1345
                }
1346
            }
1347
        }
1348
    }
1349
 
1350
    juce_free(buffer);
1351
 
1352
    if( errorMessage == String::empty ) {
1353
        if( !numValidPatches )
1354
            errorMessage = String(T("doesn't contain a valid patch!"));
1355
    }
1356
 
1357
    if( errorMessage != String::empty ) {
1358
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
1359
                                    T("The file ") + syxFile.getFileName(),
1360
                                    errorMessage,
1361
                                    String::empty);
1362
        return false;
1363
    }
1364
 
1365
    mbhpMfToolConfig->setDump(syxDump);
1366
 
1367
    return true;
1368
}
1369
 
1370
bool MbhpMfToolControl::saveSyx(File &syxFile)
1371
{
1372
    syxFile.deleteFile();
1373
    FileOutputStream *outFileStream = syxFile.createOutputStream();
1374
 
1375
    if( !outFileStream || outFileStream->failedToOpen() ) {
1376
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
1377
                                    String::empty,
1378
                                    T("File cannot be created!"),
1379
                                    String::empty);
1380
        return false;
1381
    }
1382
 
1383
    Array<uint8> syxDump;
1384
    mbhpMfToolConfig->getDump(syxDump);
1385
 
1386
    Array<uint8> data = SysexHelper::createMbhpMfWritePatch((uint8)deviceIdSlider->getValue(),
1387
                                                          (int)patchSlider->getValue()-1,
1388
                                                          &syxDump.getReference(0));
1389
    outFileStream->write(&data.getReference(0), data.size());
1390
 
1391
    delete outFileStream;
1392
 
1393
    return true;
1394
}
1395
 
1396
 
1397
//==============================================================================
1398
//==============================================================================
1399
//==============================================================================
1400
MbhpMfTool::MbhpMfTool(MiosStudio *_miosStudio)
1401
    : miosStudio(_miosStudio)
1402
    , mbhpMfToolControl(NULL)
1403
{
1404
    addAndMakeVisible(mbhpMfToolConfig = new MbhpMfToolConfig(this));
1405
    addAndMakeVisible(mbhpMfToolControl = new MbhpMfToolControl(miosStudio, mbhpMfToolConfig));
1406
 
1133 tk 1407
    // get initial dump
1408
    mbhpMfToolControl->sysexUpdateRequest();
1409
 
1131 tk 1410
    resizeLimits.setSizeLimits(100, 300, 2048, 2048);
1411
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
1412
 
1133 tk 1413
    setSize(700, 630);
1131 tk 1414
}
1415
 
1416
MbhpMfTool::~MbhpMfTool()
1417
{
1418
}
1419
 
1420
//==============================================================================
1421
void MbhpMfTool::paint (Graphics& g)
1422
{
1423
    //g.fillAll(Colour(0xffc1d0ff));
1424
    g.fillAll(Colours::white);
1425
}
1426
 
1427
void MbhpMfTool::resized()
1428
{
1429
    mbhpMfToolControl->setBounds(0, 0, getWidth(), 40);
1430
    mbhpMfToolConfig->setBounds(0, 40, getWidth(), getHeight()-40);
1431
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
1432
}