~mixxxdevelopers/mixxx/trunk

« back to all changes in this revision

Viewing changes to mixxx/src/controllers/midi/hss1394controller.cpp

Merging features_controllerAbstraction. Migration of mappings from .mixxx/midi/ to controllers/ only works on a version upgrade (end-users.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
  * @file hss1394controller.cpp
 
3
  * @author Sean M. Pappalardo  spappalardo@mixxx.org
 
4
  * @date Thu 15 Mar 2012
 
5
  * @brief HSS1394-based MIDI backend
 
6
  */
 
7
 
 
8
#include "controllers/midi/hss1394controller.h"
 
9
 
 
10
DeviceChannelListener::DeviceChannelListener(QObject* pParent, QString name)
 
11
        : QObject(pParent),
 
12
          hss1394::ChannelListener(),
 
13
          m_sName(name) {
 
14
}
 
15
 
 
16
DeviceChannelListener::~DeviceChannelListener() {
 
17
}
 
18
 
 
19
void DeviceChannelListener::Process(const hss1394::uint8 *pBuffer, hss1394::uint uBufferSize) {
 
20
    unsigned int i = 0;
 
21
 
 
22
    // If multiple three-byte messages arrive right next to each other, handle them all
 
23
    while (i < uBufferSize) {
 
24
        unsigned char status = pBuffer[i];
 
25
        unsigned char opcode = status & 0xF0;
 
26
        unsigned char channel = status & 0x0F;
 
27
        unsigned char note;
 
28
        unsigned char velocity;
 
29
        switch (status & 0xF0) {
 
30
            case MIDI_NOTE_OFF:
 
31
            case MIDI_NOTE_ON:
 
32
            case MIDI_AFTERTOUCH:
 
33
            case MIDI_CC:
 
34
            case MIDI_PITCH_BEND:
 
35
                if (i + 2 < uBufferSize) {
 
36
                    note = pBuffer[i+1];
 
37
                    velocity = pBuffer[i+2];
 
38
                    emit(incomingData(status, note, velocity));
 
39
                } else {
 
40
                    qWarning() << "Buffer underflow in DeviceChannelListener::Process()";
 
41
                }
 
42
                i += 3;
 
43
                break;
 
44
            default:
 
45
                // Handle platter messages and any others that are not 3 bytes
 
46
                QByteArray outArray((char*)pBuffer,uBufferSize);
 
47
                emit(incomingData(outArray));
 
48
                i = uBufferSize;
 
49
                break;
 
50
        }
 
51
    }
 
52
}
 
53
 
 
54
void DeviceChannelListener::Disconnected() {
 
55
    qDebug() << "HSS1394 device" << m_sName << "disconnected";
 
56
}
 
57
 
 
58
void DeviceChannelListener::Reconnected() {
 
59
    qDebug() << "HSS1394 device" << m_sName << "re-connected";
 
60
}
 
61
 
 
62
Hss1394Controller::Hss1394Controller(const hss1394::TNodeInfo deviceInfo,
 
63
                                     int deviceIndex)
 
64
        : MidiController(),
 
65
          m_deviceInfo(deviceInfo),
 
66
          m_iDeviceIndex(deviceIndex) {
 
67
    // Note: We prepend the input stream's index to the device's name to prevent
 
68
    // duplicate devices from causing mayhem.
 
69
    //setDeviceName(QString("H%1. %2").arg(QString::number(m_iDeviceIndex), QString(deviceInfo.sName.c_str())));
 
70
    setDeviceName(QString("%1").arg(QString(deviceInfo.sName.c_str())));
 
71
 
 
72
    // All HSS1394 devices are full-duplex
 
73
    setInputDevice(true);
 
74
    setOutputDevice(true);
 
75
}
 
76
 
 
77
Hss1394Controller::~Hss1394Controller() {
 
78
    close();
 
79
}
 
80
 
 
81
int Hss1394Controller::open() {
 
82
    if (isOpen()) {
 
83
        qDebug() << "HSS1394 device" << getName() << "already open";
 
84
        return -1;
 
85
    }
 
86
 
 
87
    if (getName() == MIXXX_HSS1394_NO_DEVICE_STRING) {
 
88
        return -1;
 
89
    }
 
90
 
 
91
    if (debugging()) {
 
92
        qDebug() << "Hss1394Controller: Opening" << getName() << "index" << m_iDeviceIndex;
 
93
    }
 
94
 
 
95
    using namespace hss1394;
 
96
 
 
97
    m_pChannel = Node::Instance()->OpenChannel(m_iDeviceIndex);
 
98
    if (m_pChannel == NULL) {
 
99
        qDebug() << "HSS1394 device" << getName() << "could not be opened";
 
100
        m_pChannelListener = NULL;
 
101
        return -1;
 
102
    }
 
103
 
 
104
    m_pChannelListener = new DeviceChannelListener(this, getName());
 
105
    connect(m_pChannelListener, SIGNAL(incomingData(QByteArray)),
 
106
            this, SLOT(receive(QByteArray)));
 
107
    connect(m_pChannelListener, SIGNAL(incomingData(unsigned char, unsigned char, unsigned char)),
 
108
            this, SLOT(receive(unsigned char, unsigned char, unsigned char)));
 
109
 
 
110
    if (!m_pChannel->InstallChannelListener(m_pChannelListener)) {
 
111
        qDebug() << "HSS1394 channel listener could not be installed for device" << getName();
 
112
        delete m_pChannelListener;
 
113
        m_pChannelListener = NULL;
 
114
        m_pChannel = NULL;
 
115
    }
 
116
 
 
117
    // TODO(XXX): Should be done in script, not in Mixxx
 
118
    if (getName().contains("SCS.1d",Qt::CaseInsensitive)) {
 
119
        // If we are an SCS.1d, set the record encoder event timer to fire at 1ms intervals
 
120
        //  to match the 1ms scratch timer in the controller engine
 
121
        //
 
122
        // By default on f/w version 1.25, a new record encoder event (one new position)
 
123
        //  is sent at 500 Hz max, 2ms. When this event occurs, a second timer is reset.
 
124
        //  By default this second timer expires periodically at 60 Hz max, around 16.6ms.
 
125
 
 
126
        int iPeriod = 60000/1000;   // 1000Hz = 1ms. (Internal clock is 60kHz.)
 
127
        int iTimer = 3; // 3 for new event timer, 4 for second �same position repeated� timer
 
128
        if (m_pChannel->SendUserControl(iTimer, (const hss1394::uint8*)&iPeriod, 3) == 0)
 
129
            qWarning() << "Unable to set SCS.1d platter timer period.";
 
130
    }
 
131
 
 
132
    setOpen(true);
 
133
    startEngine();
 
134
    return 0;
 
135
}
 
136
 
 
137
int Hss1394Controller::close() {
 
138
    if (!isOpen()) {
 
139
        qDebug() << "HSS1394 device" << getName() << "already closed";
 
140
        return -1;
 
141
    }
 
142
 
 
143
    disconnect(m_pChannelListener, SIGNAL(incomingData(QByteArray)),
 
144
               this, SLOT(receive(QByteArray)));
 
145
    disconnect(m_pChannelListener, SIGNAL(incomingData(unsigned char, unsigned char, unsigned char)),
 
146
               this, SLOT(receive(unsigned char, unsigned char, unsigned char)));
 
147
 
 
148
    stopEngine();
 
149
    MidiController::close();
 
150
 
 
151
    // Clean up the HSS1394Node
 
152
    using namespace hss1394;
 
153
    if (!Node::Instance()->ReleaseChannel(m_pChannel)) {
 
154
        qDebug() << "HSS1394 device" << getName() << "could not be released";
 
155
        return -1;
 
156
    }
 
157
    if (m_pChannelListener != NULL) {
 
158
        delete m_pChannelListener;
 
159
        m_pChannelListener = NULL;
 
160
    }
 
161
 
 
162
    setOpen(false);
 
163
    return 0;
 
164
}
 
165
 
 
166
void Hss1394Controller::send(unsigned int word) {
 
167
    unsigned char data[2];
 
168
    data[0] = word & 0xFF;
 
169
    data[1] = (word >> 8) & 0xFF;
 
170
    data[2] = (word >> 16) & 0xFF;
 
171
 
 
172
    QString message = QString("%1 %2 %3").arg(
 
173
        QString("%1").arg(data[0], 2, 16, QChar('0')),
 
174
        QString("%1").arg(data[1], 2, 16, QChar('0')),
 
175
        QString("%1").arg(data[2], 2, 16, QChar('0')));
 
176
 
 
177
    int bytesSent = m_pChannel->SendChannelBytes(data, 3);
 
178
 
 
179
    //if (bytesSent != 3) {
 
180
    //    qDebug()<<"ERROR: Sent" << bytesSent << "of 3 bytes:" << message;
 
181
    //    //m_pChannel->Flush();
 
182
    //}
 
183
}
 
184
 
 
185
void Hss1394Controller::send(QByteArray data) {
 
186
    int bytesSent = m_pChannel->SendChannelBytes(
 
187
        (unsigned char*)data.constData(), data.size());
 
188
 
 
189
    //if (bytesSent != length) {
 
190
    //    qDebug()<<"ERROR: Sent" << bytesSent << "of" << length << "bytes (SysEx)";
 
191
    //    //m_pChannel->Flush();
 
192
    //}
 
193
}