Subversion Repositories svn.mios32

Rev

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

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