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
1502 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: SysexLibrarian.cpp 1724 2013-03-28 20:23:40Z tk $
3
/*
4
 * SysEx Librarian Window
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2012 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
#include "SysexLibrarian.h"
16
#include "MiosStudio.h"
17
 
1503 tk 18
SysexLibrarianBank::SysexLibrarianBank(MiosStudio *_miosStudio, const String& bankName)
1502 tk 19
    : miosStudio(_miosStudio)
20
    , font(14.0f)
21
{
1503 tk 22
    addAndMakeVisible(bankHeaderLabel = new Label(bankName, bankName));
23
    bankHeaderLabel->setJustificationType(Justification::centred);
24
 
25
    addAndMakeVisible(moveDownButton = new TextButton(T("Down")));
26
    moveDownButton->addListener(this);
27
 
28
    addAndMakeVisible(moveUpButton = new TextButton(T("Up")));
29
    moveUpButton->addListener(this);
30
 
31
    addAndMakeVisible(insertButton = new TextButton(T("Insert")));
32
    insertButton->addListener(this);
33
 
34
    addAndMakeVisible(deleteButton = new TextButton(T("Delete")));
35
    deleteButton->addListener(this);
36
 
37
    addAndMakeVisible(clearButton = new TextButton(T("Clear")));
38
    clearButton->addListener(this);
39
 
1502 tk 40
    addAndMakeVisible(table = new TableListBox(T("Bank"), this));
41
    table->setColour(ListBox::outlineColourId, Colours::grey);
42
    table->setOutlineThickness(1);
43
    table->setMultipleSelectionEnabled(true);
44
 
45
    table->getHeader().addColumn(T("Patch"), 1, 50);
46
    table->getHeader().addColumn(T("Name"), 2, 140);
47
 
48
    initBank(0);
49
 
1503 tk 50
    setSize(225, 200);
1502 tk 51
}
52
 
53
SysexLibrarianBank::~SysexLibrarianBank()
54
{
55
}
56
 
57
//==============================================================================
58
int SysexLibrarianBank::getNumRows()
59
{
60
    return numRows;
61
}
62
 
63
void SysexLibrarianBank::setNumRows(const int& rows)
64
{
65
    numRows = rows;
66
 
67
    patchStorage.clear();
68
    patchName.clear();
69
    for(int i=0; i<numRows; ++i) {
70
        patchName.set(i, T(""));
71
    }
72
}
73
 
74
 
75
void SysexLibrarianBank::initBank(const unsigned& _patchSpec)
76
{
77
    if( _patchSpec < miosStudio->sysexPatchDb->getNumSpecs() ) {
78
        patchSpec = _patchSpec;
79
 
80
        // this workaround ensures that the table view will be updated
81
        numRows = 10001;
82
        table->selectRow(10000);
83
 
84
        setNumRows(miosStudio->sysexPatchDb->getNumPatchesPerBank(patchSpec));
85
        table->selectRow(0);
86
    }
87
}
88
 
1503 tk 89
unsigned SysexLibrarianBank::getPatchSpec(void)
90
{
91
    return patchSpec;
92
}
93
 
1502 tk 94
unsigned SysexLibrarianBank::getSelectedPatch(void)
95
{
96
    return table->getSelectedRow();
97
}
98
 
99
bool SysexLibrarianBank::isSelectedPatch(const unsigned& patch)
100
{
101
    return table->isRowSelected(patch);
102
}
103
 
104
void SysexLibrarianBank::selectPatch(const unsigned& patch)
105
{
106
    table->selectRow(patch);
107
}
108
 
1505 tk 109
bool SysexLibrarianBank::isSingleSelection(void)
110
{
111
    int numSelected = 0;
112
 
113
    for(int patch=0; patch<numRows; ++patch)
114
        if( isSelectedPatch(patch) )
115
            ++numSelected;
116
 
117
    return numSelected == 1;
118
}
119
 
120
void SysexLibrarianBank::incPatchIfSingleSelection(void)
121
{
122
    if( !isSelectedPatch(numRows-1) && isSingleSelection() )
123
        selectPatch(getSelectedPatch()+1);
124
}
125
 
126
 
1502 tk 127
void SysexLibrarianBank::paintRowBackground(Graphics &g, int rowNumber, int width, int height, bool rowIsSelected)
128
{
129
    if( rowIsSelected )
130
        g.fillAll(Colours::lightblue);
131
}
132
 
133
void SysexLibrarianBank::paintCell(Graphics &g, int rowNumber, int columnId, int width, int height, bool rowIsSelected)
134
{
135
    g.setColour(Colours::black);
136
    g.setFont(font);
137
 
138
    switch( columnId ) {
139
    case 1: {
140
        char buffer[20];
141
        sprintf(buffer, "%03d", rowNumber+1);
142
        const String text(buffer);
143
        g.drawText(text, 2, 0, width - 4, height, Justification::centred, true);
144
    } break;
145
    }
146
 
147
    g.setColour(Colours::black.withAlpha (0.2f));
148
    g.fillRect(width - 1, 0, 1, height);
149
}
150
 
151
 
152
Component* SysexLibrarianBank::refreshComponentForCell(int rowNumber, int columnId, bool isRowSelected, Component* existingComponentToUpdate)
153
{
154
    switch( columnId ) {
155
    case 2: {
156
        ConfigTableLabel *label = (ConfigTableLabel *)existingComponentToUpdate;
157
 
158
        if( label == 0 ) {
159
            label = new ConfigTableLabel(*this);
160
        }
161
 
162
        label->setRowAndColumn(rowNumber, columnId);
1503 tk 163
 
1502 tk 164
        return label;
165
    } break;
166
    }
167
 
168
    return 0;
169
}
170
 
171
 
172
//==============================================================================
173
void SysexLibrarianBank::resized()
174
{
1503 tk 175
    bankHeaderLabel->setBounds(0, 0, getWidth(), 20);
176
 
177
    //unsigned buttonWidth = getWidth() / 5;
178
    unsigned buttonWidth = 200 / 5;
179
 
180
    moveDownButton->setBounds (0*buttonWidth+8, 20, buttonWidth-8, 16);
181
    moveUpButton->setBounds   (1*buttonWidth+8, 20, buttonWidth-8, 16);
182
    insertButton->setBounds   (2*buttonWidth+8, 20, buttonWidth-8, 16);
183
    deleteButton->setBounds   (3*buttonWidth+8, 20, buttonWidth-8, 16);
184
    clearButton->setBounds    (4*buttonWidth+8, 20, buttonWidth-8, 16);
185
 
186
    table->setBounds          (8, 40, getWidth()-16-16, getHeight()-40-8);
1502 tk 187
}
188
 
189
 
190
//==============================================================================
191
int SysexLibrarianBank::getTableValue(const int rowNumber, const int columnId)
192
{
193
    return 0;
194
}
195
 
196
void SysexLibrarianBank::setTableValue(const int rowNumber, const int columnId, const int newValue)
197
{
198
}
199
 
200
 
201
//==============================================================================
202
String SysexLibrarianBank::getTableString(const int rowNumber, const int columnId)
203
{
204
    switch( columnId ) {
205
    case 2: return patchName[rowNumber];
206
    }
207
    return String(T("???"));
208
}
209
 
210
void SysexLibrarianBank::setTableString(const int rowNumber, const int columnId, const String newString)
211
{
212
    switch( columnId ) {
213
    case 2: {
214
        Array<uint8>* p = patchStorage[rowNumber];
215
        if( p != NULL && p->size() ) {
216
            // replace patchname
217
            miosStudio->sysexPatchDb->replacePatchNameInPayload(patchSpec, *p, newString);
218
 
219
            // and back from payload (to doublecheck that it has been taken over)
220
            patchName.set(rowNumber, miosStudio->sysexPatchDb->getPatchNameFromPayload(patchSpec, *p));
221
        }
222
    } break;
223
    }
224
}
225
 
226
 
227
//==============================================================================
228
Array<uint8>* SysexLibrarianBank::getPatch(const uint8& patch)
229
{
230
    return patchStorage[patch];
231
}
232
 
233
void SysexLibrarianBank::setPatch(const uint8& patch, const Array<uint8> &payload)
234
{
235
    if( patchStorage[patch] != NULL ) {
236
        //juce_free(patchStorage[patch]);
237
    }
238
    patchStorage.set(patch, new Array<uint8>(payload));
1503 tk 239
    if( payload.size() ) {
240
        patchName.set(patch, miosStudio->sysexPatchDb->getPatchNameFromPayload(patchSpec, payload));
241
    } else {
242
        patchName.set(patch, String::empty);
243
    }
1502 tk 244
 
245
    table->resized(); // will do the trick, repaint() doesn't cause update
246
}
247
 
248
 
249
//==============================================================================
1503 tk 250
void SysexLibrarianBank::buttonClicked(Button* buttonThatWasClicked)
251
{
252
    Array<uint8> emptyArray;
253
    int maxPatches=getNumRows();
254
 
255
    if( buttonThatWasClicked == clearButton ) {
256
        initBank(patchSpec);
257
    } else if( buttonThatWasClicked == moveDownButton ) {
258
        for(int patch=maxPatches-2; patch >= 0; --patch) { // last patch won't be moved
259
            if( isSelectedPatch(patch) ) {
260
                Array<uint8>* p = getPatch(patch);
261
                Array<uint8> storage((p != NULL) ? *p : emptyArray);
262
                Array<uint8>* p2 = getPatch(patch+1);
263
                setPatch(patch, (p2 != NULL) ? *p2 : emptyArray);
264
                setPatch(patch+1, storage);
265
                table->deselectRow(patch);
266
                table->selectRow(patch+1, false, false);
267
            }
268
        }
269
    } else if( buttonThatWasClicked == moveUpButton ) {
270
        for(int patch=1; patch <maxPatches; ++patch) { // first patch won't be moved
271
            if( isSelectedPatch(patch) ) {
272
                Array<uint8>* p = getPatch(patch-1);
273
                Array<uint8> storage((p != NULL) ? *p : emptyArray);
274
                Array<uint8>* p2 = getPatch(patch);
275
                setPatch(patch-1, (p2 != NULL) ? *p2 : emptyArray);
276
                setPatch(patch, storage);
277
                table->deselectRow(patch);
278
                table->selectRow(patch-1, false, false);
279
            }
280
        }
281
    } else if( buttonThatWasClicked == insertButton ) {
282
        for(int patch=0; patch<maxPatches; ++patch) {
283
            if( isSelectedPatch(patch) ) {
284
                for(int i=maxPatches-2; i >= patch; --i) {
285
                    Array<uint8>* p = getPatch(i);
286
                    setPatch(i+1, (p != NULL) ? *p : emptyArray);
287
                }
288
                setPatch(patch, emptyArray);
289
                table->selectRow(patch, false, false); // to ensure table update
290
            }
291
        }
292
    } else if( buttonThatWasClicked == deleteButton ) {
293
        for(int patch=0; patch<maxPatches; ++patch) {
294
            if( isSelectedPatch(patch) ) {
295
                for(int i=patch; i < (maxPatches-1); ++i) {
296
                    Array<uint8>* p = getPatch(i+1);
297
                    setPatch(i, (p != NULL) ? *p : emptyArray);
298
                }
299
                setPatch(maxPatches-1, emptyArray);
300
                table->selectRow(patch, false, false); // to ensure table update
301
            }
302
        }
303
    }
304
}
305
 
306
 
1502 tk 307
//==============================================================================
308
//==============================================================================
1503 tk 309
//==============================================================================
1502 tk 310
SysexLibrarianControl::SysexLibrarianControl(MiosStudio *_miosStudio, SysexLibrarian *_sysexLibrarian)
311
    : miosStudio(_miosStudio)
312
    , sysexLibrarian(_sysexLibrarian)
313
    , currentPatch(0)
1519 tk 314
    , timerRestartDelay(10)
315
    , retryCtr(0)
1502 tk 316
    , progress(0)
317
    , receiveDump(false)
318
    , handleSinglePatch(false)
319
    , bufferTransfer(false)
320
    , dumpReceived(false)
321
    , checksumError(false)
322
    , errorResponse(false)
323
{
324
    addAndMakeVisible(deviceTypeLabel = new Label(T("MIDI Device:"), T("MIDI Device:")));
325
    deviceTypeLabel->setJustificationType(Justification::right);
326
 
327
    addAndMakeVisible(deviceTypeSelector = new ComboBox(String::empty));
328
    deviceTypeSelector->addListener(this);
329
    deviceTypeSelector->clear();
330
    for(int i=0; i<miosStudio->sysexPatchDb->getNumSpecs(); ++i) {
331
        deviceTypeSelector->addItem(miosStudio->sysexPatchDb->getSpecName(i), i+1);
332
    }
333
    deviceTypeSelector->setSelectedId(1, true);
334
    deviceTypeSelector->setEnabled(true);
335
 
336
    addAndMakeVisible(deviceIdLabel = new Label(T("Device ID"), T("Device ID:")));
337
    deviceIdLabel->setJustificationType(Justification::right);
338
 
339
    addAndMakeVisible(deviceIdSlider = new Slider(T("Device ID")));
340
    deviceIdSlider->setRange(0, 7, 1);
341
    deviceIdSlider->setSliderStyle(Slider::IncDecButtons);
342
    deviceIdSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
343
    deviceIdSlider->setDoubleClickReturnValue(true, 0);
344
 
345
    addAndMakeVisible(bankSelectLabel = new Label(T("Bank"), T("Bank:")));
346
    bankSelectLabel->setJustificationType(Justification::right);
347
 
348
    addAndMakeVisible(bankSelectSlider = new Slider(T("Bank")));
349
    bankSelectSlider->setRange(1, 8, 1);
350
    bankSelectSlider->setSliderStyle(Slider::IncDecButtons);
351
    bankSelectSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
352
    bankSelectSlider->setDoubleClickReturnValue(true, 0);
353
 
354
    addAndMakeVisible(loadBankButton = new TextButton(T("Load Bank")));
355
    loadBankButton->addListener(this);
356
    addAndMakeVisible(saveBankButton = new TextButton(T("Save Bank")));
357
    saveBankButton->addListener(this);
358
    addAndMakeVisible(receiveBankButton = new TextButton(T("Receive Bank")));
359
    receiveBankButton->addListener(this);
360
    addAndMakeVisible(sendBankButton = new TextButton(T("Send Bank")));
361
    sendBankButton->addListener(this);
362
 
363
    addAndMakeVisible(loadPatchButton = new TextButton(T("Load Patch")));
364
    loadPatchButton->addListener(this);
365
    addAndMakeVisible(savePatchButton = new TextButton(T("Save Patch")));
366
    savePatchButton->addListener(this);
367
    addAndMakeVisible(receivePatchButton = new TextButton(T("Receive Patch")));
368
    receivePatchButton->addListener(this);
369
    addAndMakeVisible(sendPatchButton = new TextButton(T("Send Patch")));
370
    sendPatchButton->addListener(this);
371
 
372
    addAndMakeVisible(bufferLabel = new Label(T("Buffer"), T("SID:")));
373
    bufferLabel->setJustificationType(Justification::right);
374
 
375
    addAndMakeVisible(bufferSlider = new Slider(T("Buffer")));
376
    bufferSlider->setRange(1, 4, 1);
377
    bufferSlider->setSliderStyle(Slider::IncDecButtons);
378
    bufferSlider->setTextBoxStyle(Slider::TextBoxLeft, false, 30, 20);
379
    bufferSlider->setDoubleClickReturnValue(true, 0);
380
 
381
    addAndMakeVisible(receiveBufferButton = new TextButton(T("Receive Buffer")));
382
    receiveBufferButton->addListener(this);
383
    addAndMakeVisible(sendBufferButton = new TextButton(T("Send Buffer")));
384
    sendBufferButton->addListener(this);
385
 
386
    addAndMakeVisible(stopButton = new TextButton(T("Stop")));
387
    stopButton->addListener(this);
1505 tk 388
    stopButton->setEnabled(false);
1502 tk 389
 
390
    addAndMakeVisible(progressBar = new ProgressBar(progress));
391
 
392
    // restore settings
1724 tk 393
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1502 tk 394
    if( propertiesFile ) {
1517 tk 395
        deviceIdSlider->setValue(propertiesFile->getIntValue(T("sysexLibrarianDeviceId"), 0));
1502 tk 396
        String syxFileName(propertiesFile->getValue(T("sysexLibrarianSyxFile"), String::empty));
397
        if( syxFileName != String::empty )
398
            syxFile = File(syxFileName);
1517 tk 399
        deviceTypeSelector->setSelectedId(propertiesFile->getIntValue(T("sysexLibrarianDevice"), 1), true);
1519 tk 400
        setSpec(deviceTypeSelector->getSelectedId()-1);
1502 tk 401
    }
402
 
403
    setSize(300, 200);
404
}
405
 
406
SysexLibrarianControl::~SysexLibrarianControl()
407
{
408
}
409
 
410
//==============================================================================
411
void SysexLibrarianControl::paint (Graphics& g)
412
{
413
    g.fillAll(Colours::white);
414
}
415
 
416
void SysexLibrarianControl::resized()
417
{
418
    int buttonX0 = 15;
419
    int buttonXOffset = 100;
420
    int buttonY = 8;
421
    int buttonYOffset = 32;
422
    int buttonWidth = 90;
423
    int buttonHeight = 24;
424
 
425
#if 0
426
    deviceTypeLabel->setBounds   (buttonX0 + 0*buttonXOffset, buttonY + 0*buttonYOffset, buttonWidth, buttonHeight);
427
    deviceTypeSelector->setBounds(buttonX0 + 1*buttonXOffset, buttonY + 0*buttonYOffset, buttonWidth, buttonHeight);
428
#else
429
    deviceTypeSelector->setBounds(buttonX0 + 0*buttonXOffset, buttonY + 0*buttonYOffset, 2*buttonWidth+10, buttonHeight);
430
#endif
431
 
432
    deviceIdLabel->setBounds (buttonX0 + 0*buttonXOffset, buttonY + 1*buttonYOffset, buttonWidth, buttonHeight);
433
    deviceIdSlider->setBounds(buttonX0 + 1*buttonXOffset, buttonY + 1*buttonYOffset+4, buttonWidth, buttonHeight-8);
434
 
435
    bankSelectLabel->setBounds (buttonX0 + 0*buttonXOffset, buttonY + 3*buttonYOffset, buttonWidth, buttonHeight);
436
    bankSelectSlider->setBounds(buttonX0 + 1*buttonXOffset, buttonY + 3*buttonYOffset+4, buttonWidth, buttonHeight-8);
437
 
438
    loadBankButton->setBounds   (buttonX0 + 0*buttonXOffset, buttonY + 4*buttonYOffset, buttonWidth, buttonHeight);
439
    saveBankButton->setBounds   (buttonX0 + 1*buttonXOffset, buttonY + 4*buttonYOffset, buttonWidth, buttonHeight);
440
    receiveBankButton->setBounds(buttonX0 + 0*buttonXOffset, buttonY + 5*buttonYOffset, buttonWidth, buttonHeight);
441
    sendBankButton->setBounds   (buttonX0 + 1*buttonXOffset, buttonY + 5*buttonYOffset, buttonWidth, buttonHeight);
442
 
443
    loadPatchButton->setBounds   (buttonX0 + 0*buttonXOffset, buttonY + 7*buttonYOffset, buttonWidth, buttonHeight);
444
    savePatchButton->setBounds   (buttonX0 + 1*buttonXOffset, buttonY + 7*buttonYOffset, buttonWidth, buttonHeight);
445
    receivePatchButton->setBounds(buttonX0 + 0*buttonXOffset, buttonY + 8*buttonYOffset, buttonWidth, buttonHeight);
446
    sendPatchButton->setBounds   (buttonX0 + 1*buttonXOffset, buttonY + 8*buttonYOffset, buttonWidth, buttonHeight);
447
 
448
    bufferLabel->setBounds (buttonX0 + 0*buttonXOffset, buttonY + 10*buttonYOffset, buttonWidth, buttonHeight);
449
    bufferSlider->setBounds(buttonX0 + 1*buttonXOffset, buttonY + 10*buttonYOffset+4, buttonWidth, buttonHeight-8);
450
 
451
    receiveBufferButton->setBounds(buttonX0 + 0*buttonXOffset, buttonY + 11*buttonYOffset, buttonWidth, buttonHeight);
452
    sendBufferButton->setBounds   (buttonX0 + 1*buttonXOffset, buttonY + 11*buttonYOffset, buttonWidth, buttonHeight);
453
 
1505 tk 454
    progressBar->setBounds(buttonX0, getHeight()-buttonY-buttonHeight, 2*buttonWidth-45, buttonHeight);
455
    stopButton->setBounds(buttonX0 + 2*buttonWidth-45+10, getHeight()-buttonY-buttonHeight, 45, buttonHeight);
1502 tk 456
}
457
 
458
//==============================================================================
459
void SysexLibrarianControl::buttonClicked(Button* buttonThatWasClicked)
460
{
461
    if( buttonThatWasClicked == stopButton ) {
462
        stopTransfer();
463
    } else if( buttonThatWasClicked == loadBankButton ||
464
               buttonThatWasClicked == loadPatchButton ) {
465
        FileChooser fc(T("Choose a .syx file that you want to open..."),
466
                       syxFile,
467
                       T("*.syx"));
468
 
469
        if( fc.browseForFileToOpen() ) {
470
            syxFile = fc.getResult();
471
            if( loadSyx(syxFile, buttonThatWasClicked == loadBankButton) ) {
1724 tk 472
                PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1502 tk 473
                if( propertiesFile )
474
                    propertiesFile->setValue(T("sysexLibrarianSyxFile"), syxFile.getFullPathName());
475
            }
476
        }
477
    } else if( buttonThatWasClicked == saveBankButton ||
478
               buttonThatWasClicked == savePatchButton ) {
479
        FileChooser fc(T("Choose a .syx file that you want to save..."),
480
                       syxFile,
481
                       T("*.syx"));
482
        if( fc.browseForFileToSave(true) ) {
483
            syxFile = fc.getResult();
484
            if( saveSyx(syxFile, buttonThatWasClicked == saveBankButton) ) {
1724 tk 485
                PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1502 tk 486
                if( propertiesFile )
487
                    propertiesFile->setValue(T("sysexLibrarianSyxFile"), syxFile.getFullPathName());
488
            }
489
        }
490
    } else if( buttonThatWasClicked == sendBankButton ||
491
               buttonThatWasClicked == receiveBankButton ||
492
               buttonThatWasClicked == sendPatchButton ||
493
               buttonThatWasClicked == receivePatchButton ||
494
               buttonThatWasClicked == sendBufferButton ||
495
               buttonThatWasClicked == receiveBufferButton ) {
496
        deviceIdSlider->setEnabled(false);
497
        bankSelectSlider->setEnabled(false);
498
        loadBankButton->setEnabled(false);
499
        saveBankButton->setEnabled(false);
500
        sendBankButton->setEnabled(false);
501
        receiveBankButton->setEnabled(false);
502
        loadPatchButton->setEnabled(false);
503
        savePatchButton->setEnabled(false);
504
        sendPatchButton->setEnabled(false);
505
        receivePatchButton->setEnabled(false);
506
        bufferSlider->setEnabled(false);
507
        sendBufferButton->setEnabled(false);
508
        receiveBufferButton->setEnabled(false);
509
        stopButton->setEnabled(true);
510
 
511
        currentPatch = (buttonThatWasClicked == sendBankButton || buttonThatWasClicked == receiveBankButton) ? 0 : sysexLibrarian->sysexLibrarianBank->getSelectedPatch();
512
        progress = 0;
1519 tk 513
        dumpRequested = false;
1502 tk 514
        errorResponse = false;
515
        checksumError = false;
516
 
1519 tk 517
        retryCtr = 0; // no retry yet
518
 
1502 tk 519
        handleSinglePatch =
520
            buttonThatWasClicked == sendPatchButton ||
521
            buttonThatWasClicked == receivePatchButton ||
522
            buttonThatWasClicked == sendBufferButton ||
523
            buttonThatWasClicked == receiveBufferButton;
524
 
525
        bufferTransfer =
526
            buttonThatWasClicked == sendBufferButton ||
527
            buttonThatWasClicked == receiveBufferButton;
528
 
529
        receiveDump =
530
            buttonThatWasClicked == receiveBankButton ||
531
            buttonThatWasClicked == receivePatchButton ||
532
            buttonThatWasClicked == receiveBufferButton;
533
 
534
        startTimer(1);
535
    }
536
}
537
 
538
 
539
//==============================================================================
540
void SysexLibrarianControl::sliderValueChanged(Slider* slider)
541
{
542
    if( slider == deviceIdSlider ) {
543
        // store setting
1724 tk 544
        PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1502 tk 545
        if( propertiesFile )
546
            propertiesFile->setValue(T("sysexLibrarianDeviceId"), (int)slider->getValue());
547
    }
548
}
549
 
550
 
551
//==============================================================================
552
void SysexLibrarianControl::comboBoxChanged(ComboBox* comboBox)
553
{
554
    if( comboBox == deviceTypeSelector ) {
1503 tk 555
        setSpec(comboBox->getSelectedId()-1);
1517 tk 556
 
557
        // store setting
1724 tk 558
        PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1517 tk 559
        if( propertiesFile )
560
            propertiesFile->setValue(T("sysexLibrarianDevice"), (int)comboBox->getSelectedId());
1503 tk 561
    }
562
}
563
 
564
//==============================================================================
565
void SysexLibrarianControl::setSpec(const unsigned& spec)
566
{
567
    if( spec < miosStudio->sysexPatchDb->getNumSpecs() ) {
568
        sysexLibrarian->sysexLibrarianBank->initBank(spec);
1504 tk 569
        sysexLibrarian->sysexLibrarianAssemblyBank->initBank(spec);
1503 tk 570
        bankSelectSlider->setRange(1, miosStudio->sysexPatchDb->getNumBanks(spec), 1);
571
 
572
        String bufferName(miosStudio->sysexPatchDb->getBufferName(spec));
573
        if( bufferName.isEmpty() )
574
            bufferLabel->setText(bufferName, true); // empty...
575
        else
576
            bufferLabel->setText(bufferName + String(T(":")), true); // empty...
577
 
578
        int numBuffers = miosStudio->sysexPatchDb->getNumBuffers(spec);
579
        if( numBuffers ) {
580
            bufferSlider->setRange(1, numBuffers, 1);
581
            bufferSlider->setEnabled(true);
582
        } else {
583
            bufferSlider->setRange(1, 1, 1);
584
            bufferSlider->setEnabled(false);
1502 tk 585
        }
1519 tk 586
 
587
        // starting delay - will be increased if synth needs more time
588
        timerRestartDelay = 10;
1502 tk 589
    }
590
}
591
 
592
//==============================================================================
593
 
594
void SysexLibrarianControl::stopTransfer(void)
595
{
596
    stopTimer();
597
 
598
    progress = 0;
599
    deviceIdSlider->setEnabled(true);
600
    bankSelectSlider->setEnabled(true);
601
    loadBankButton->setEnabled(true);
602
    saveBankButton->setEnabled(true);
603
    sendBankButton->setEnabled(true);
604
    receiveBankButton->setEnabled(true);
605
    loadPatchButton->setEnabled(true);
606
    savePatchButton->setEnabled(true);
607
    sendPatchButton->setEnabled(true);
608
    receivePatchButton->setEnabled(true);
609
    bufferSlider->setEnabled(true);
610
    sendBufferButton->setEnabled(true);
611
    receiveBufferButton->setEnabled(true);
612
    stopButton->setEnabled(false);
613
}
614
 
615
//==============================================================================
616
void SysexLibrarianControl::timerCallback()
617
{
618
    stopTimer(); // will be restarted if required
619
 
620
    // transfer has been stopped?
621
    if( !stopButton->isEnabled() )
622
        return;
623
 
624
    bool transferFinished = false;
625
 
626
    if( receiveDump ) {
1519 tk 627
        if( dumpRequested ) {
628
            if( checksumError ) {
1502 tk 629
                transferFinished = true;
630
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
631
                                            T("Detected checksum error!"),
632
                                            T("Check:\n- MIDI In/Out connections\n- your MIDI interface"),
633
                                            String::empty);
1519 tk 634
            } else if( !dumpReceived ) {
635
                if( ++retryCtr < 16 ) {
636
                    --currentPatch;
637
                    timerRestartDelay = 100*retryCtr; // delay increases with each retry
638
                } else {
639
                    transferFinished = true;
1520 tk 640
                    timerRestartDelay = 10; // next time we will start with short delay again
1519 tk 641
                    AlertWindow::showMessageBox(AlertWindow::WarningIcon,
642
                                                T("No response from device."),
643
                                                T("Check:\n- MIDI In/Out connections\n- Device ID\n- that MIDIbox firmware has been uploaded"),
644
                                                String::empty);
645
                }
1502 tk 646
            }
647
        }
648
 
649
        if( !transferFinished ) {
650
            int spec = deviceTypeSelector->getSelectedId()-1;
651
            if( spec < 0 || spec >= miosStudio->sysexPatchDb->getNumSpecs() ) {
652
                transferFinished = true;
1505 tk 653
            } else if( (handleSinglePatch && !sysexLibrarian->sysexLibrarianBank->isSelectedPatch(currentPatch)) ||
1502 tk 654
                       (currentPatch >= miosStudio->sysexPatchDb->getNumPatchesPerBank(spec)) ) {
655
                transferFinished = true;
656
            } else {
657
                dumpReceived = false;
658
                checksumError = false;
659
                errorResponse = false;
660
                int spec = deviceTypeSelector->getSelectedId()-1;
661
                if( spec < 0 || spec >= miosStudio->sysexPatchDb->getNumSpecs() ) {
662
                    dumpReceived = true;
663
                } else {
664
                    Array<uint8> data;
665
 
666
                    if( bufferTransfer ) {
1505 tk 667
                        uint8 bufferNum = (uint8)bufferSlider->getValue() - 1;
668
                        Array<uint8> selectBuffer = miosStudio->sysexPatchDb->createSelectBuffer(spec,
669
                                                                                                 (uint8)deviceIdSlider->getValue(),
670
                                                                                                 bufferNum);
671
                        if( selectBuffer.size() ) {
672
                            Array<uint8> data(selectBuffer);
673
                            MidiMessage message = SysexHelper::createMidiMessage(data);
674
                            miosStudio->sendMidiMessage(message);
675
                            bufferNum = 0; // don't transfer offset in this case
676
                        }
677
 
1502 tk 678
                        data = miosStudio->sysexPatchDb->createReadBuffer(spec,
1505 tk 679
                                                                          (uint8)deviceIdSlider->getValue(),
680
                                                                          bufferNum,
681
                                                                          (uint8)bankSelectSlider->getValue()-1,
682
                                                                          currentPatch);
1502 tk 683
                    } else {
684
                        data = miosStudio->sysexPatchDb->createReadPatch(spec,
685
                                                                         (uint8)deviceIdSlider->getValue(),
686
                                                                         0,
687
                                                                         (uint8)bankSelectSlider->getValue()-1,
688
                                                                         currentPatch);
689
                    }
690
                    MidiMessage message = SysexHelper::createMidiMessage(data);
691
                    miosStudio->sendMidiMessage(message);
692
 
1519 tk 693
                    dumpRequested = true;
1502 tk 694
                    ++currentPatch;
695
 
696
                    if( handleSinglePatch )
697
                        progress = 1;
698
                    else
699
                        progress = (double)currentPatch / (double)miosStudio->sysexPatchDb->getNumPatchesPerBank(spec);
700
                    startTimer(miosStudio->sysexPatchDb->getDelayBetweenReads(spec));
701
                }
702
            }
703
        }
704
    } else {
705
        int spec = deviceTypeSelector->getSelectedId()-1;
706
        if( spec < 0 || spec >= miosStudio->sysexPatchDb->getNumSpecs() ) {
707
            transferFinished = true;
708
        } else {
709
            if( errorResponse ) {
710
                transferFinished = true;
711
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
712
                                            T("Got Error response!"),
713
                                            T("Check:\n- if a valid patch has been uploaded\n- error code in MIDI IN monitor"),
714
                                            String::empty);
715
            } else {
716
                if( (handleSinglePatch && currentPatch != sysexLibrarian->sysexLibrarianBank->getSelectedPatch()) ||
717
                    currentPatch >= miosStudio->sysexPatchDb->getNumPatchesPerBank(spec) ) {
718
                    transferFinished = true;
719
                } else {
720
                    Array<uint8>* p = NULL;
721
                    while( currentPatch < sysexLibrarian->sysexLibrarianBank->getNumRows() &&
722
                           (p=sysexLibrarian->sysexLibrarianBank->getPatch(currentPatch)) == NULL )
723
                        ++currentPatch;
724
 
725
                    if( p == NULL ) {
726
                        transferFinished = true;
727
                    } else {
728
                        errorResponse = false;
729
 
730
                        Array<uint8> data;
731
 
732
                        if( bufferTransfer ) {
1505 tk 733
                            uint8 bufferNum = (uint8)bufferSlider->getValue() - 1;
734
                            Array<uint8> selectBuffer = miosStudio->sysexPatchDb->createSelectBuffer(spec,
735
                                                                                                     (uint8)deviceIdSlider->getValue(),
736
                                                                                                     bufferNum);
737
                            if( selectBuffer.size() ) {
738
                                Array<uint8> data(selectBuffer);
739
                                MidiMessage message = SysexHelper::createMidiMessage(data);
740
                                miosStudio->sendMidiMessage(message);
741
                                bufferNum = 0; // don't transfer offset in this case
742
                            }
743
 
1502 tk 744
                            data = miosStudio->sysexPatchDb->createWriteBuffer(spec,
745
                                                                              (uint8)deviceIdSlider->getValue(),
1505 tk 746
                                                                              bufferNum,
1502 tk 747
                                                                              (uint8)bankSelectSlider->getValue()-1,
748
                                                                              currentPatch,
749
                                                                              &p->getReference(0),
750
                                                                              p->size());
751
                        } else {
752
                            data = miosStudio->sysexPatchDb->createWritePatch(spec,
753
                                                                              (uint8)deviceIdSlider->getValue(),
754
                                                                              0,
755
                                                                              (uint8)bankSelectSlider->getValue()-1,
756
                                                                              currentPatch,
757
                                                                              &p->getReference(0),
758
                                                                              p->size());
759
                        }
760
 
761
                        MidiMessage message = SysexHelper::createMidiMessage(data);
762
                        miosStudio->sendMidiMessage(message);
763
 
764
                        ++currentPatch;
765
 
766
                        if( handleSinglePatch )
767
                            progress = 1;
1505 tk 768
                        else {
1502 tk 769
                            progress = (double)currentPatch / (double)miosStudio->sysexPatchDb->getNumPatchesPerBank(spec);
1505 tk 770
                            sysexLibrarian->sysexLibrarianBank->selectPatch(currentPatch-1);
771
                        }
1502 tk 772
 
773
                        startTimer(miosStudio->sysexPatchDb->getDelayBetweenWrites(spec));
774
                    }
775
                }
776
            }
777
        }
778
    }
779
 
780
    if( transferFinished ) {
781
        stopTransfer();
782
    }
783
}
784
 
785
//==============================================================================
786
void SysexLibrarianControl::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
787
{
1724 tk 788
    uint8 *data = (uint8 *)message.getRawData();
1502 tk 789
    uint32 size = message.getRawDataSize();
790
 
791
    int spec = deviceTypeSelector->getSelectedId()-1;
792
    if( spec < 0 || spec >= miosStudio->sysexPatchDb->getNumSpecs() )
793
        return;
794
 
795
    if( receiveDump ) {
796
        int receivedPatch = currentPatch-1;
1505 tk 797
        uint8 bufferNum = (uint8)bufferSlider->getValue() - 1;
798
        Array<uint8> selectBuffer = miosStudio->sysexPatchDb->createSelectBuffer(spec,
799
                                                                                 (uint8)deviceIdSlider->getValue(),
800
                                                                                 bufferNum);
801
        if( selectBuffer.size() ) {
802
            bufferNum = 0; // offset not transfered in this case
803
        }
804
 
1502 tk 805
        if( (bufferTransfer && miosStudio->sysexPatchDb->isValidWriteBuffer(spec,
806
                                                                            data, size,
807
                                                                            (int)deviceIdSlider->getValue(),
1505 tk 808
                                                                            bufferNum,
1502 tk 809
                                                                            -1,
810
                                                                            -1))
811
            ||
812
            (!bufferTransfer && miosStudio->sysexPatchDb->isValidWritePatch(spec,
813
                                                                            data, size,
814
                                                                            (int)deviceIdSlider->getValue(),
815
                                                                            0,
1505 tk 816
                                                                            -1,
817
                                                                            -1))
1502 tk 818
            ) {
819
 
820
            dumpReceived = true;
821
 
822
            if( size != miosStudio->sysexPatchDb->getPatchSize(spec) ||
823
                !miosStudio->sysexPatchDb->hasValidChecksum(spec, data, size) ) {
824
                checksumError = true;
825
            } else {
826
                Array<uint8> payload(miosStudio->sysexPatchDb->getPayload(spec, data, size));
827
                sysexLibrarian->sysexLibrarianBank->setPatch(receivedPatch, payload);
828
                sysexLibrarian->sysexLibrarianBank->selectPatch(receivedPatch);
1505 tk 829
                // leads to endless download if a single patch is selected and received, since the handler checks for the selection...
830
                //sysexLibrarian->sysexLibrarianBank->incPatchIfSingleSelection();
1502 tk 831
            }
832
 
1519 tk 833
            // trigger timer immediately with variable delay (will be increased if timeouts have been notified)
1502 tk 834
            stopTimer();
1519 tk 835
            startTimer(timerRestartDelay);
1502 tk 836
        }
837
    } else if( isTimerRunning() ) {
838
        if( miosStudio->sysexPatchDb->isValidErrorAcknowledge(spec, data, size, (int)deviceIdSlider->getValue()) ) {
839
            // trigger timer immediately
840
            errorResponse = true;
841
            stopTimer();
1517 tk 842
            startTimer(100);
1502 tk 843
        } else if( miosStudio->sysexPatchDb->isValidAcknowledge(spec, data, size, (int)deviceIdSlider->getValue()) ) {
844
            // trigger timer immediately
845
            stopTimer();
1517 tk 846
            startTimer(100);
1502 tk 847
        }
848
    }
849
}
850
 
851
 
852
//==============================================================================
853
bool SysexLibrarianControl::loadSyx(File &syxFile, const bool& loadBank)
854
{
855
    FileInputStream *inFileStream = syxFile.createInputStream();
856
 
1542 tk 857
    if( !inFileStream ) {
1502 tk 858
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
859
                                    T("The file ") + syxFile.getFileName(),
860
                                    T("doesn't exist!"),
861
                                    String::empty);
862
        return false;
863
    } else if( inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
864
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
865
                                    T("The file ") + syxFile.getFileName(),
866
                                    T("is empty!"),
867
                                    String::empty);
868
        return false;
869
    }
870
 
871
    int64 size = inFileStream->getTotalLength();
872
    uint8 *buffer = (uint8 *)juce_malloc(size);
873
    int64 readNumBytes = inFileStream->read(buffer, size);
874
    String errorMessage;
875
    int spec = deviceTypeSelector->getSelectedId()-1;
876
 
877
    if( readNumBytes != size ) {
878
        errorMessage = String(T("cannot be read completely!"));
879
    } else if( spec < 0 || spec >= miosStudio->sysexPatchDb->getNumSpecs() ) {
880
        errorMessage = String(T("invalid patch type selected!"));
881
    } else {
882
        int patchSize = miosStudio->sysexPatchDb->getPatchSize(spec);
883
        int maxPatches = miosStudio->sysexPatchDb->getNumPatchesPerBank(spec);
884
 
885
        if( loadBank ) {
886
            sysexLibrarian->sysexLibrarianBank->initBank(spec);
887
        }
888
 
889
        unsigned patch = 0;
890
        unsigned numPatches = 0;
891
        int pos = 0;
892
        while( errorMessage.isEmpty() &&
893
               (pos+patchSize) <= size ) {
894
            uint8* patchPtr = &buffer[pos];
895
            if( miosStudio->sysexPatchDb->isValidWritePatch(spec, patchPtr, patchSize, -1, -1, -1, -1) ||
896
                miosStudio->sysexPatchDb->isValidWriteBuffer(spec, patchPtr, patchSize, -1, -1, -1, -1) ) {
897
 
898
                if( !loadBank ) {
899
                    while( patch < maxPatches && !sysexLibrarian->sysexLibrarianBank->isSelectedPatch(patch) )
900
                        ++patch;
901
                }
902
                if( patch >= maxPatches )
903
                    break;
904
 
905
                Array<uint8> payload(miosStudio->sysexPatchDb->getPayload(spec, patchPtr, patchSize));
906
                sysexLibrarian->sysexLibrarianBank->setPatch(patch, payload);
1505 tk 907
                if( loadBank ) {
1502 tk 908
                    sysexLibrarian->sysexLibrarianBank->selectPatch(patch);
1505 tk 909
                }
910
                sysexLibrarian->sysexLibrarianBank->incPatchIfSingleSelection();
1502 tk 911
 
912
                ++numPatches;
913
                ++patch;
914
                pos += patchSize;
915
            } else {
916
                // search for next F0
917
                while( ((++pos+patchSize) <= size) && (buffer[pos] != 0xf0) );
918
            }
919
        }
920
 
921
        if( numPatches == 0 ) {
922
            errorMessage = String(T("doesn't contain any valid SysEx dump for a ") + miosStudio->sysexPatchDb->getSpecName(spec));
923
        } else {
924
            if( loadBank ) {
925
                sysexLibrarian->sysexLibrarianBank->selectPatch(0); // select the first patch in bank
926
            }
927
        }
928
    }
929
 
930
    juce_free(buffer);
931
 
932
    if( !errorMessage.isEmpty() ) {
933
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
934
                                    T("The file ") + syxFile.getFileName(),
935
                                    errorMessage,
936
                                    String::empty);
937
        return false;
938
    }
939
 
940
    return true;
941
}
942
 
943
bool SysexLibrarianControl::saveSyx(File &syxFile, const bool& saveBank)
944
{
945
    syxFile.deleteFile();
946
    FileOutputStream *outFileStream = syxFile.createOutputStream();
947
 
948
    if( !outFileStream || outFileStream->failedToOpen() ) {
949
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
950
                                    String::empty,
951
                                    T("File cannot be created!"),
952
                                    String::empty);
953
        return false;
954
    }
955
 
956
 
957
    int spec = deviceTypeSelector->getSelectedId()-1;
958
    if( spec < 0 || spec >= miosStudio->sysexPatchDb->getNumSpecs() ) {
959
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
960
                                    String::empty,
961
                                    T("Invalid patch type selected!"),
962
                                    String::empty);
963
    } else {
964
        int maxPatches = sysexLibrarian->sysexLibrarianBank->getNumRows();
965
        for(int patch=0; patch<maxPatches; ++patch) {
966
            if( saveBank || sysexLibrarian->sysexLibrarianBank->isSelectedPatch(patch) ) {
967
                Array<uint8>* p = NULL;
968
                if( ((p=sysexLibrarian->sysexLibrarianBank->getPatch(patch)) != NULL) && p->size() ) {
969
                    Array<uint8> syxDump(miosStudio->sysexPatchDb->createWritePatch(spec,
970
                                                                                    0,
971
                                                                                    0,
972
                                                                                    (uint8)bankSelectSlider->getValue()-1,
973
                                                                                    patch,
974
                                                                                    &p->getReference(0),
975
                                                                                    p->size()));
976
                    outFileStream->write(&syxDump.getReference(0), syxDump.size());
977
                }
978
            }
979
        }
980
    }
981
 
982
    delete outFileStream;
983
 
984
    return true;
985
}
986
 
987
 
988
//==============================================================================
989
//==============================================================================
990
//==============================================================================
991
SysexLibrarian::SysexLibrarian(MiosStudio *_miosStudio)
992
    : miosStudio(_miosStudio)
993
{
1504 tk 994
    addAndMakeVisible(sysexLibrarianAssemblyBank = new SysexLibrarianBank(miosStudio, String(T("Assembly Bank"))));
1503 tk 995
    addAndMakeVisible(sysexLibrarianBank = new SysexLibrarianBank(miosStudio, String(T("Transaction Bank"))));
1502 tk 996
    addAndMakeVisible(sysexLibrarianControl = new SysexLibrarianControl(miosStudio, this));
997
 
1503 tk 998
    addAndMakeVisible(transferBankRButton = new TextButton(T("==>")));
999
    transferBankRButton->addListener(this);
1504 tk 1000
    transferBankRButton->setTooltip(T("Move all patches from Transaction to Assembly Bank"));
1503 tk 1001
 
1002
    addAndMakeVisible(transferPatchRButton = new TextButton(T("-->")));
1003
    transferPatchRButton->addListener(this);
1504 tk 1004
    transferPatchRButton->setTooltip(T("Move selected patches from Transaction to Assembly Bank"));
1503 tk 1005
 
1006
    addAndMakeVisible(transferPatchLButton = new TextButton(T("<--")));
1007
    transferPatchLButton->addListener(this);
1504 tk 1008
    transferPatchLButton->setTooltip(T("Move selected patches from Assembly to Transaction Bank"));
1503 tk 1009
 
1010
    addAndMakeVisible(transferBankLButton = new TextButton(T("<==")));
1011
    transferBankLButton->addListener(this);
1504 tk 1012
    transferBankLButton->setTooltip(T("Move all patches from Assembly to Transaction Bank"));
1503 tk 1013
 
1502 tk 1014
    resizeLimits.setSizeLimits(100, 300, 2048, 2048);
1015
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
1016
 
1503 tk 1017
    setSize(725, 500);
1502 tk 1018
}
1019
 
1020
SysexLibrarian::~SysexLibrarian()
1021
{
1022
}
1023
 
1024
//==============================================================================
1025
void SysexLibrarian::paint (Graphics& g)
1026
{
1027
    //g.fillAll(Colour(0xffc1d0ff));
1028
    g.fillAll(Colours::white);
1029
}
1030
 
1031
void SysexLibrarian::resized()
1032
{
1503 tk 1033
    sysexLibrarianControl->setBounds       (0, 0, 225, getHeight());
1034
    sysexLibrarianBank->setBounds          (220, 0, 225, getHeight());
1504 tk 1035
    sysexLibrarianAssemblyBank->setBounds(500, 0, 225, getHeight());
1503 tk 1036
 
1037
    unsigned buttonYOffset = (getHeight()-4*24)/2 - 4;
1038
 
1039
    transferBankRButton->setBounds         (445, buttonYOffset + 0*24 + 4, 45, 16);
1040
    transferPatchRButton->setBounds        (445, buttonYOffset + 1*24 + 4, 45, 16);
1041
    transferPatchLButton->setBounds        (445, buttonYOffset + 2*24 + 4, 45, 16);
1042
    transferBankLButton->setBounds         (445, buttonYOffset + 3*24 + 4, 45, 16);
1043
 
1502 tk 1044
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
1045
}
1503 tk 1046
 
1047
//==============================================================================
1048
void SysexLibrarian::buttonClicked (Button* buttonThatWasClicked)
1049
{
1050
    bool transfer =
1051
        (buttonThatWasClicked == transferBankRButton) ||
1052
        (buttonThatWasClicked == transferPatchRButton) ||
1053
        (buttonThatWasClicked == transferPatchLButton) ||
1054
        (buttonThatWasClicked == transferBankLButton);
1055
 
1056
    bool transferRight =
1057
        (buttonThatWasClicked == transferBankRButton) ||
1058
        (buttonThatWasClicked == transferPatchRButton);
1059
 
1060
    bool transferBank =
1061
        (buttonThatWasClicked == transferBankRButton) ||
1062
        (buttonThatWasClicked == transferBankLButton);
1063
 
1064
    if( transfer ) {
1504 tk 1065
        SysexLibrarianBank* srcBank = transferRight ? sysexLibrarianBank : sysexLibrarianAssemblyBank;
1066
        SysexLibrarianBank* dstBank = transferRight ? sysexLibrarianAssemblyBank : sysexLibrarianBank;
1503 tk 1067
 
1068
        if( transferBank )
1069
            dstBank->initBank(srcBank->getPatchSpec());
1070
 
1071
        int dstPatch = -1;
1072
        int lastDstPatch = -1;
1073
        int maxPatches = srcBank->getNumRows();
1074
        for(int srcPatch=0; srcPatch<maxPatches; ++srcPatch) {
1075
            if( transferBank || srcBank->isSelectedPatch(srcPatch) ) {
1076
                if( transferBank ) {
1077
                    dstPatch = srcPatch;
1078
                } else {
1079
                    while( ++dstPatch < maxPatches && !dstBank->isSelectedPatch(dstPatch) );
1080
                    if( dstPatch >= maxPatches )
1081
                        dstPatch = lastDstPatch + 1;
1082
                }
1083
 
1084
                if( dstPatch >= maxPatches )
1085
                    break;
1086
 
1087
                Array<uint8>* p = srcBank->getPatch(srcPatch);
1088
                if( p != NULL ) {
1089
                    dstBank->setPatch(dstPatch, *p);
1090
                }
1091
                lastDstPatch = dstPatch;
1092
            }
1093
        }
1505 tk 1094
 
1095
        if( !transferBank ) {
1096
            srcBank->incPatchIfSingleSelection();
1097
            dstBank->incPatchIfSingleSelection();
1098
        }
1503 tk 1099
    }
1100
}
1101