Subversion Repositories svn.mios

Rev

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

Rev Author Line No. Line
213 tk 1
/*
2
 * @(#)SIDV2librarian.java  beta1   2008/01/21
3
 *
4
 * Copyright (C) 2008    Rutger Vlek (rutgervlek@hotmail.com)
5
 *
6
 * This application is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This application is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this application; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
 
21
package org.midibox.sidlibr;
22
 
628 adamjking 23
import java.awt.event.ActionEvent;
24
import java.awt.event.ActionListener;
213 tk 25
import java.util.Observable;
628 adamjking 26
 
27
import javax.sound.midi.MidiMessage;
213 tk 28
import javax.sound.midi.Receiver;
628 adamjking 29
import javax.sound.midi.SysexMessage;
30
import javax.swing.JOptionPane;
31
import javax.swing.ProgressMonitor;
32
import javax.swing.Timer;
213 tk 33
 
628 adamjking 34
import org.midibox.midi.MidiUtils;
213 tk 35
import org.midibox.sidedit.SIDSysexInfo;
36
 
628 adamjking 37
public class SysExController extends Observable implements Receiver,
38
        ActionListener {
213 tk 39
    public static Object PATCH = new Object();
628 adamjking 40
    public static Object ENSEMBLE = new Object();
41
 
213 tk 42
    public Object pickMeUp;
628 adamjking 43
 
213 tk 44
    private Timer timer;
45
    private int timeOut = 2000;
628 adamjking 46
 
213 tk 47
    private ProgressMonitor progress;
628 adamjking 48
 
295 rutgerv 49
    private static String IDLE = "IDLE";
50
    private static String COLLECTING = "COLLECTING";
51
    private static String DUMPING = "DUMPING";
52
    private static String SCANNING = "SCANNING";
53
    private static String FORWARDING = "FORWARDING";
54
    private String STATE;
628 adamjking 55
 
213 tk 56
    private Object tempSyxType;
293 rutgerv 57
    private String tempSyx = new String();
58
    private String[] dumpStack;
59
    private int dumpCount;
628 adamjking 60
 
293 rutgerv 61
    private String tempResponse;
213 tk 62
    private boolean syxErrorChk = true;
63
    private Receiver receiver;
64
    private int masterCore = 0;
628 adamjking 65
 
293 rutgerv 66
    public int[] requestPatch;
67
    public int requestBank;
68
    public int requestCount;
628 adamjking 69
 
213 tk 70
    public SysExController(Receiver receiver) {
293 rutgerv 71
        this.receiver = receiver;
72
        timer = new Timer(timeOut, this);
73
        timer.setInitialDelay(timeOut);
295 rutgerv 74
        STATE = IDLE;
213 tk 75
    }
628 adamjking 76
 
213 tk 77
    public Receiver getReceiver() {
78
        return receiver;
79
    }
628 adamjking 80
 
213 tk 81
    public boolean isDone() {
628 adamjking 82
        return (STATE == IDLE);
213 tk 83
    }
628 adamjking 84
 
85
    public void close() {
86
    }
87
 
88
    // ****************** Forwarding functions ***********************
293 rutgerv 89
    public void resetForwarding() {
90
        String init = getForwardSyx(0);
91
        sendSyx(init);
213 tk 92
    }
628 adamjking 93
 
293 rutgerv 94
    public void setForwarding(int cores) {
95
        sendSyx(getForwardSyx(cores));
96
    }
628 adamjking 97
 
293 rutgerv 98
    private String getForwardSyx(int cores) {
99
        String s = SIDSysexInfo.forwardSysex;
100
        s = s.replace("<device>", zeroPadToHex(masterCore));
101
        s = s.replace("<sids>", zeroPadToHex(cores));
102
        return s;
103
    }
628 adamjking 104
 
105
    // ****************** Hardware scan functions ***********************
293 rutgerv 106
    public void scanHardware() {
213 tk 107
        if (isDone()) {
293 rutgerv 108
            setForwarding(15);
109
            String message = SIDSysexInfo.pingSysex;
110
            message = message.replace("<device>", zeroPadToHex(masterCore));
628 adamjking 111
            progress = new ProgressMonitor(null, "", "Receiving SysEx data...",
112
                    0, 1);
293 rutgerv 113
            timer.start();
295 rutgerv 114
            STATE = SCANNING;
293 rutgerv 115
            sendSyx(message);
213 tk 116
        }
117
    }
628 adamjking 118
 
293 rutgerv 119
    private void stopScan() {
120
        timer.stop();
295 rutgerv 121
        STATE = IDLE;
628 adamjking 122
        if (progress != null) {
293 rutgerv 123
            progress.close();
213 tk 124
        }
125
    }
628 adamjking 126
 
127
    // ****************** Receive functions ***********************
293 rutgerv 128
    public void requestPatch(int[] patchNumber, int bankNumber) {
213 tk 129
        if (isDone()) {
293 rutgerv 130
            resetForwarding();
131
            requestPatch = patchNumber;
132
            requestBank = bankNumber;
628 adamjking 133
            startRequest(PATCH);
213 tk 134
        }
135
    }
628 adamjking 136
 
137
    public void requestPatchBuffer(int coreNumber, int patch, int bank) {
293 rutgerv 138
        if (isDone()) {
139
            resetForwarding();
628 adamjking 140
            requestPatch = new int[] { patch };
293 rutgerv 141
            requestBank = bank;
142
            timer.start();
628 adamjking 143
            requestCount = 0;
293 rutgerv 144
            tempSyxType = PATCH;
628 adamjking 145
            progress = new ProgressMonitor(null, "", "Receiving SysEx data...",
146
                    0, requestPatch.length);
147
            STATE = COLLECTING;
293 rutgerv 148
            String message = SIDSysexInfo.editPatchRequestSysex;
149
            message = message.replace("<device>", zeroPadToHex(coreNumber));
150
            sendSyx(message);
151
        }
152
    }
628 adamjking 153
 
293 rutgerv 154
    private void requestNext() {
155
        requestCount++;
156
        if (requestCount < requestPatch.length) {
157
            timer.restart();
158
            String message = SIDSysexInfo.hardPatchRequestSysex;
159
            message = message.replace("<device>", "00");
628 adamjking 160
            message = message.replace("<bank>", zeroPadToHex(requestBank));
161
            message = message.replace("<patch>",
162
                    zeroPadToHex(requestPatch[requestCount]));
293 rutgerv 163
            sendSyx(message);
164
        } else {
165
            stopRequest();
166
        }
167
    }
628 adamjking 168
 
293 rutgerv 169
    private void startRequest(Object type) {
170
        timer.start();
628 adamjking 171
        requestCount = -1;
213 tk 172
        tempSyxType = type;
628 adamjking 173
        progress = new ProgressMonitor(null, "", "Receiving SysEx data...", 0,
174
                requestPatch.length);
295 rutgerv 175
        STATE = COLLECTING;
293 rutgerv 176
        requestNext();
213 tk 177
    }
628 adamjking 178
 
213 tk 179
    private void stopRequest() {
628 adamjking 180
        STATE = IDLE;
213 tk 181
        timer.stop();
628 adamjking 182
        if (progress != null) {
213 tk 183
            progress.close();
184
        }
185
    }
628 adamjking 186
 
293 rutgerv 187
    private void scanSyx(String m) {
628 adamjking 188
        if (progress.isCanceled()
189
                || (tempResponse.substring(0, 5).equals("ERROR"))) {
293 rutgerv 190
            stopScan();
191
        } else if (tempResponse.substring(0, 12).equals("ACKNOWLEDGED")) {
192
            stopScan();
628 adamjking 193
            pickMeUp = Integer.parseInt(m.substring(14, 16), 16);
293 rutgerv 194
            setChanged();
195
            notifyObservers("Hardware scan");
628 adamjking 196
            clearChanged();
213 tk 197
        }
198
    }
628 adamjking 199
 
213 tk 200
    protected void collectSyx(String m) {
201
        if (progress.isCanceled()) {
202
            stopRequest();
628 adamjking 203
        } else {
204
            if (!(m.indexOf(SIDSysexInfo.acknowledgedSysex.replace("<device>",
205
                    "00")) == 0)) {
206
                if (m.substring(0, 2).equalsIgnoreCase("F0")) { // select next
207
                    // array item
208
                    // with each F0
209
                    tempSyx = m;
210
                } else {
211
                    if (m.substring(0, 2).equalsIgnoreCase("F7")) { // for
212
                        // windows
213
                        // (1024
214
                        // byte
215
                        // limit, F7
216
                        // added at
217
                        // beginning
218
                        // of next
219
                        // chunk)
293 rutgerv 220
                        m = m.substring(2);
221
                    }
628 adamjking 222
                    tempSyx += m;
293 rutgerv 223
                }
224
                timer.restart();
628 adamjking 225
                progress.setProgress(requestCount);
226
                if (m.substring(m.length() - 2).equalsIgnoreCase("F7")) {
227
                    parseSysex();
228
                }
247 tk 229
            }
213 tk 230
        }
231
    }
628 adamjking 232
 
213 tk 233
    private void parseSysex() {
628 adamjking 234
        if (tempSyxType == PATCH) {
235
            Patch tempPatch = new Patch(receiver);
293 rutgerv 236
            String status = tempPatch.parsePatch(tempSyx);
213 tk 237
            if (statusCheck(status)) {
238
                pickMeUp = tempPatch;
239
                setChanged();
240
                notifyObservers("Patch ready");
241
                clearChanged();
293 rutgerv 242
                requestNext();
243
            } else {
244
                stopRequest();
213 tk 245
            }
628 adamjking 246
        } else if (tempSyxType == ENSEMBLE) {
213 tk 247
            setChanged();
248
            notifyObservers("Ensemble ready");
249
            clearChanged();
250
        }
251
    }
628 adamjking 252
 
213 tk 253
    public boolean statusCheck(String status) {
254
        boolean b = false;
628 adamjking 255
        if (status == "succesful") {
213 tk 256
            b = true;
628 adamjking 257
        } else if (status == "checksum error") {
258
            JOptionPane.showMessageDialog(null, "Checksum error!", "Error",
259
                    JOptionPane.ERROR_MESSAGE);
260
        } else if (status == "parse error error") {
261
            JOptionPane.showMessageDialog(null,
262
                    "An error occured while parsing a patch!", "Error",
263
                    JOptionPane.ERROR_MESSAGE);
264
        }
213 tk 265
        return b;
266
    }
628 adamjking 267
 
213 tk 268
    // ****************** Transmit functions ***********************
293 rutgerv 269
    public void dumpPatch(Patch[] p, int[] patchNumber, int bankNumber) {
213 tk 270
        if (isDone()) {
628 adamjking 271
            String[] s = new String[p.length + 1];
293 rutgerv 272
            s[0] = getForwardSyx(0);
628 adamjking 273
            for (int i = 0; i < p.length; i++) {
293 rutgerv 274
                String dataStr = p[i].getSysexString();
275
                String strMessage = SIDSysexInfo.hardPatchDumpSysex;
628 adamjking 276
                strMessage = strMessage.replace("<device>",
277
                        zeroPadToHex(masterCore));
278
                strMessage = strMessage.replace("<bank>",
279
                        zeroPadToHex(bankNumber));
280
                strMessage = strMessage.replace("<patch>",
281
                        zeroPadToHex(patchNumber[i]));
293 rutgerv 282
                strMessage = strMessage.replace("<data><checksum>", dataStr);
628 adamjking 283
                s[i + 1] = strMessage;
284
            }
285
            startDump(s);
213 tk 286
        }
287
    }
628 adamjking 288
 
293 rutgerv 289
    public void dumpPatchToBuffer(Patch p, int cores) {
628 adamjking 290
        if (isDone() && cores != 0) {
291
            String strMessage = SIDSysexInfo.editPatchDumpSysex;
292
            strMessage = strMessage.replace("<device>",
293
                    zeroPadToHex(masterCore));
294
            strMessage = strMessage.replace("<data><checksum>", p
295
                    .getSysexString());
296
            startDump(new String[] { getForwardSyx(cores), strMessage });
213 tk 297
        }
298
    }
628 adamjking 299
 
213 tk 300
    public void dumpPatchBank(Bank b, int bankNumber) {
301
        if (isDone()) {
628 adamjking 302
            Patch[] p = new Patch[b.bankSize - 1];
303
            int[] pNr = new int[b.bankSize - 1];
304
            for (int i = 1; i < b.bankSize; i++) {
305
                p[i - 1] = b.getPatchAt(i);
306
                pNr[i - 1] = i;
293 rutgerv 307
            }
628 adamjking 308
            dumpPatch(p, pNr, bankNumber);
213 tk 309
        }
310
    }
628 adamjking 311
 
293 rutgerv 312
    private void startDump(String[] s) {
313
        dumpStack = s;
314
        dumpCount = 0;
555 rutgerv 315
        System.out.println("Transmitting SysEx data...");
628 adamjking 316
        progress = new ProgressMonitor(null, "", "Transmitting SysEx data...",
317
                0, dumpStack.length);
213 tk 318
        timer.start();
295 rutgerv 319
        STATE = DUMPING;
628 adamjking 320
        tempResponse = "";
213 tk 321
        sendNext();
322
    }
628 adamjking 323
 
213 tk 324
    private void stopDump() {
295 rutgerv 325
        STATE = IDLE;
213 tk 326
        timer.stop();
628 adamjking 327
        if (progress != null) {
213 tk 328
            progress.close();
329
        }
330
    }
628 adamjking 331
 
213 tk 332
    private void sendNext() {
628 adamjking 333
        if (dumpCount == dumpStack.length) { // If no more to send then finish
213 tk 334
            stopDump();
335
            setChanged();
336
            notifyObservers("Dump completed");
337
            clearChanged();
628 adamjking 338
        } else { // send Syx and wait for next call of ()
339
            sendSyx(dumpStack[dumpCount++]);
293 rutgerv 340
            progress.setProgress(dumpCount);
341
            timer.restart();
213 tk 342
        }
343
    }
628 adamjking 344
 
213 tk 345
    protected void dumpSyx(String m) {
628 adamjking 346
        if (progress.isCanceled()
347
                || (tempResponse.substring(0, 5).equals("ERROR"))) {
213 tk 348
            stopDump();
293 rutgerv 349
        } else if (tempResponse.substring(0, 12).equals("ACKNOWLEDGED")) {
628 adamjking 350
            tempResponse = "";
351
            sendNext();
213 tk 352
        }
353
    }
628 adamjking 354
 
293 rutgerv 355
    // ****************** General functions ***********************
356
    public void send(MidiMessage message, long timestamp) {
628 adamjking 357
        String m = MidiUtils.getHexString(message.getMessage())
358
                .replace(" ", "");
359
 
293 rutgerv 360
        if (syxErrorChk) {
361
            checkError(m);
362
        }
628 adamjking 363
 
295 rutgerv 364
        if (STATE == COLLECTING) {
293 rutgerv 365
            collectSyx(m);
628 adamjking 366
        }
367
 
295 rutgerv 368
        if (STATE == DUMPING) {
293 rutgerv 369
            dumpSyx(m);
370
        }
628 adamjking 371
 
295 rutgerv 372
        if (STATE == SCANNING) {
293 rutgerv 373
            scanSyx(m);
374
        }
375
    }
628 adamjking 376
 
293 rutgerv 377
    public void actionPerformed(ActionEvent ae) {
378
        if (ae.getSource() == timer) {
628 adamjking 379
            if (STATE == COLLECTING) {
293 rutgerv 380
                stopRequest();
381
            }
628 adamjking 382
            if (STATE == DUMPING) {
293 rutgerv 383
                stopDump();
384
            }
628 adamjking 385
 
386
            if (STATE == SCANNING) {
293 rutgerv 387
                stopScan();
388
            }
628 adamjking 389
            JOptionPane
390
                    .showMessageDialog(
391
                            null,
392
                            "The MBSID V2 is not responding. Please check all connections!",
393
                            "Error", JOptionPane.ERROR_MESSAGE);
293 rutgerv 394
        }
395
    }
628 adamjking 396
 
213 tk 397
    protected void checkError(String m) {
628 adamjking 398
        if (m.indexOf(SIDSysexInfo.acknowledgedSysex.replace("<device>", "00")) == 0) {
399
            tempResponse = "ACKNOWLEDGED" + m.substring(14, 16);
400
        } else if (m.equals(SIDSysexInfo.error1Sysex.replace("<device>", "00"))) {
401
            tempResponse = "ERROR1";
402
            JOptionPane.showMessageDialog(null,
403
                    "MBSID says: Received less bytes then expected!", "Error",
404
                    JOptionPane.ERROR_MESSAGE);
405
        } else if (m.equals(SIDSysexInfo.error2Sysex.replace("<device>", "00"))) {
406
            tempResponse = "ERROR2";
407
            JOptionPane.showMessageDialog(null, "MBSID says: Wrong checksum!",
408
                    "Error", JOptionPane.ERROR_MESSAGE);
409
        } else if (m.equals(SIDSysexInfo.error3Sysex.replace("<device>", "00"))) {
410
            tempResponse = "ERROR3";
411
            JOptionPane
412
                    .showMessageDialog(
413
                            null,
414
                            "MBSID says: Bankstick or patch/drumset/ensemble not available!",
415
                            "Error", JOptionPane.ERROR_MESSAGE);
416
        } else if (m.equals(SIDSysexInfo.error4Sysex.replace("<device>", "00"))) {
417
            tempResponse = "ERROR4";
418
            JOptionPane.showMessageDialog(null,
419
                    "MBSID says: Parameter not available!", "Error",
420
                    JOptionPane.ERROR_MESSAGE);
421
        } else if (m.equals(SIDSysexInfo.error5Sysex.replace("<device>", "00"))) {
422
            tempResponse = "ERROR5";
423
            JOptionPane.showMessageDialog(null,
424
                    "MBSID says: RAM access not supported!", "Error",
425
                    JOptionPane.ERROR_MESSAGE);
426
        } else if (m.equals(SIDSysexInfo.error6Sysex.replace("<device>", "00"))) {
427
            tempResponse = "ERROR6";
428
            JOptionPane.showMessageDialog(null,
429
                    "MBSID says: BankStick too small for 128 patches!",
430
                    "Error", JOptionPane.ERROR_MESSAGE);
431
        } else {
432
            // System.out.println("MBSID: " + m);
433
        }
213 tk 434
    }
628 adamjking 435
 
213 tk 436
    protected void sendSyx(String s) {
628 adamjking 437
        SysexMessage sysexMessage = new SysexMessage();
213 tk 438
        try {
439
            byte[] abMessage = toByteArray(s);
628 adamjking 440
            sysexMessage.setMessage(abMessage, abMessage.length);
441
        } catch (Exception e) {
442
            JOptionPane.showMessageDialog(null,
443
                    "The System Exclusive data could not be sent!", "Error",
444
                    JOptionPane.ERROR_MESSAGE);
213 tk 445
        }
446
        receiver.send(sysexMessage, -1);
447
    }
628 adamjking 448
 
213 tk 449
    protected byte[] toByteArray(String s) {
628 adamjking 450
        int nLengthInBytes = s.length() / 2;
451
        byte[] abMessage = new byte[nLengthInBytes];
452
        for (int i = 0; i < nLengthInBytes; i++) {
453
            abMessage[i] = (byte) Integer.parseInt(s
454
                    .substring(i * 2, i * 2 + 2), 16);
455
        }
213 tk 456
        return abMessage;
457
    }
293 rutgerv 458
 
459
    protected String zeroPadToHex(int i) {
460
        String s = "00" + Integer.toHexString(i);
628 adamjking 461
        s = s.substring(s.length() - 2);
462
        return s;
293 rutgerv 463
    }
628 adamjking 464
 
213 tk 465
}