274 lines
8 KiB
C++
274 lines
8 KiB
C++
//=============================================================================
|
|
// MusE Score
|
|
// Linux Music Score Editor
|
|
// $Id: pm.cpp 4874 2011-10-21 12:18:42Z wschweer $
|
|
//
|
|
// Copyright (C) 2002-2007 Werner Schweer and others
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//=============================================================================
|
|
|
|
#if defined(Q_OS_WIN)
|
|
#include <windows.h>
|
|
#include <mmsystem.h>
|
|
#endif
|
|
|
|
#include "portmidi/porttime/porttime.h"
|
|
|
|
#include "preferences.h"
|
|
#include "pm.h"
|
|
#include "musescore.h"
|
|
#include "seq.h"
|
|
|
|
namespace Ms {
|
|
|
|
//---------------------------------------------------------
|
|
// Port
|
|
//---------------------------------------------------------
|
|
|
|
Port::Port()
|
|
{
|
|
type = ZERO_TYPE;
|
|
}
|
|
|
|
Port::Port(unsigned char client, unsigned char port)
|
|
{
|
|
_alsaPort = port;
|
|
_alsaClient = client;
|
|
type = ALSA_TYPE;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setZero
|
|
//---------------------------------------------------------
|
|
|
|
void Port::setZero()
|
|
{
|
|
type = ZERO_TYPE;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// isZero
|
|
//---------------------------------------------------------
|
|
|
|
bool Port::isZero() const
|
|
{
|
|
return type == ZERO_TYPE;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// operator==
|
|
//---------------------------------------------------------
|
|
|
|
bool Port::operator==(const Port& p) const
|
|
{
|
|
if (type == ALSA_TYPE)
|
|
return _alsaPort == p._alsaPort && _alsaClient == p._alsaClient;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// operator<
|
|
//---------------------------------------------------------
|
|
|
|
bool Port::operator<(const Port& p) const
|
|
{
|
|
if (type == ALSA_TYPE) {
|
|
if (_alsaPort != p._alsaPort)
|
|
return _alsaPort < p._alsaPort;
|
|
return _alsaClient < p._alsaClient;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// PortMidiDriver
|
|
//---------------------------------------------------------
|
|
|
|
PortMidiDriver::PortMidiDriver(Seq* s)
|
|
: MidiDriver(s)
|
|
{
|
|
inputStream = 0;
|
|
timer = 0;
|
|
}
|
|
|
|
PortMidiDriver::~PortMidiDriver()
|
|
{
|
|
if (inputStream) {
|
|
Pt_Stop();
|
|
Pm_Close(inputStream);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// init
|
|
// return false on error
|
|
//---------------------------------------------------------
|
|
|
|
bool PortMidiDriver::init()
|
|
{
|
|
inputId = getDeviceIn(preferences.portMidiInput);
|
|
if(inputId == -1)
|
|
inputId = Pm_GetDefaultInputDeviceID();
|
|
outputId = Pm_GetDefaultOutputDeviceID();
|
|
|
|
if (inputId == pmNoDevice)
|
|
return false;
|
|
|
|
static const int INPUT_BUFFER_SIZE = 100;
|
|
static const int DRIVER_INFO = 0;
|
|
static const int TIME_INFO = 0;
|
|
|
|
Pt_Start(20, 0, 0); // timer started, 20 millisecond accuracy
|
|
|
|
PmError error = Pm_OpenInput(&inputStream,
|
|
inputId,
|
|
(void*)DRIVER_INFO, INPUT_BUFFER_SIZE,
|
|
((long (*)(void*)) Pt_Time),
|
|
(void*)TIME_INFO);
|
|
if (error != pmNoError) {
|
|
const char* p = Pm_GetErrorText(error);
|
|
qDebug("PortMidi: open input (id=%d) failed: %s\n", int(inputId), p);
|
|
Pt_Stop();
|
|
return false;
|
|
}
|
|
|
|
Pm_SetFilter(inputStream, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
|
|
|
|
PmEvent buffer[1];
|
|
while (Pm_Poll(inputStream))
|
|
Pm_Read(inputStream, buffer, 1);
|
|
|
|
timer = new QTimer();
|
|
timer->setInterval(20); // 20 msec
|
|
timer->start();
|
|
timer->connect(timer, SIGNAL(timeout()), seq, SLOT(midiInputReady()));
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// registerOutPort
|
|
//---------------------------------------------------------
|
|
|
|
Port PortMidiDriver::registerOutPort(const QString&)
|
|
{
|
|
return Port();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// registerInPort
|
|
//---------------------------------------------------------
|
|
|
|
Port PortMidiDriver::registerInPort(const QString&)
|
|
{
|
|
return Port();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getInputPollFd
|
|
//---------------------------------------------------------
|
|
|
|
void PortMidiDriver::getInputPollFd(struct pollfd**, int* n)
|
|
{
|
|
*n = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getOutputPollFd
|
|
//---------------------------------------------------------
|
|
|
|
void PortMidiDriver::getOutputPollFd(struct pollfd**, int* n)
|
|
{
|
|
*n = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void PortMidiDriver::read()
|
|
{
|
|
static const int THRESHOLD = 3; // iterations required before consecutive drum notes are not considered part of a chord
|
|
static int active = 0;
|
|
static int iter = 0;
|
|
//for some reason, some users could have "active" blocked in < 0
|
|
if (active < 0)
|
|
active = 0;
|
|
if (!inputStream)
|
|
return;
|
|
PmEvent buffer[1];
|
|
iter = (iter >= THRESHOLD) ? iter : (iter+1);
|
|
while (Pm_Poll(inputStream)) {
|
|
int n = Pm_Read(inputStream, buffer, 1);
|
|
if (n > 0) {
|
|
int status = Pm_MessageStatus(buffer[0].message);
|
|
int type = status & 0xF0;
|
|
int channel = status & 0x0F;
|
|
if (type == ME_NOTEON) {
|
|
int pitch = Pm_MessageData1(buffer[0].message);
|
|
int velo = Pm_MessageData2(buffer[0].message);
|
|
mscore->midiNoteReceived(channel, pitch, velo);
|
|
}
|
|
else if (type == ME_NOTEOFF) {
|
|
int pitch = Pm_MessageData1(buffer[0].message);
|
|
int velo = Pm_MessageData2(buffer[0].message);
|
|
mscore->midiNoteReceived(channel, pitch, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// write
|
|
//---------------------------------------------------------
|
|
|
|
void PortMidiDriver::write(const Event&)
|
|
{
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// deviceInList
|
|
//---------------------------------------------------------
|
|
|
|
QStringList PortMidiDriver::deviceInList() const
|
|
{
|
|
QStringList il;
|
|
int interf = Pm_CountDevices();
|
|
for (PmDeviceID id = 0; id < interf; id++) {
|
|
const PmDeviceInfo* info = Pm_GetDeviceInfo((PmDeviceID)id);
|
|
if(info->input)
|
|
il.append(QString(info->interf) +","+ QString(info->name));
|
|
}
|
|
return il;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// getDeviceIn
|
|
//---------------------------------------------------------
|
|
|
|
int PortMidiDriver::getDeviceIn(const QString& name)
|
|
{
|
|
int interf = Pm_CountDevices();
|
|
for (int id = 0; id < interf; id++) {
|
|
const PmDeviceInfo* info = Pm_GetDeviceInfo((PmDeviceID)id);
|
|
if (info->input) {
|
|
QString n = QString(info->interf) + "," + QString(info->name);
|
|
if (n == name)
|
|
return id;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|