Subversion Repositories svn.mios32

Rev

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