Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
927 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: SysexTool.cpp 1724 2013-03-28 20:23:40Z tk $
3
/*
4
 * SysEx 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 "SysexTool.h"
16
#include "MiosStudio.h"
17
 
18
 
19
//==============================================================================
20
SysexToolSend::SysexToolSend(MiosStudio *_miosStudio)
21
    : miosStudio(_miosStudio)
928 tk 22
    , numBytesToSend(0)
23
    , numBytesSent(0)
24
    , progress(0)
927 tk 25
{
928 tk 26
    addAndMakeVisible(statusLabel = new Label(T("Number of Bytes"), String::empty));
27
    statusLabel->setJustificationType(Justification::right);
927 tk 28
 
928 tk 29
    addAndMakeVisible(sendBox = new HexTextEditor(statusLabel));
30
 
927 tk 31
    addAndMakeVisible(sendFileChooser = new FilenameComponent (T("syxfile"),
32
                                                               File::nonexistent,
33
                                                               true, false, false,
34
                                                               "*.syx",
35
                                                               String::empty,
36
                                                               T("(choose a .syx file to send)")));
37
    sendFileChooser->addListener(this);
38
    sendFileChooser->setBrowseButtonText(T("Browse"));
39
 
40
    addAndMakeVisible(sendStartButton = new TextButton(T("Send Button")));
41
    sendStartButton->setButtonText(T("Send"));
1502 tk 42
    sendStartButton->addListener(this);
927 tk 43
 
44
    addAndMakeVisible(sendStopButton = new TextButton(T("Stop Button")));
45
    sendStopButton->setButtonText(T("Stop"));
46
    sendStopButton->setEnabled(false);
1502 tk 47
    sendStopButton->addListener(this);
927 tk 48
 
928 tk 49
    addAndMakeVisible(sendClearButton = new TextButton(T("Clear Button")));
50
    sendClearButton->setButtonText(T("Clear"));
1502 tk 51
    sendClearButton->addListener(this);
927 tk 52
 
928 tk 53
    addAndMakeVisible(sendDelayLabel = new Label(T("Send Delay"), T("Send Delay:")));
927 tk 54
    sendDelayLabel->setJustificationType(Justification::centred);
55
 
56
    addAndMakeVisible(sendDelaySlider = new Slider(T("Send Delay (mS)")));
57
    sendDelaySlider->setRange(0, 5000, 50);
58
    sendDelaySlider->setValue(750);
59
    sendDelaySlider->setSliderStyle(Slider::IncDecButtons);
928 tk 60
    sendDelaySlider->setTextBoxStyle(Slider::TextBoxLeft, false, 80, 20);
927 tk 61
    sendDelaySlider->setDoubleClickReturnValue(true, 0);
62
    sendDelaySlider->addListener(this);
63
 
928 tk 64
    addAndMakeVisible(progressBar = new ProgressBar(progress));
65
 
927 tk 66
    // restore settings
1724 tk 67
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
927 tk 68
    if( propertiesFile ) {
69
        sendDelaySlider->setValue(propertiesFile->getIntValue(T("sysexSendDelay"), 750));
70
 
71
        String recentlyUsedSyxFiles = propertiesFile->getValue(T("recentlyUsedSyxSendFiles"), String::empty);
72
        // seems that Juce doesn't provide a split function?
73
        StringArray recentlyUsedSyxFilesArray;
74
        int index = 0;
75
        while( (index=recentlyUsedSyxFiles.indexOfChar(';')) >= 0 ) {
76
            recentlyUsedSyxFilesArray.add(recentlyUsedSyxFiles.substring(0, index));
77
            recentlyUsedSyxFiles = recentlyUsedSyxFiles.substring(index+1);
78
        }
79
        if( recentlyUsedSyxFiles != String::empty )
80
            recentlyUsedSyxFilesArray.add(recentlyUsedSyxFiles);
81
        sendFileChooser->setRecentlyUsedFilenames(recentlyUsedSyxFilesArray);
82
 
928 tk 83
        sendFileChooser->setDefaultBrowseTarget(propertiesFile->getValue(T("defaultSyxSendFile"), String::empty));
927 tk 84
    }
928 tk 85
 
86
    setSize(800, 200);
927 tk 87
}
88
 
89
SysexToolSend::~SysexToolSend()
90
{
91
}
92
 
93
//==============================================================================
94
void SysexToolSend::paint (Graphics& g)
95
{
96
    g.fillAll(Colours::white);
97
}
98
 
99
void SysexToolSend::resized()
100
{
101
    sendFileChooser->setBounds(4, 4, getWidth()-8, 24);
102
 
928 tk 103
    int sendButtonY = 4+32;
927 tk 104
    int sendButtonWidth = 72;
928 tk 105
    sendStartButton->setBounds(10 + 0*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
106
    sendStopButton->setBounds(10 + 1*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
107
    sendClearButton->setBounds(10 + 2*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
108
    sendDelayLabel->setBounds(10 + 4*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
109
    sendDelaySlider->setBounds(10 + 5*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
934 tk 110
    statusLabel->setBounds(getWidth()-10-150, sendButtonY, 150, 24);
927 tk 111
 
928 tk 112
    sendBox->setBounds(4, 32+40, getWidth()-8, getHeight()-32-40-4-28-4);
927 tk 113
 
928 tk 114
    progressBar->setBounds(4, getHeight()-28, getWidth()-8, 24);
927 tk 115
}
116
 
117
//==============================================================================
118
void SysexToolSend::buttonClicked(Button* buttonThatWasClicked)
119
{
120
    if( buttonThatWasClicked == sendStartButton ) {
928 tk 121
        sendData = sendBox->getBinary();
122
        numBytesToSend = sendData.size();
123
        numBytesSent = 0;
124
        progress = 0;
125
        if( numBytesToSend > 0 ) {
126
            startTimer(1);
127
            sendStartButton->setEnabled(false);
128
            sendStopButton->setEnabled(true);
129
            sendDelaySlider->setEnabled(false);
130
            sendFileChooser->setEnabled(false);
131
            sendClearButton->setEnabled(false);
132
        }
927 tk 133
    } else if( buttonThatWasClicked == sendStopButton ) {
928 tk 134
        stopTimer();
927 tk 135
        sendStopButton->setEnabled(false);
136
        sendStartButton->setEnabled(true);
137
        sendDelaySlider->setEnabled(true);
138
        sendFileChooser->setEnabled(true);
928 tk 139
        sendClearButton->setEnabled(true);
930 tk 140
        progress = 0;
928 tk 141
    } else if( buttonThatWasClicked == sendClearButton ) {
142
        sendBox->clear();
927 tk 143
    }
144
}
145
 
146
 
147
//==============================================================================
148
void SysexToolSend::sliderValueChanged(Slider* slider)
149
{
150
    if( slider == sendDelaySlider ) {
151
        // store settings
1724 tk 152
        PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
927 tk 153
        if( propertiesFile ) {
154
            propertiesFile->setValue(T("sysexSendDelay"), sendDelaySlider->getValue());
155
        }
156
    }
157
}
158
 
159
 
160
//==============================================================================
161
void SysexToolSend::filenameComponentChanged(FilenameComponent *fileComponentThatHasChanged)
162
{
163
    if( fileComponentThatHasChanged == sendFileChooser ) {
928 tk 164
        File inFile = sendFileChooser->getCurrentFile();
927 tk 165
 
928 tk 166
        FileInputStream *inFileStream = inFile.createInputStream();
167
 
1542 tk 168
        if( !inFileStream ) {
928 tk 169
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
934 tk 170
                                        T("The file ") + inFile.getFileName(),
171
                                        T("doesn't exist!"),
172
                                        String::empty);
928 tk 173
        } else if( inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
174
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
934 tk 175
                                        T("The file ") + inFile.getFileName(),
176
                                        T("is empty!"),
177
                                        String::empty);
928 tk 178
        } else {
179
            int64 size = inFileStream->getTotalLength();
180
            uint8 *buffer = (uint8 *)juce_malloc(size);
181
            int64 readNumBytes = inFileStream->read(buffer, size);
182
            sendBox->setBinary(buffer, readNumBytes);
183
            juce_free(buffer);
184
 
185
            // store setting
1724 tk 186
            PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
928 tk 187
            if( propertiesFile ) {
188
                String recentlyUsedHexFiles = sendFileChooser->getRecentlyUsedFilenames().joinIntoString(";");
189
                propertiesFile->setValue(T("recentlyUsedSyxSendFiles"), recentlyUsedHexFiles);
190
                propertiesFile->setValue(T("defaultSyxSendFile"), inFile.getFullPathName());
191
            }
192
        }
193
 
194
        deleteAndZero(inFileStream);
927 tk 195
    }
196
}
197
 
198
 
928 tk 199
//==============================================================================
200
void SysexToolSend::timerCallback()
201
{
202
    stopTimer(); // will be restarted if required
927 tk 203
 
928 tk 204
    if( sendData.size() == 0 ) {
205
        sendStopButton->setEnabled(false);
206
        sendStartButton->setEnabled(true);
207
        sendDelaySlider->setEnabled(true);
208
        sendFileChooser->setEnabled(true);
209
        sendClearButton->setEnabled(true);
210
        progress = 0;
211
    } else {
212
        int streamEnd = sendData.indexOf(0xf7);
213
        if( streamEnd < 0 ) {
214
            MidiMessage message = SysexHelper::createMidiMessage(sendData);
215
            miosStudio->sendMidiMessage(message);
931 tk 216
            sendData.clear();
928 tk 217
            numBytesSent += sendData.size();
218
        } else {
219
            // send string until 0xf7
220
            MidiMessage message = SysexHelper::createMidiMessage(sendData, streamEnd+1);
221
            miosStudio->sendMidiMessage(message);
222
            sendData.removeRange(0, streamEnd+1);
223
            numBytesSent += streamEnd+1;
224
        }
927 tk 225
 
928 tk 226
        progress = (double)numBytesSent / (double)numBytesToSend;
227
 
228
        if( sendData.size() > 0 ) {
229
            int delay = sendDelaySlider->getValue();
230
            startTimer((delay > 0) ? delay : 1);
231
        } else {
930 tk 232
            startTimer(1000); // stop progress bar after 1 second
928 tk 233
        }
234
    }
235
}
236
 
237
 
927 tk 238
//==============================================================================
239
SysexToolReceive::SysexToolReceive(MiosStudio *_miosStudio)
240
    : miosStudio(_miosStudio)
241
{
928 tk 242
    addAndMakeVisible(statusLabel = new Label(T("Number of Bytes"), String::empty));
243
    statusLabel->setJustificationType(Justification::right);
927 tk 244
 
928 tk 245
    addAndMakeVisible(receiveBox = new HexTextEditor(statusLabel));
934 tk 246
    receiveBox->setTextToShowWhenEmpty(T("Received Data will be displayed once the stop button has been pressed!"),
247
                                       Colour(0xff808080));
928 tk 248
 
927 tk 249
    addAndMakeVisible(receiveFileChooser = new FilenameComponent (T("syxfile"),
250
                                                                  File::nonexistent,
251
                                                                  true, false, true,
252
                                                                  "*.syx",
928 tk 253
                                                                  ".syx",
927 tk 254
                                                                  T("(choose a .syx file to save)")));
255
    receiveFileChooser->addListener(this);
256
    receiveFileChooser->setBrowseButtonText(T("Browse"));
257
 
258
    addAndMakeVisible(receiveStartButton = new TextButton(T("Receive Button")));
259
    receiveStartButton->setButtonText(T("Receive"));
260
    receiveStartButton->setEnabled(true);
1502 tk 261
    receiveStartButton->addListener(this);
927 tk 262
 
263
    addAndMakeVisible(receiveStopButton = new TextButton(T("Stop Button")));
264
    receiveStopButton->setButtonText(T("Stop"));
265
    receiveStopButton->setEnabled(false);
1502 tk 266
    receiveStopButton->addListener(this);
927 tk 267
 
268
    addAndMakeVisible(receiveClearButton = new TextButton(T("Clear Button")));
269
    receiveClearButton->setButtonText(T("Clear"));
1502 tk 270
    receiveClearButton->addListener(this);
928 tk 271
 
272
    // restore settings
1724 tk 273
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
928 tk 274
    if( propertiesFile ) {
275
        String recentlyUsedSyxFiles = propertiesFile->getValue(T("recentlyUsedSyxReceiveFiles"), String::empty);
276
        // seems that Juce doesn't provide a split function?
277
        StringArray recentlyUsedSyxFilesArray;
278
        int index = 0;
279
        while( (index=recentlyUsedSyxFiles.indexOfChar(';')) >= 0 ) {
280
            recentlyUsedSyxFilesArray.add(recentlyUsedSyxFiles.substring(0, index));
281
            recentlyUsedSyxFiles = recentlyUsedSyxFiles.substring(index+1);
282
        }
283
        if( recentlyUsedSyxFiles != String::empty )
284
            recentlyUsedSyxFilesArray.add(recentlyUsedSyxFiles);
285
        receiveFileChooser->setRecentlyUsedFilenames(recentlyUsedSyxFilesArray);
286
 
287
        receiveFileChooser->setDefaultBrowseTarget(propertiesFile->getValue(T("defaultSyxReceiveFile"), String::empty));
288
    }
289
 
290
    setSize(800, 200);
927 tk 291
}
292
 
293
SysexToolReceive::~SysexToolReceive()
294
{
295
}
296
 
297
//==============================================================================
298
void SysexToolReceive::paint (Graphics& g)
299
{
300
    g.fillAll(Colours::white);
301
}
302
 
303
void SysexToolReceive::resized()
304
{
305
    receiveFileChooser->setBounds(4, 4, getWidth()-8, 24);
306
 
928 tk 307
    int receiveButtonY = 4+32;
927 tk 308
    int receiveButtonWidth = 72;
928 tk 309
    receiveStartButton->setBounds(10 + 0*(receiveButtonWidth+10), receiveButtonY, receiveButtonWidth, 24);
310
    receiveStopButton->setBounds(10 + 1*(receiveButtonWidth+10), receiveButtonY, receiveButtonWidth, 24);
311
    receiveClearButton->setBounds(10 + 2*(receiveButtonWidth+10), receiveButtonY, receiveButtonWidth, 24);
934 tk 312
    statusLabel->setBounds(getWidth()-10-150, receiveButtonY, 150, 24);
927 tk 313
 
928 tk 314
    receiveBox->setBounds(4, 32+40, getWidth()-8, getHeight()-32-40-4);
927 tk 315
}
316
 
317
//==============================================================================
318
void SysexToolReceive::buttonClicked(Button* buttonThatWasClicked)
319
{
320
    if( buttonThatWasClicked == receiveStartButton ) {
321
        receiveStartButton->setEnabled(false);
322
        receiveStopButton->setEnabled(true);
323
        receiveFileChooser->setEnabled(false);
934 tk 324
        receivedData.clear();
325
        statusLabel->setText(String(receivedData.size()) + T(" bytes received"), true);
927 tk 326
    } else if( buttonThatWasClicked == receiveStopButton ) {
327
        receiveStopButton->setEnabled(false);
328
        receiveStartButton->setEnabled(true);
928 tk 329
        receiveFileChooser->setEnabled(true);
936 tk 330
        if( receivedData.size() > 0 )
331
            receiveBox->addBinary(&receivedData.getReference(0), receivedData.size());
934 tk 332
        receivedData.clear();
927 tk 333
    } else if( buttonThatWasClicked == receiveClearButton ) {
334
        receiveBox->clear();
335
    }
336
}
337
 
338
 
339
//==============================================================================
340
void SysexToolReceive::filenameComponentChanged(FilenameComponent *fileComponentThatHasChanged)
341
{
342
    if( fileComponentThatHasChanged == receiveFileChooser ) {
928 tk 343
        File outFile = receiveFileChooser->getCurrentFile();
344
 
345
        Array<uint8> saveData = receiveBox->getBinary();
346
        if( saveData.size() == 0 ) {
347
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
348
                                        String::empty,
349
                                        T("No data to save!"),
350
                                        String::empty);
351
        } else {
934 tk 352
            outFile.deleteFile();
928 tk 353
            FileOutputStream *outFileStream = outFile.createOutputStream();
354
 
355
            if( !outFileStream || outFileStream->failedToOpen() ) {
356
                AlertWindow::showMessageBox(AlertWindow::WarningIcon,
357
                                            String::empty,
358
                                            T("File cannot be created!"),
359
                                            String::empty);
360
            } else {
361
                uint8 *data = &saveData.getReference(0);
362
                outFileStream->write(data, saveData.size());
363
                delete outFileStream;
364
                statusLabel->setText(String(saveData.size()) + T(" bytes saved"), true);
365
            }
366
        }
367
 
368
        // store setting
1724 tk 369
        PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
928 tk 370
        if( propertiesFile ) {
371
            String recentlyUsedHexFiles = receiveFileChooser->getRecentlyUsedFilenames().joinIntoString(";");
372
            propertiesFile->setValue(T("recentlyUsedSyxReceiveFiles"), recentlyUsedHexFiles);
373
            propertiesFile->setValue(T("defaultSyxReceiveFile"), outFile.getFullPathName());
374
        }
927 tk 375
    }
376
}
377
 
378
 
379
//==============================================================================
380
void SysexToolReceive::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
381
{
382
    if( !receiveStartButton->isEnabled() ) { // !enabled means that we are ready for receive
934 tk 383
        Array<uint8> data(message.getRawData(), message.getRawDataSize());
384
        receivedData.addArray(data);
385
        statusLabel->setText(String(receivedData.size()) + T(" bytes received"), true);
927 tk 386
    }
387
}
388
 
389
 
390
//==============================================================================
391
//==============================================================================
392
//==============================================================================
393
SysexTool::SysexTool(MiosStudio *_miosStudio)
394
    : miosStudio(_miosStudio)
395
{
396
    addAndMakeVisible(sysexToolSend = new SysexToolSend(miosStudio));
397
    addAndMakeVisible(sysexToolReceive = new SysexToolReceive(miosStudio));
398
 
399
    //                             num   min   max  prefered  
400
    horizontalLayout.setItemLayout(0, -0.005, -0.9, -0.25); // Send Window
401
    horizontalLayout.setItemLayout(1,    8,      8,     8); // Resizer
402
    horizontalLayout.setItemLayout(2, -0.005, -0.9, -0.25); // Receive Window
403
 
404
    horizontalDividerBar = new StretchableLayoutResizerBar(&horizontalLayout, 1, false);
405
    addAndMakeVisible(horizontalDividerBar);
406
 
928 tk 407
    resizeLimits.setSizeLimits(100, 300, 2048, 2048);
927 tk 408
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
409
 
928 tk 410
    setSize(860, 500);
927 tk 411
}
412
 
413
SysexTool::~SysexTool()
414
{
415
}
416
 
417
//==============================================================================
418
void SysexTool::paint (Graphics& g)
419
{
928 tk 420
    g.fillAll(Colour(0xffc1d0ff));
927 tk 421
}
422
 
423
void SysexTool::resized()
424
{
425
    Component* hcomps[] = { sysexToolSend,
426
                            horizontalDividerBar,
427
                            sysexToolReceive,
428
    };
429
 
430
    horizontalLayout.layOutComponents(hcomps, 3,
431
                                      4, 4,
432
                                      getWidth() - 8, getHeight() - 8,
433
                                      true,  // lay out above each other
434
                                      true); // resize the components' heights as well as widths
435
 
436
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
437
}