Subversion Repositories svn.mios32

Rev

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