SMF playback, graphic user interface program.
#include "guiplayer.h"
#include "ui_guiplayer.h"
#include "playerabout.h"
#include "player.h"
#include "song.h"
#include <QtGui/QApplication>
#include <QtGui/QFileDialog>
#include <QtGui/QInputDialog>
#include <QtGui/QDragEnterEvent>
#include <QtGui/QDropEvent>
#include <QtGui/QCloseEvent>
#include <QtGui/QToolTip>
#include <QtGui/QMessageBox>
#include <QtGui/QStatusBar>
#include <QtCore/QSettings>
#include <QtCore/QUrl>
#include <QtCore/QFileInfo>
#include <QtCore/QTextCodec>
#include <qmath.h>
GUIPlayer::GUIPlayer(QWidget *parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags),
m_portId(-1),
m_queueId(-1),
m_initialTempo(0),
m_tempoFactor(1.0),
m_tick(0),
m_state(InvalidState),
m_smf(0),
m_wrk(0),
m_ove(0),
m_Client(0),
m_Port(0),
m_Queue(0),
m_player(0),
m_ui(new Ui::GUIPlayerClass),
m_pd(0),
m_aboutDlg(0),
m_song(new Song)
{
m_ui->setupUi(this);
setAcceptDrops(true);
connect(m_ui->actionAbout, SIGNAL(triggered()), SLOT(about()));
connect(m_ui->actionAboutQt, SIGNAL(triggered()), SLOT(aboutQt()));
connect(m_ui->actionPlay, SIGNAL(triggered()), SLOT(play()));
connect(m_ui->actionPause, SIGNAL(triggered()), SLOT(pause()));
connect(m_ui->actionStop, SIGNAL(triggered()), SLOT(stop()));
connect(m_ui->actionOpen, SIGNAL(triggered()), SLOT(open()));
connect(m_ui->actionMIDISetup, SIGNAL(triggered()), SLOT(setup()));
connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(quit()));
connect(m_ui->btnTempo, SIGNAL(clicked()), SLOT(tempoReset()));
connect(m_ui->btnVolume, SIGNAL(clicked()), SLOT(volumeReset()));
connect(m_ui->sliderTempo, SIGNAL(valueChanged(int)), SLOT(tempoSlider(int)));
connect(m_ui->volumeSlider, SIGNAL(valueChanged(int)), SLOT(volumeSlider(int)));
connect(m_ui->spinPitch, SIGNAL(valueChanged(int)), SLOT(pitchShift(int)));
connect(m_ui->toolBar->toggleViewAction(), SIGNAL(toggled(bool)),
m_ui->actionShowToolbar, SLOT(setChecked(bool)));
m_ui->actionPlay->setShortcut( Qt::Key_MediaPlay );
m_ui->actionStop->setShortcut( Qt::Key_MediaStop );
m_Client = new MidiClient(this);
m_Client->open();
m_Client->setPoolOutput(50);
m_Client->setClientName("MIDI Player");
connect( m_Client, SIGNAL(eventReceived(SequencerEvent*)),
SLOT(sequencerEvent(SequencerEvent*)), Qt::QueuedConnection );
m_Port = new MidiPort(this);
m_Port->attach( m_Client );
m_Port->setPortName("MIDI Player Output Port");
m_Port->setCapability( SND_SEQ_PORT_CAP_READ |
SND_SEQ_PORT_CAP_SUBS_READ |
SND_SEQ_PORT_CAP_WRITE );
m_Port->setPortType( SND_SEQ_PORT_TYPE_APPLICATION |
SND_SEQ_PORT_TYPE_MIDI_GENERIC );
m_Queue = m_Client->createQueue(QSTR_APPNAME);
m_queueId = m_Queue->getId();
m_portId = m_Port->getPortId();
m_smf = new QSmf(this);
connect(m_smf, SIGNAL(signalSMFHeader(int,int,int)),
SLOT(smfHeaderEvent(int,int,int)));
connect(m_smf, SIGNAL(signalSMFNoteOn(int,int,int)),
SLOT(smfNoteOnEvent(int,int,int)));
connect(m_smf, SIGNAL(signalSMFNoteOff(int,int,int)),
SLOT(smfNoteOffEvent(int,int,int)));
connect(m_smf, SIGNAL(signalSMFKeyPress(int,int,int)),
SLOT(smfKeyPressEvent(int,int,int)));
connect(m_smf, SIGNAL(signalSMFCtlChange(int,int,int)),
SLOT(smfCtlChangeEvent(int,int,int)));
connect(m_smf, SIGNAL(signalSMFPitchBend(int,int)),
SLOT(smfPitchBendEvent(int,int)));
connect(m_smf, SIGNAL(signalSMFProgram(int,int)),
SLOT(smfProgramEvent(int,int)));
connect(m_smf, SIGNAL(signalSMFChanPress(int,int)),
SLOT(smfChanPressEvent(int,int)));
connect(m_smf, SIGNAL(signalSMFSysex(const QByteArray&)),
SLOT(smfSysexEvent(const QByteArray&)));
connect(m_smf, SIGNAL(signalSMFText(int,const QString&)),
SLOT(smfUpdateLoadProgress()));
connect(m_smf, SIGNAL(signalSMFTempo(int)),
SLOT(smfTempoEvent(int)));
connect(m_smf, SIGNAL(signalSMFTrackStart()),
SLOT(smfUpdateLoadProgress()));
connect(m_smf, SIGNAL(signalSMFTrackEnd()),
SLOT(smfUpdateLoadProgress()));
connect(m_smf, SIGNAL(signalSMFendOfTrack()),
SLOT(smfUpdateLoadProgress()));
connect(m_smf, SIGNAL(signalSMFError(const QString&)),
SLOT(smfErrorHandler(const QString&)));
m_wrk = new QWrk(this);
connect(m_wrk, SIGNAL(signalWRKError(const QString&)),
SLOT(wrkErrorHandler(const QString&)));
connect(m_wrk, SIGNAL(signalWRKUnknownChunk(int,const QByteArray&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKHeader(int,int)),
SLOT(wrkFileHeader(int,int)));
connect(m_wrk, SIGNAL(signalWRKEnd()),
SLOT(wrkEndOfFile()));
connect(m_wrk, SIGNAL(signalWRKStreamEnd(long)),
SLOT(wrkStreamEndEvent(long)));
connect(m_wrk, SIGNAL(signalWRKGlobalVars()),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKTrack(const QString&, const QString&, int,int,int,int,int,bool,bool,bool)),
SLOT(wrkTrackHeader(const QString&, const QString&, int,int,int,int,int,bool,bool,bool)));
connect(m_wrk, SIGNAL(signalWRKTimeBase(int)),
SLOT(wrkTimeBase(int)));
connect(m_wrk, SIGNAL(signalWRKNote(int,long,int,int,int,int)),
SLOT(wrkNoteEvent(int,long,int,int,int,int)));
connect(m_wrk, SIGNAL(signalWRKKeyPress(int,long,int,int,int)),
SLOT(wrkKeyPressEvent(int,long,int,int,int)));
connect(m_wrk, SIGNAL(signalWRKCtlChange(int,long,int,int,int)),
SLOT(wrkCtlChangeEvent(int,long,int,int,int)));
connect(m_wrk, SIGNAL(signalWRKPitchBend(int,long,int,int)),
SLOT(wrkPitchBendEvent(int,long,int,int)));
connect(m_wrk, SIGNAL(signalWRKProgram(int,long,int,int)),
SLOT(wrkProgramEvent(int,long,int,int)));
connect(m_wrk, SIGNAL(signalWRKChanPress(int,long,int,int)),
SLOT(wrkChanPressEvent(int,long,int,int)));
connect(m_wrk, SIGNAL(signalWRKSysexEvent(int,long,int)),
SLOT(wrkSysexEvent(int,long,int)));
connect(m_wrk, SIGNAL(signalWRKSysex(int,const QString&,bool,int,const QByteArray&)),
SLOT(wrkSysexEventBank(int,const QString&,bool,int,const QByteArray&)));
connect(m_wrk, SIGNAL(signalWRKText(int,long,int,const QString&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKTimeSig(int,int,int)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKKeySig(int,int)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKTempo(long,int)),
SLOT(wrkTempoEvent(long,int)));
connect(m_wrk, SIGNAL(signalWRKTrackPatch(int,int)),
SLOT(wrkTrackPatch(int,int)));
connect(m_wrk, SIGNAL(signalWRKComments(const QString&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKVariableRecord(const QString&,const QByteArray&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKNewTrack(const QString&,int,int,int,int,int,bool,bool,bool)),
SLOT(wrkNewTrackHeader(const QString&,int,int,int,int,int,bool,bool,bool)));
connect(m_wrk, SIGNAL(signalWRKTrackName(int,const QString&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKTrackVol(int,int)),
SLOT(wrkTrackVol(int,int)));
connect(m_wrk, SIGNAL(signalWRKTrackBank(int,int)),
SLOT(wrkTrackBank(int,int)));
connect(m_wrk, SIGNAL(signalWRKSegment(int,long,const QString&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKChord(int,long,const QString&,const QByteArray&)),
SLOT(wrkUpdateLoadProgress()));
connect(m_wrk, SIGNAL(signalWRKExpression(int,long,int,const QString&)),
SLOT(wrkUpdateLoadProgress()));
m_ove = new QOve(this);
connect(m_ove, SIGNAL(signalOVEError(const QString&)),
SLOT(oveErrorHandler(const QString&)));
connect(m_ove, SIGNAL(signalOVEHeader(int,int)),
SLOT(oveFileHeader(int,int)));
connect(m_ove, SIGNAL(signalOVEEnd()),
SLOT(wrkEndOfFile()));
connect(m_ove, SIGNAL(signalOVENoteOn(int, long, int, int, int)),
SLOT(oveNoteOnEvent(int, long, int, int, int)));
connect(m_ove, SIGNAL(signalOVENoteOff(int, long, int, int, int)),
SLOT(oveNoteOffEvent(int, long, int, int, int)));
connect(m_ove, SIGNAL(signalOVEKeyPress(int,long,int,int,int)),
SLOT(wrkKeyPressEvent(int,long,int,int,int)));
connect(m_ove, SIGNAL(signalOVECtlChange(int,long,int,int,int)),
SLOT(wrkCtlChangeEvent(int,long,int,int,int)));
connect(m_ove, SIGNAL(signalOVEPitchBend(int,long,int,int)),
SLOT(wrkPitchBendEvent(int,long,int,int)));
connect(m_ove, SIGNAL(signalOVEProgram(int,long,int,int)),
SLOT(wrkProgramEvent(int,long,int,int)));
connect(m_ove, SIGNAL(signalOVEChanPress(int,long,int,int)),
SLOT(wrkChanPressEvent(int,long,int,int)));
connect(m_ove, SIGNAL(signalOVESysexEvent(int,long,int)),
SLOT(wrkSysexEvent(int,long,int)));
connect(m_ove, SIGNAL(signalOVESysex(int,const QString&,bool,int,const QByteArray&)),
SLOT(wrkSysexEventBank(int,const QString&,bool,int,const QByteArray&)));
connect(m_ove, SIGNAL(signalOVETempo(long,int)),
SLOT(wrkTempoEvent(long,int)));
connect(m_ove, SIGNAL(signalOVETrackPatch(int,int,int)),
SLOT(oveTrackPatch(int,int,int)));
connect(m_ove, SIGNAL(signalOVENewTrack(const QString&,int,int,int,int,int,bool,bool,bool)),
SLOT(wrkNewTrackHeader(const QString&,int,int,int,int,int,bool,bool,bool)));
connect(m_ove, SIGNAL(signalOVETrackVol(int,int,int)),
SLOT(wrkTrackVol(int,int)));
connect(m_ove, SIGNAL(signalOVETrackBank(int,int,int)),
SLOT(oveTrackBank(int,int,int)));
m_player = new Player(m_Client, m_portId);
connect(m_player, SIGNAL(finished()), SLOT(songFinished()));
connect(m_player, SIGNAL(stopped()), SLOT(playerStopped()));
m_Client->setRealTimeInput(false);
m_Client->startSequencerInput();
tempoReset();
volumeReset();
updateState(EmptyState);
}
GUIPlayer::~GUIPlayer()
{
m_Client->stopSequencerInput();
m_Port->detach();
m_Client->close();
delete m_player;
}
void GUIPlayer::subscribe(const QString& portName)
{
try {
if (!m_subscription.isEmpty()) {
m_Port->unsubscribeTo(m_subscription);
}
m_subscription = portName;
m_Port->subscribeTo(m_subscription);
} catch (const SequencerError& err) {
qWarning() << "SequencerError exception. Error code: " << err.code()
<< " (" << err.qstrError() << ")";
qWarning() << "Location: " << err.location();
}
}
void GUIPlayer::updateTimeLabel(int mins, int secs, int cnts)
{
static QChar fill('0');
QString stime = QString("%1:%2.%3").arg(mins,2,10,fill)
.arg(secs,2,10,fill)
.arg(cnts,2,10,fill);
m_ui->lblTime->setText(stime);
}
void GUIPlayer::updateState(PlayerState newState)
{
if (m_state == newState)
return;
switch (newState) {
case EmptyState:
m_ui->actionPlay->setEnabled(false);
m_ui->actionPause->setEnabled(false);
m_ui->actionStop->setEnabled(false);
statusBar()->showMessage("Please, load a song");
break;
case PlayingState:
m_ui->actionPlay->setEnabled(false);
m_ui->actionPause->setEnabled(true);
m_ui->actionStop->setEnabled(true);
statusBar()->showMessage("Playing");
break;
case PausedState:
m_ui->actionPlay->setEnabled(false);
m_ui->actionStop->setEnabled(true);
statusBar()->showMessage("Paused");
break;
case StoppedState:
m_ui->actionPause->setChecked(false);
m_ui->actionPause->setEnabled(false);
m_ui->actionStop->setEnabled(false);
m_ui->actionPlay->setEnabled(true);
statusBar()->showMessage("Stopped");
break;
default:
statusBar()->showMessage("Not initialized");
break;
}
m_state = newState;
}
void GUIPlayer::play()
{
if (!m_song->isEmpty()) {
if (m_player->getInitialPosition() == 0) {
if (m_initialTempo == 0)
return;
QueueTempo firstTempo = m_Queue->getTempo();
firstTempo.setPPQ(m_song->getDivision());
firstTempo.setTempo(m_initialTempo);
firstTempo.setTempoFactor(m_tempoFactor);
m_Queue->setTempo(firstTempo);
m_Client->drainOutput();
m_player->sendVolumeEvents();
}
m_player->start();
updateState(PlayingState);
}
}
void GUIPlayer::pause()
{
if (m_state == PlayingState || m_player->isRunning()) {
m_player->stop();
m_player->setPosition(m_Queue->getStatus().getTickTime());
updateState(PausedState);
} else if (!m_song->isEmpty()) {
m_player->start();
updateState(PlayingState);
}
}
void GUIPlayer::stop()
{
if (m_state == PlayingState || m_state == PausedState ||
m_player->isRunning())
m_player->stop();
if (m_initialTempo != 0)
songFinished();
else
updateState(StoppedState);
}
void GUIPlayer::progressDialogInit(const QString& type, int max)
{
m_pd = new QProgressDialog(0, 0, 0, max, this);
m_pd->setWindowTitle(QString("Loading %1 file...").arg(type));
m_pd->setMinimumDuration(1000);
m_pd->setValue(0);
}
void GUIPlayer::progressDialogUpdate(int pos)
{
if (m_pd != 0) {
m_pd->setValue(pos);
qApp->processEvents();
}
}
void GUIPlayer::progressDialogClose()
{
delete m_pd;
}
void GUIPlayer::openFile(const QString& fileName)
{
QFileInfo finfo(fileName);
if (finfo.exists()) {
m_song->clear();
m_loadingMessages.clear();
m_tick = 0;
m_initialTempo = 0;
try {
QString ext = finfo.suffix().toLower();
if (ext == "wrk") {
progressDialogInit("Cakewalk", finfo.size());
m_wrk->readFromFile(fileName);
}
else if (ext == "mid" || ext == "midi" || ext == "kar") {
progressDialogInit("MIDI", finfo.size());
m_smf->readFromFile(fileName);
}
else if (ext == "ove") {
m_ove->readFromFile(fileName);
}
progressDialogUpdate(finfo.size());
if (m_song->isEmpty()) {
m_ui->lblName->clear();
} else {
m_song->sort();
m_player->setSong(m_song);
m_ui->lblName->setText(finfo.fileName());
m_lastDirectory = finfo.absolutePath();
}
} catch (...) {
m_song->clear();
m_ui->lblName->clear();
}
progressDialogClose();
if (m_initialTempo == 0) {
m_initialTempo = 500000;
}
updateTimeLabel(0,0,0);
updateTempoLabel(6.0e7f / m_initialTempo);
m_ui->progressBar->setValue(0);
if (!m_loadingMessages.isEmpty()) {
m_loadingMessages.insert(0,
"Warning, this file may be non-standard or damaged.<br>");
QMessageBox::warning(this, QSTR_APPNAME, m_loadingMessages);
}
if (m_song->isEmpty())
updateState(EmptyState);
else
updateState(StoppedState);
}
}
void GUIPlayer::open()
{
QString fileName = QFileDialog::getOpenFileName(this,
"Open MIDI File", m_lastDirectory,
"All files (*.kar *.mid *.midi *.ove *.wrk);;"
"Karaoke files (*.kar);;"
"MIDI Files (*.mid *.midi);;"
"Overture Files (*.ove);;"
"Cakewalk files (*.wrk)" );
if (! fileName.isEmpty() ) {
stop();
openFile(fileName);
}
}
void GUIPlayer::setup()
{
bool ok;
int current;
QStringList items;
QListIterator<PortInfo> it(m_Client->getAvailableOutputs());
while(it.hasNext()) {
PortInfo p = it.next();
items << QString("%1:%2").arg(p.getClientName()).arg(p.getPort());
}
current = items.indexOf(m_subscription);
QString item = QInputDialog::getItem(this, "Player subscription",
"Output port:", items,
current, false, &ok);
if (ok && !item.isEmpty())
subscribe(item);
}
void GUIPlayer::songFinished()
{
m_player->resetPosition();
updateState(StoppedState);
}
void GUIPlayer::playerStopped()
{
int portId = m_Port->getPortId();
for (int channel = 0; channel < 16; ++channel) {
ControllerEvent ev1(channel, MIDI_CTL_ALL_NOTES_OFF, 0);
ev1.setSource(portId);
ev1.setSubscribers();
ev1.setDirect();
m_Client->outputDirect(&ev1);
ControllerEvent ev2(channel, MIDI_CTL_ALL_SOUNDS_OFF, 0);
ev2.setSource(portId);
ev2.setSubscribers();
ev2.setDirect();
m_Client->outputDirect(&ev2);
}
m_Client->drainOutput();
}
void GUIPlayer::updateTempoLabel(float ftempo)
{
QString stempo = QString("%1 bpm").arg(ftempo, 0, 'f', 2);
m_ui->lblOther->setText(stempo);
}
void GUIPlayer::sequencerEvent(SequencerEvent *ev)
{
if ((ev->getSequencerType() == SND_SEQ_EVENT_ECHO) && (m_tick != 0)){
int pos = 100 * ev->getTick() / m_tick;
const snd_seq_real_time_t* rt = m_Queue->getStatus().getRealtime();
int mins = rt->tv_sec / 60;
int secs = rt->tv_sec % 60;
int cnts = qFloor( rt->tv_nsec / 1.0e7 );
updateTempoLabel(m_Queue->getTempo().getRealBPM());
updateTimeLabel(mins, secs, cnts);
m_ui->progressBar->setValue(pos);
}
delete ev;
}
void GUIPlayer::pitchShift(int value)
{
m_player->setPitchShift(value);
}
void GUIPlayer::tempoReset()
{
m_ui->sliderTempo->setValue(100);
tempoSlider(100);
}
void GUIPlayer::volumeReset()
{
m_ui->volumeSlider->setValue(100);
volumeSlider(100);
}
void GUIPlayer::tempoSlider(int value)
{
m_tempoFactor = (value*value + 100.0*value + 20000.0) / 40000.0;
QueueTempo qtempo = m_Queue->getTempo();
qtempo.setTempoFactor(m_tempoFactor);
m_Queue->setTempo(qtempo);
m_Client->drainOutput();
if (!m_player->isRunning())
updateTempoLabel(qtempo.getRealBPM());
QString tip = QString("%1\%").arg(m_tempoFactor*100.0, 0, 'f', 0);
m_ui->sliderTempo->setToolTip(tip);
QToolTip::showText(QCursor::pos(), tip, this);
}
void GUIPlayer::volumeSlider(int value)
{
QString tip = QString::number(value)+'%';
m_ui->lblVolume->setText(tip);
m_ui->volumeSlider->setToolTip(tip);
m_player->setVolumeFactor(value);
QToolTip::showText(QCursor::pos(), tip, this);
}
void GUIPlayer::dragEnterEvent( QDragEnterEvent * event )
{
if (event->mimeData()->hasFormat("text/uri-list"))
event->acceptProposedAction();
}
void GUIPlayer::dropEvent( QDropEvent * event )
{
QString data = event->mimeData()->text();
QString fileName = QUrl(data).path().trimmed();
while (fileName.endsWith(QChar::Null)) fileName.chop(1);
if ( fileName.endsWith(".ove", Qt::CaseInsensitive) ||
fileName.endsWith(".mid", Qt::CaseInsensitive) ||
fileName.endsWith(".midi", Qt::CaseInsensitive) ||
fileName.endsWith(".kar", Qt::CaseInsensitive) ||
fileName.endsWith(".wrk", Qt::CaseInsensitive) ) {
stop();
openFile(fileName);
event->accept();
} else {
QMessageBox::warning(this, QSTR_APPNAME,
QString("Dropped file %1 is not supported").arg(fileName));
}
}
bool GUIPlayer::event(
QEvent * event )
{
if(event->type() == QEvent::Polish) {
readSettings();
QStringList args = QCoreApplication::arguments();
if (args.size() > 1) {
QString first = args.at(1);
openFile(first);
}
event->accept();
}
return QMainWindow::event(event);
}
void GUIPlayer::readSettings()
{
QSettings settings;
settings.beginGroup("Window");
restoreGeometry(settings.value("Geometry").toByteArray());
restoreState(settings.value("State").toByteArray());
settings.endGroup();
settings.beginGroup("Preferences");
m_lastDirectory = settings.value("LastDirectory").toString();
QString midiConn = settings.value("MIDIConnection").toString();
settings.endGroup();
if (midiConn.length() > 0)
subscribe(midiConn);
}
void GUIPlayer::writeSettings()
{
QSettings settings;
settings.beginGroup("Window");
settings.setValue("Geometry", saveGeometry());
settings.setValue("State", saveState());
settings.endGroup();
settings.beginGroup("Preferences");
settings.setValue("LastDirectory", m_lastDirectory);
settings.setValue("MIDIConnection", m_subscription);
settings.endGroup();
}
void GUIPlayer::closeEvent( QCloseEvent *event )
{
writeSettings();
event->accept();
}
void GUIPlayer::about()
{
if (m_aboutDlg == 0)
m_aboutDlg = new About(this);
m_aboutDlg->exec();
}
void GUIPlayer::aboutQt()
{
qApp->aboutQt();
}
void GUIPlayer::quit()
{
stop();
m_player->wait();
close();
}
void GUIPlayer::smfUpdateLoadProgress()
{
progressDialogUpdate(m_smf->getFilePos());
}
void GUIPlayer::appendSMFEvent(SequencerEvent* ev)
{
unsigned long tick = m_smf->getCurrentTime();
ev->setSource(m_portId);
if (ev->getSequencerType() != SND_SEQ_EVENT_TEMPO) {
ev->setSubscribers();
}
ev->scheduleTick(m_queueId, tick, false);
m_song->append(ev);
if (tick > m_tick)
m_tick = tick;
smfUpdateLoadProgress();
}
void GUIPlayer::smfHeaderEvent(int format, int ntrks, int division)
{
m_song->setHeader(format, ntrks, division);
smfUpdateLoadProgress();
}
void GUIPlayer::smfNoteOnEvent(int chan, int pitch, int vol)
{
SequencerEvent* ev = new NoteOnEvent (chan, pitch, vol);
appendSMFEvent(ev);
}
void GUIPlayer::smfNoteOffEvent(int chan, int pitch, int vol)
{
SequencerEvent* ev = new NoteOffEvent (chan, pitch, vol);
appendSMFEvent(ev);
}
void GUIPlayer::smfKeyPressEvent(int chan, int pitch, int press)
{
SequencerEvent* ev = new KeyPressEvent (chan, pitch, press);
appendSMFEvent(ev);
}
void GUIPlayer::smfCtlChangeEvent(int chan, int ctl, int value)
{
SequencerEvent* ev = new ControllerEvent (chan, ctl, value);
appendSMFEvent(ev);
}
void GUIPlayer::smfPitchBendEvent(int chan, int value)
{
SequencerEvent* ev = new PitchBendEvent (chan, value);
appendSMFEvent(ev);
}
void GUIPlayer::smfProgramEvent(int chan, int patch)
{
SequencerEvent* ev = new ProgramChangeEvent (chan, patch);
appendSMFEvent(ev);
}
void GUIPlayer::smfChanPressEvent(int chan, int press)
{
SequencerEvent* ev = new ChanPressEvent (chan, press);
appendSMFEvent(ev);
}
void GUIPlayer::smfSysexEvent(const QByteArray& data)
{
SequencerEvent* ev = new SysExEvent (data);
appendSMFEvent(ev);
}
void GUIPlayer::smfTempoEvent(int tempo)
{
if ( m_initialTempo == 0 ) {
m_initialTempo = tempo;
}
SequencerEvent* ev = new TempoEvent (m_queueId, tempo);
appendSMFEvent(ev);
}
void GUIPlayer::smfErrorHandler(const QString& errorStr)
{
if (m_loadingMessages.length() < 1024)
m_loadingMessages.append(QString("%1 at file offset %2<br>")
.arg(errorStr).arg(m_smf->getFilePos()));
}
void GUIPlayer::wrkUpdateLoadProgress()
{
if (m_pd != 0)
progressDialogUpdate(m_wrk->getFilePos());
}
void
GUIPlayer::appendWRKEvent(unsigned long ticks, SequencerEvent* ev)
{
ev->setSource(m_portId);
if (ev->getSequencerType() != SND_SEQ_EVENT_TEMPO) {
ev->setSubscribers();
}
ev->scheduleTick(m_queueId, ticks, false);
m_song->append(ev);
if (ticks > m_tick)
m_tick = ticks;
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkErrorHandler(const QString& errorStr)
{
if (m_loadingMessages.length() < 1024)
m_loadingMessages.append(QString("%1 at file offset %2<br>")
.arg(errorStr).arg(m_wrk->getFilePos()));
}
void GUIPlayer::wrkFileHeader(int , int )
{
m_song->setHeader(1, 0, 120);
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkTimeBase(int timebase)
{
m_song->setDivision(timebase);
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkStreamEndEvent(long time)
{
unsigned long ticks = time;
if (ticks > m_tick)
m_tick = ticks;
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkTrackHeader( const QString& ,
const QString& ,
int trackno, int channel,
int pitch, int velocity, int ,
bool , bool , bool )
{
TrackMapRec rec;
rec.channel = channel;
rec.pitch = pitch;
rec.velocity = velocity;
m_trackMap[trackno] = rec;
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkNoteEvent(int track, long time, int chan, int pitch, int vol, int dur)
{
int channel = chan;
TrackMapRec rec = m_trackMap[track];
int key = pitch + rec.pitch;
int velocity = vol + rec.velocity;
if (rec.channel > -1)
channel = rec.channel;
SequencerEvent* ev = new NoteEvent(channel, key, velocity, dur);
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkKeyPressEvent(int track, long time, int chan, int pitch, int press)
{
int channel = chan;
TrackMapRec rec = m_trackMap[track];
int key = pitch + rec.pitch;
if (rec.channel > -1)
channel = rec.channel;
SequencerEvent* ev = new KeyPressEvent(channel, key, press);
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkCtlChangeEvent(int track, long time, int chan, int ctl, int value)
{
int channel = chan;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
SequencerEvent* ev = new ControllerEvent(channel, ctl, value);
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkPitchBendEvent(int track, long time, int chan, int value)
{
int channel = chan;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
SequencerEvent* ev = new PitchBendEvent(channel, value);
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkProgramEvent(int track, long time, int chan, int patch)
{
int channel = chan;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
SequencerEvent* ev = new ProgramChangeEvent(channel, patch);
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkChanPressEvent(int track, long time, int chan, int press)
{
int channel = chan;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
SequencerEvent* ev = new ChanPressEvent(channel, press);
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkSysexEvent(int track, long time, int bank)
{
SysexEventRec rec;
rec.track = track;
rec.time = time;
rec.bank = bank;
m_savedSysexEvents.append(rec);
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkSysexEventBank(int bank, const QString& ,
bool autosend, int , const QByteArray& data)
{
SysExEvent* ev = new SysExEvent(data);
if (autosend)
appendWRKEvent(0, ev->clone());
foreach(const SysexEventRec& rec, m_savedSysexEvents) {
if (rec.bank == bank) {
appendWRKEvent(rec.time, ev->clone());
}
}
delete ev;
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkTempoEvent(long time, int tempo)
{
double bpm = tempo / 100.0;
if ( m_initialTempo < 0 )
m_initialTempo = qRound( bpm );
SequencerEvent* ev = new TempoEvent(m_queueId, qRound ( 6e7 / bpm ) );
appendWRKEvent(time, ev);
}
void GUIPlayer::wrkTrackPatch(int track, int patch)
{
int channel = 0;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
wrkProgramEvent(track, 0, channel, patch);
}
void GUIPlayer::wrkNewTrackHeader( const QString& ,
int trackno, int channel,
int pitch, int velocity, int ,
bool , bool , bool )
{
TrackMapRec rec;
rec.channel = channel;
rec.pitch = pitch;
rec.velocity = velocity;
m_trackMap[trackno] = rec;
wrkUpdateLoadProgress();
}
void GUIPlayer::wrkTrackVol(int track, int vol)
{
int channel = 0;
int lsb, msb;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
if (vol < 128)
wrkCtlChangeEvent(track, 0, channel, MIDI_CTL_MSB_MAIN_VOLUME, vol);
else {
lsb = vol % 0x80;
msb = vol / 0x80;
wrkCtlChangeEvent(track, 0, channel, MIDI_CTL_LSB_MAIN_VOLUME, lsb);
wrkCtlChangeEvent(track, 0, channel, MIDI_CTL_MSB_MAIN_VOLUME, msb);
}
}
void GUIPlayer::wrkTrackBank(int track, int bank)
{
int channel = 0;
int lsb, msb;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
channel = rec.channel;
lsb = bank % 0x80;
msb = bank / 0x80;
wrkCtlChangeEvent(track, 0, channel, MIDI_CTL_MSB_BANK, msb);
wrkCtlChangeEvent(track, 0, channel, MIDI_CTL_LSB_BANK, lsb);
}
void GUIPlayer::wrkEndOfFile()
{
if (m_initialTempo < 0)
m_initialTempo = 120;
SequencerEvent* ev = new SystemEvent(SND_SEQ_EVENT_ECHO);
appendWRKEvent(m_tick, ev);
}
void
GUIPlayer::appendOVEEvent(unsigned long ticks, SequencerEvent* ev)
{
ev->setSource(m_portId);
if (ev->getSequencerType() != SND_SEQ_EVENT_TEMPO)
ev->setSubscribers();
ev->scheduleTick(m_queueId, ticks, false);
m_song->append(ev);
if (ticks > m_tick)
m_tick = ticks;
}
void GUIPlayer::oveErrorHandler(const QString& errorStr)
{
if (m_loadingMessages.length() < 1024)
m_loadingMessages.append(errorStr);
}
void GUIPlayer::oveFileHeader(int quarter, int trackCount)
{
m_song->setHeader(1, trackCount, quarter);
}
void GUIPlayer::oveNoteOnEvent(int , long tick, int channel, int pitch, int vol)
{
SequencerEvent* ev = new NoteOnEvent(channel, pitch, vol);
appendOVEEvent(tick, ev);
}
void GUIPlayer::oveNoteOffEvent(int , long tick, int channel, int pitch, int vol)
{
SequencerEvent* ev = new NoteOffEvent(channel, pitch, vol);
appendOVEEvent(tick, ev);
}
void GUIPlayer::oveTrackPatch(int track, int channel, int patch)
{
int ch = channel;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
ch = rec.channel;
wrkProgramEvent(track, 0, ch, patch);
}
void GUIPlayer::oveTrackVol(int track, int channel, int vol)
{
int ch = channel;
int lsb, msb;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
ch = rec.channel;
if (vol < 128)
wrkCtlChangeEvent(track, 0, ch, MIDI_CTL_MSB_MAIN_VOLUME, vol);
else {
lsb = vol % 0x80;
msb = vol / 0x80;
wrkCtlChangeEvent(track, 0, ch, MIDI_CTL_LSB_MAIN_VOLUME, lsb);
wrkCtlChangeEvent(track, 0, ch, MIDI_CTL_MSB_MAIN_VOLUME, msb);
}
}
void GUIPlayer::oveTrackBank(int track, int channel, int bank)
{
int ch = channel;
int lsb, msb;
TrackMapRec rec = m_trackMap[track];
if (rec.channel > -1)
ch = rec.channel;
lsb = bank % 0x80;
msb = bank / 0x80;
wrkCtlChangeEvent(track, 0, ch, MIDI_CTL_MSB_BANK, msb);
wrkCtlChangeEvent(track, 0, ch, MIDI_CTL_LSB_BANK, lsb);
}
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer events.
Classes managing ALSA Sequencer ports.
Classes managing ALSA Sequencer queues.
The QEvent class is the base class of all event classes.
Overture OVE Files Input.
Standard MIDI Files Input/Output.
Cakewalk WRK Files Input.