Subversion Repositories svn.mios32

Rev

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