bool checkRoute(const QString& s, const QString& d)/*{{{*/ { Route src(s, false, -1); Route dst(d, true, -1); if (!(src.isValid() && dst.isValid()) || (src == dst)) return false; if (src.type == Route::JACK_ROUTE) { if (dst.type == Route::TRACK_ROUTE) { if (dst.track->type() != Track::AUDIO_INPUT) { return false; } src.channel = dst.channel; RouteList* inRoutes = dst.track->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (*i == src) { // route already there return false; } } } else if (dst.type == Route::MIDI_DEVICE_ROUTE) { src.channel = -1; RouteList* routes = dst.device->inRoutes(); for (iRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == src) { // route already there return false; } } } else return false; } else if (dst.type == Route::JACK_ROUTE) { if (src.type == Route::TRACK_ROUTE) { if (src.track->type() != Track::AUDIO_OUTPUT) { return false; } RouteList* outRoutes = src.track->outRoutes(); dst.channel = src.channel; for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { // route already there return false; } } } else if (src.type == Route::MIDI_DEVICE_ROUTE) { RouteList* routes = src.device->outRoutes(); dst.channel = -1; for (iRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == dst) { // route already there return false; } } } else return false; } else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { RouteList* outRoutes = midiPorts[src.midiPort].outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { // route already there return false; } } } else { RouteList* outRoutes = (src.type == Route::MIDI_DEVICE_ROUTE) ? src.device->outRoutes() : src.track->outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { // route already there return false; } } } return true; }/*}}}*/
void addRoute(Route src, Route dst)/*{{{*/ { //TODO: Add hooks to update the patchcanvas on success //This should be conditionally checked so we dont update if the canvas is what made the connection #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute:\n"); #endif if (!src.isValid() || !dst.isValid()) { if (!src.isValid()) fprintf(stderr, "addRoute: invalid src\n"); if (!dst.isValid()) fprintf(stderr, "addRoute: invalid dst\n"); return; } if (src.type == Route::JACK_ROUTE) { if (dst.type == Route::TRACK_ROUTE) { if (dst.track->type() != Track::AUDIO_INPUT) { fprintf(stderr, "addRoute: source is jack, dest:%s is track but not audio input\n", dst.track->name().toLatin1().constData()); return; } if (dst.channel < 0) { fprintf(stderr, "addRoute: source is jack, dest:%s is track but invalid channel:%d\n", dst.track->name().toLatin1().constData(), dst.channel); return; } src.channel = dst.channel; RouteList* inRoutes = dst.track->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (*i == src) // route already there { fprintf(stderr, "addRoute: src track route already exists.\n"); return; } } #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src Jack dst track name: %s pushing source route\n", dst.track->name().toLatin1().constData()); #endif inRoutes->push_back(src); } else if (dst.type == Route::MIDI_DEVICE_ROUTE) { if (dst.device->deviceType() == MidiDevice::JACK_MIDI) { src.channel = dst.channel; RouteList* routes = dst.device->inRoutes(); for (iRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == src) // route already there { fprintf(stderr, "addRoute: src Jack midi route already exists.\n"); return; } } #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src Jack dst Jack midi name: %s pushing source route\n", dst.device->name().toLatin1().constData()); #endif routes->push_back(src); } else { fprintf(stderr, "addRoute: source is Jack, but destination is not jack midi - type:%d\n", dst.device->deviceType()); return; } } else { fprintf(stderr, "addRoute: source is Jack, but destination is not track or midi - type:%d \n", dst.type); return; } } else if (dst.type == Route::JACK_ROUTE) { if (src.type == Route::TRACK_ROUTE) { if (src.track->type() != Track::AUDIO_OUTPUT) { fprintf(stderr, "addRoute: destination is jack, source is track but not audio output\n"); return; } if (src.channel < 0) { fprintf(stderr, "addRoute: destination is jack, source:%s is track but invalid channel:%d\n", src.track->name().toLatin1().constData(), src.channel); return; } RouteList* outRoutes = src.track->outRoutes(); dst.channel = src.channel; for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) // route already there { #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: dst track route already exists.\n"); #endif return; } } #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: dst Jack src track name: %s pushing destination route\n", src.track->name().toLatin1().constData()); #endif outRoutes->push_back(dst); } else if (src.type == Route::MIDI_DEVICE_ROUTE) { if (src.device->deviceType() == MidiDevice::JACK_MIDI) { dst.channel = src.channel; RouteList* routes = src.device->outRoutes(); for (iRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == dst) // route already there { fprintf(stderr, "addRoute: dst Jack midi route already exists.\n"); return; } } #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: dst Jack src Jack midi name: %s pushing destination route\n", src.device->name().toLatin1().constData()); #endif routes->push_back(dst); } else { fprintf(stderr, "addRoute: destination is Jack, but source is not jack midi - type:%d\n", src.device->deviceType()); return; } } else { fprintf(stderr, "addRoute: destination is Jack, but source is not track or midi - type:%d \n", src.type); return; } } else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { if (dst.type != Route::TRACK_ROUTE) { fprintf(stderr, "addRoute: source is midi port:%d, but destination is not track\n", src.midiPort); return; } if (dst.channel < 1 || dst.channel >= (1 << MIDI_CHANNELS)) { fprintf(stderr, "addRoute: source is midi port:%d, but destination channel mask:%d out of range\n", src.midiPort, dst.channel); return; } MidiPort *mp = &midiPorts[src.midiPort]; src.channel = dst.channel; RouteList* outRoutes = mp->outRoutes(); iRoute ir = outRoutes->begin(); // p3.3.50 for (; ir != outRoutes->end(); ++ir) { if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track) // p3.3.50 Does a route to the track exist? { ir->channel |= dst.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. break; } } #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src midi port:%d dst track name:%s pushing dst and src routes\n", src.midiPort, dst.track->name().toLatin1().constData()); #endif if (ir == outRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. outRoutes->push_back(dst); RouteList* inRoutes = dst.track->inRoutes(); // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. ir = inRoutes->begin(); for (; ir != inRoutes->end(); ++ir) { if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort) // p3.3.50 Does a route to the midi port exist? { ir->channel |= src.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. break; } } if (ir == inRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. inRoutes->push_back(src); } else if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { if (src.type != Route::TRACK_ROUTE) { fprintf(stderr, "addRoute: destination is midi port:%d, but source is not track\n", dst.midiPort); return; } if (src.channel < 1 || src.channel >= (1 << MIDI_CHANNELS)) { fprintf(stderr, "addRoute: destination is midi port:%d, but source channel mask:%d out of range\n", dst.midiPort, src.channel); return; } dst.channel = src.channel; RouteList* outRoutes = src.track->outRoutes(); iRoute ir = outRoutes->begin(); // p3.3.50 for (; ir != outRoutes->end(); ++ir) { if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == dst.midiPort) // p3.3.50 Does a route to the midi port exist? { ir->channel |= dst.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. break; } } if (ir == outRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. outRoutes->push_back(dst); MidiPort *mp = &midiPorts[dst.midiPort]; #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src track:%s dst midi port:%d pushing dst and src routes\n", src.track->name().toLatin1().constData(), dst.midiPort); #endif RouteList* inRoutes = mp->inRoutes(); // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. ir = inRoutes->begin(); for (; ir != inRoutes->end(); ++ir) { if (ir->type == Route::TRACK_ROUTE && ir->track == src.track) // p3.3.50 Does a route to the track exist? { ir->channel |= src.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. break; } } if (ir == inRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. inRoutes->push_back(src); } else { if (src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) // p3.3.49 { fprintf(stderr, "addRoute: source or destination are not track routes\n"); return; } { RouteList* outRoutes = src.track->outRoutes(); // // Must enforce to ensure channel and channels are valid if defaults of -1 passed. // if (src.track->type() == Track::AUDIO_SOFTSYNTH) { if (src.channel == -1) src.channel = 0; if (src.channels == -1) src.channels = src.track->channels(); dst.channel = src.channel; dst.channels = src.channels; dst.remoteChannel = src.remoteChannel; } for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) // route already there { //#ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src track route already exists.\n"); //#endif return; } } outRoutes->push_back(dst); RouteList* inRoutes; { #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n", src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().toLatin1().constData()); #endif inRoutes = dst.track->inRoutes(); } // // make sure AUDIO_AUX is processed last // if (src.track->type() == Track::AUDIO_AUX) inRoutes->push_back(src); else inRoutes->insert(inRoutes->begin(), src); } } }/*}}}*/
void removeRoute(Route src, Route dst)/*{{{*/ { //TODO: Add hooks to update the patchcanvas on success //This should be conditionally checked so we dont update if the canvas is what made the connection if (src.type == Route::JACK_ROUTE) { if (!dst.isValid()) { printf("removeRoute: source is jack, invalid destination\n"); return; } if (dst.type == Route::TRACK_ROUTE) { if (dst.track->type() != Track::AUDIO_INPUT) { fprintf(stderr, "removeRoute: source is jack, destination is track but not audio input\n"); // exit(-1); return; } RouteList* inRoutes = dst.track->inRoutes(); iRoute i; for (i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (*i == src) { inRoutes->erase(i); break; } } } else if (dst.type == Route::MIDI_DEVICE_ROUTE) { RouteList* routes = dst.device->inRoutes(); iRoute i; for (i = routes->begin(); i != routes->end(); ++i) { if (*i == src) { routes->erase(i); break; } } } else { fprintf(stderr, "removeRoute: source is jack, destination unknown\n"); return; } } else if (dst.type == Route::JACK_ROUTE) { if (!src.isValid()) { printf("removeRoute: destination is jack, invalid source\n"); return; } if (src.type == Route::TRACK_ROUTE) { if (src.track->type() != Track::AUDIO_OUTPUT) { fprintf(stderr, "removeRoute: destination is jack, source is track but not audio output\n"); return; } RouteList* outRoutes = src.track->outRoutes(); iRoute i; for (i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { outRoutes->erase(i); break; } } } else if (src.type == Route::MIDI_DEVICE_ROUTE) { RouteList* routes = src.device->outRoutes(); iRoute i; for (i = routes->begin(); i != routes->end(); ++i) { if (*i == dst) { routes->erase(i); break; } } } else { fprintf(stderr, "removeRoute: destination is jack, source unknown\n"); // exit(-1); return; } } else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { if (dst.type != Route::TRACK_ROUTE) { fprintf(stderr, "removeRoute: source is midi port:%d, but destination is not track\n", src.midiPort); return; } if (src.isValid()) { MidiPort *mp = &midiPorts[src.midiPort]; RouteList* outRoutes = mp->outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { //if (*i == dst) if (i->type == Route::TRACK_ROUTE && i->track == dst.track) // p3.3.50 Is there a route to the track? { i->channel &= ~dst.channel; // p3.3.50 Unset the desired channel bits. if (i->channel == 0) // Only if there are no channel bits set, erase the route. outRoutes->erase(i); break; // For safety, keep looking and remove any more found. // No, must break, else crash. There should only be one route anyway... } } } else printf("removeRoute: source is midi port:%d but invalid\n", src.midiPort); if (dst.isValid()) { RouteList* inRoutes = dst.track->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == src.midiPort) // p3.3.50 Is there a route to the midi port? { i->channel &= ~src.channel; // p3.3.50 Unset the desired channel bits. if (i->channel == 0) // Only if there are no channel bits set, erase the route. inRoutes->erase(i); break; // For safety, keep looking and remove any more found. // No, must break, else crash. There should only be one route anyway... } } } else printf("removeRoute: source is midi port:%d but destination track invalid\n", src.midiPort); } else if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { if (src.type != Route::TRACK_ROUTE) { fprintf(stderr, "removeRoute: destination is midi port:%d, but source is not track\n", dst.midiPort); return; } if (src.isValid()) { RouteList* outRoutes = src.track->outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == dst.midiPort) // p3.3.50 Is there a route to the midi port? { i->channel &= ~dst.channel; // p3.3.50 Unset the desired channel bits. if (i->channel == 0) // Only if there are no channel bits set, erase the route. outRoutes->erase(i); break; // For safety, keep looking and remove any more found. // No, must break, else crash. There should only be one route anyway... } } } else printf("removeRoute: destination is midi port:%d but source track is invalid\n", dst.midiPort); if (dst.isValid()) { MidiPort *mp = &midiPorts[src.midiPort]; RouteList* inRoutes = mp->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (i->type == Route::TRACK_ROUTE && i->track == src.track) // p3.3.50 Is there a route to the track? { i->channel &= ~src.channel; // p3.3.50 Unset the desired channel bits. if (i->channel == 0) // Only if there are no channel bits set, erase the route. inRoutes->erase(i); break; // For safety, keep looking and remove any more found. // No, must break, else crash. There should only be one route anyway... } } } else printf("removeRoute: destination is midi port:%d but invalid\n", dst.midiPort); } else { if (src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) // p3.3.49 { fprintf(stderr, "removeRoute: source and destination are not tracks\n"); return; } if (src.isValid()) { RouteList* outRoutes = src.track->outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if ((*i).name() == dst.name()) { outRoutes->erase(i); break; } } } else printf("removeRoute: source is track but invalid\n"); if (dst.isValid()) { RouteList* inRoutes = dst.track->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if ((*i).name() == src.name()) { inRoutes->erase(i); break; } } } else printf("removeRoute: source is track but destination invalid\n"); } }/*}}}*/
bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float** bp) { bool have_data = false; if ((MusEGlobal::song->bounceTrack != this) && !noInRoute()) { RouteList* irl = inRoutes(); for(ciRoute i = irl->begin(); i != irl->end(); ++i) { if(i->track->isMidiTrack()) continue; ((AudioTrack*)i->track)->copyData(framePos, channels, i->channel, i->channels, nframe, bp, have_data); have_data = true; } if (recordFlag()) { //if (have_data && recordFlag()) { //if (MusEGlobal::audio->isRecording() && recFile()) { if (have_data && MusEGlobal::audio->isRecording() && recFile()) { if (MusEGlobal::audio->freewheel()) { } else { #ifdef _AUDIO_USE_TRUE_FRAME_ // TODO: Tested: This is the line that would be needed for Audio Inputs, // because the data arrived in the previous period! Test OK, the waves are in sync. // So we need to do Audio Inputs separately above, AND find a way to mix two overlapping // periods into the file! Nothing wrong with the FIFO per se, we could stamp overlapping // times. But the soundfile just writes, does not mix. //if (fifo.put(channels, nframe, bp, MusEGlobal::audio->previousPos().frame())) // // Tested: This line is OK for track-to-track recording, the waves are in sync: #endif if (fifo.put(channels, nframe, bp, MusEGlobal::audio->pos().frame())) printf("WaveTrack::getData(%d, %d, %d): fifo overrun\n", framePos, channels, nframe); } } //return true; // REMOVE Tim. Can't hear existing parts while recording, even while simply armed. // FIXME TODO Remove this. But first code below needs to become ADDITIVE/REPLACING (don't just take over buffers). return have_data; } } if (!MusEGlobal::audio->isPlaying()) return false; //return have_data; if (MusEGlobal::audio->freewheel()) { // when freewheeling, read data direct from file: // Indicate do not seek file before each read. fetchData(framePos, nframe, bp, false); } else { unsigned pos; if (_prefetchFifo.get(channels, nframe, bp, &pos)) { printf("WaveTrack::getData(%s) fifo underrun\n", name().toLocal8Bit().constData()); return false; } if (pos != framePos) { if (MusEGlobal::debugMsg) printf("fifo get error expected %d, got %d\n", framePos, pos); while (pos < framePos) { if (_prefetchFifo.get(channels, nframe, bp, &pos)) { printf("WaveTrack::getData(%s) fifo underrun\n", name().toLocal8Bit().constData()); return false; } } } } return true; }
void MPConfig::songChanged(int flags) { // Is it simply a midi controller value adjustment? Forget it. if (flags == SC_MIDI_CONTROLLER) return; // Get currently selected index... int no = -1; QTableWidgetItem* sitem = mdevView->currentItem(); if (sitem) { QString id = sitem->tableWidget()->item(sitem->row(), DEVCOL_NO)->text(); no = atoi(id.toLatin1().constData()) - 1; if (no < 0 || no >= kMaxMidiPorts) no = -1; } sitem = 0; for (int i = kMaxMidiPorts - 1; i >= 0; --i) { mdevView->blockSignals(true); // otherwise itemChanged() is triggered and bad things happen. MidiPort* port = &midiPorts[i]; MidiDevice* dev = port->device(); QString s; s.setNum(i + 1); QTableWidgetItem* itemno = mdevView->item(i, DEVCOL_NO); QTableWidgetItem* itemstate = mdevView->item(i, DEVCOL_STATE); itemstate->setText(port->state()); QTableWidgetItem* iteminstr = mdevView->item(i, DEVCOL_INSTR); QString instrumentName = port->instrument() ? port->instrument()->iname() : tr("<unknown>"); iteminstr->setText(instrumentName); iteminstr->setToolTip(instrumentName); QTableWidgetItem* itemname = mdevView->item(i, DEVCOL_NAME); QTableWidgetItem* itemgui = mdevView->item(i, DEVCOL_GUI); QTableWidgetItem* itemfb = mdevView->item(i, DEVCOL_CACHE_NRPN); QTableWidgetItem* itemrec = mdevView->item(i, DEVCOL_REC); QTableWidgetItem* itemplay = mdevView->item(i, DEVCOL_PLAY); QTableWidgetItem* itemout = mdevView->item(i, DEVCOL_OUTROUTES); QTableWidgetItem* itemin = mdevView->item(i, DEVCOL_INROUTES); QTableWidgetItem* itemdefin = mdevView->item(i, DEVCOL_DEF_IN_CHANS); itemdefin->setText(bitmap2String(port->defaultInChannels())); QTableWidgetItem* itemdefout = mdevView->item(i, DEVCOL_DEF_OUT_CHANS); itemdefout->setText(bitmap2String(port->defaultOutChannels())); mdevView->blockSignals(false); if (dev) { itemname->setText(dev->name()); itemname->setToolTip(dev->name()); // Is it a Jack midi device? Allow renaming. //if(dynamic_cast<MidiJackDevice*>(dev)) if (dev->deviceType() == MidiDevice::JACK_MIDI) itemname->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled); if (dev->rwFlags() & 0x2) { itemrec->setIcon(dev->openFlags() & 2 ? QIcon(*dotIcon) : QIcon(*dothIcon)); } else { itemrec->setIcon(QIcon(QPixmap())); } if (dev->rwFlags() & 0x1) { itemplay->setIcon(dev->openFlags() & 1 ? QIcon(*dotIcon) : QIcon(*dothIcon)); } else itemplay->setIcon(QIcon(QPixmap())); itemfb->setIcon(dev->cacheNRPN() ? QIcon(*dotIcon) : QIcon(*dothIcon)); } else { itemname->setText(tr("<none>")); itemname->setToolTip(""); itemgui->setIcon(QIcon(*dothIcon)); itemrec->setIcon(QIcon(QPixmap())); itemplay->setIcon(QIcon(QPixmap())); itemfb->setIcon(QIcon(QPixmap())); } // falkTX, we don't want this in the connections manager //if (port->hasGui()) //{ // itemgui->setIcon(port->guiVisible() ? QIcon(*dotIcon) : QIcon(*dothIcon)); //} //else //{ itemgui->setIcon(QIcon(QPixmap())); //} iteminstr->setIcon(QIcon(*buttondownIcon)); itemname->setIcon(QIcon(*buttondownIcon)); //if(dev && dynamic_cast<MidiJackDevice*>(dev)) if (dev && dev->deviceType() == MidiDevice::JACK_MIDI) { //item->setPixmap(DEVCOL_ROUTES, *buttondownIcon); //item->setText(DEVCOL_ROUTES, tr("routes")); // p3.3.55 if (dev->rwFlags() & 1) //if(dev->openFlags() & 1) { itemout->setIcon(QIcon(*buttondownIcon)); if (port->device() && !port->device()->outRoutes()->empty()) { RouteList* list = port->device()->outRoutes(); if (!list->empty()) { iRoute r = list->begin(); itemout->setText(r->name()); } } else { itemout->setText(tr("out")); } //if (dev->openFlags() & 1) // itemout->setText(tr("out")); } if (dev->rwFlags() & 2) //if(dev->openFlags() & 2) { itemin->setIcon(QIcon(*buttondownIcon)); if (dev->openFlags() & 2) itemin->setText(tr("in")); } } if (i == no) sitem = itemno; } if (sitem) { mdevView->setCurrentItem(sitem); } }
void MPConfig::rbClicked(QTableWidgetItem* item) { if (item == 0) return; QString id = item->tableWidget()->item(item->row(), DEVCOL_NO)->text(); int no = atoi(id.toLatin1().constData()) - 1; if (no < 0 || no >= kMaxMidiPorts) return; int n; MidiPort* port = &midiPorts[no]; MidiDevice* dev = port->device(); int rwFlags = dev ? dev->rwFlags() : 0; int openFlags = dev ? dev->openFlags() : 0; QTableWidget* listView = item->tableWidget(); QPoint ppt = listView->visualItemRect(item).bottomLeft(); QPoint mousepos = QCursor::pos(); int col = item->column(); ppt += QPoint(0, listView->horizontalHeader()->height()); ppt = listView->mapToGlobal(ppt); switch (col) { case DEVCOL_GUI: if (dev == 0) //break; return; // falkTX, we don't want this in the connections manager //if (port->hasGui()) //{ // port->instrument()->showGui(!port->guiVisible()); // item->setIcon(port->guiVisible() ? QIcon(*dotIcon) : QIcon(*dothIcon)); //} //break; return; case DEVCOL_CACHE_NRPN: if (!dev) return; dev->setCacheNRPN(!dev->cacheNRPN()); item->setIcon(dev->cacheNRPN() ? QIcon(*dotIcon) : QIcon(*dothIcon)); return; case DEVCOL_REC: if (dev == 0 || !(rwFlags & 2)) return; openFlags ^= 0x2; dev->setOpenFlags(openFlags); midiSeq->msgSetMidiDevice(port, dev); // reopen device item->setIcon(openFlags & 2 ? QIcon(*dotIcon) : QIcon(*dothIcon)); if (dev->deviceType() == MidiDevice::JACK_MIDI) { if (dev->openFlags() & 2) { item->tableWidget()->item(item->row(), DEVCOL_INROUTES)->setText(tr("in")); } else { item->tableWidget()->item(item->row(), DEVCOL_INROUTES)->setText(""); } } return; case DEVCOL_PLAY: if (dev == 0 || !(rwFlags & 1)) return; openFlags ^= 0x1; dev->setOpenFlags(openFlags); midiSeq->msgSetMidiDevice(port, dev); // reopen device item->setIcon(openFlags & 1 ? QIcon(*dotIcon) : QIcon(*dothIcon)); if (dev->deviceType() == MidiDevice::JACK_MIDI) { if (dev->openFlags() & 1) { item->tableWidget()->item(item->row(), DEVCOL_OUTROUTES)->setText(tr("out")); } else { item->tableWidget()->item(item->row(), DEVCOL_OUTROUTES)->setText(""); } } return; case DEVCOL_INROUTES: case DEVCOL_OUTROUTES: { if (!checkAudioDevice()) return; if (audioDevice->deviceType() != AudioDevice::JACK_AUDIO) //Only if Jack is running. return; if (!dev) return; // Only Jack midi devices. if (dev->deviceType() != MidiDevice::JACK_MIDI) return; if (!(dev->openFlags() & ((col == DEVCOL_OUTROUTES) ? 1 : 2))) return; RouteList* rl = (col == DEVCOL_OUTROUTES) ? dev->outRoutes() : dev->inRoutes(); // p3.3.55 QMenu* pup = 0; int gid = 0; std::list<QString> sl; pup = new QMenu(this); //A temporary Route to us for matching later QString currentRoute(""); bool routeSelected = false; _redisplay: pup->clear(); gid = 0; // Jack input ports if device is writable, and jack output ports if device is readable. sl = (col == DEVCOL_OUTROUTES) ? audioDevice->inputPorts(true, _showAliases) : audioDevice->outputPorts(true, _showAliases); QAction* act; act = pup->addAction(tr("Show first aliases")); act->setData(gid); act->setCheckable(true); act->setChecked(_showAliases == 0); ++gid; act = pup->addAction(tr("Show second aliases")); act->setData(gid); act->setCheckable(true); act->setChecked(_showAliases == 1); ++gid; pup->addSeparator(); for (std::list<QString>::iterator ip = sl.begin(); ip != sl.end(); ++ip) { act = pup->addAction(*ip); act->setData(gid); act->setCheckable(true); Route rt(*ip, (col == DEVCOL_OUTROUTES), -1, Route::JACK_ROUTE); for (iRoute ir = rl->begin(); ir != rl->end(); ++ir) { if (*ir == rt) { currentRoute = (*ir).name(); act->setChecked(true); routeSelected = true; break; } } ++gid; } act = pup->exec(ppt); if (act) { n = act->data().toInt(); if (n == 0) // Show first aliases { if (_showAliases == 0) _showAliases = -1; else _showAliases = 0; goto _redisplay; // Go back } else if (n == 1) // Show second aliases { if (_showAliases == 1) _showAliases = -1; else _showAliases = 1; goto _redisplay; // Go back } QString s(act->text()); if (col == DEVCOL_OUTROUTES) // Writable { Route srcRoute(dev, -1); Route dstRoute(s, true, -1, Route::JACK_ROUTE); if(routeSelected && currentRoute == s) { //it will alread be handled by an unchecked operation routeSelected = false; } iRoute iir = rl->begin(); for (; iir != rl->end(); ++iir) { if (*iir == dstRoute) break; } if (iir != rl->end()) { // disconnect audio->msgRemoveRoute(srcRoute, dstRoute); } else { // connect audio->msgAddRoute(srcRoute, dstRoute); } if(routeSelected) { iRoute selr = rl->begin(); for (; selr != rl->end(); ++selr) { //clean up the routing list as something was selected that was not the current so delete the old route if((*selr).name() == currentRoute) { audio->msgRemoveRoute(srcRoute, (*selr)); break; } } } } else { Route srcRoute(s, false, -1, Route::JACK_ROUTE); Route dstRoute(dev, -1); iRoute iir = rl->begin(); for (; iir != rl->end(); ++iir) { if (*iir == srcRoute) break; } if (iir != rl->end()) // disconnect audio->msgRemoveRoute(srcRoute, dstRoute); else // connect audio->msgAddRoute(srcRoute, dstRoute); } audio->msgUpdateSoloStates(); song->update(SC_ROUTE); } delete pup; } return; case DEVCOL_DEF_IN_CHANS: case DEVCOL_DEF_OUT_CHANS: { } //break; return; case DEVCOL_NAME: { //printf("MPConfig::rbClicked DEVCOL_NAME\n"); // Did we click in the text area? // NOTE: this needs the +15 pixels to make up for padding in the stylesheet. if ((mousepos.x() - (ppt.x() + 15)) > buttondownIcon->width()) { // Start the renaming of the cell... QModelIndex current = item->tableWidget()->currentIndex(); if (item->flags() & Qt::ItemIsEditable) item->tableWidget()->edit(current.sibling(current.row(), DEVCOL_NAME)); return; } else {// We clicked the 'down' button. QMenu* pup = new QMenu(this); QAction* act; act = pup->addAction(tr("Create") + QT_TRANSLATE_NOOP("@default", " Jack") + tr(" device")); act->setData(0); typedef std::map<std::string, int > asmap; typedef std::map<std::string, int >::iterator imap; asmap mapALSA; asmap mapJACK; int aix = 0x10000000; int jix = 0x20000000; for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) { if ((*i)->deviceType() == MidiDevice::ALSA_MIDI) { mapALSA.insert(std::pair<std::string, int> (std::string((*i)->name().toLatin1().constData()), aix)); ++aix; } else if ((*i)->deviceType() == MidiDevice::JACK_MIDI) { mapJACK.insert(std::pair<std::string, int> (std::string((*i)->name().toLatin1().constData()), jix)); ++jix; } else printf("MPConfig::rbClicked unknown midi device: %s\n", (*i)->name().toLatin1().constData()); } pup->addSeparator(); pup->addAction(new MenuTitleItem(QT_TRANSLATE_NOOP("@default", "ALSA:"), pup)); for (imap i = mapALSA.begin(); i != mapALSA.end(); ++i) { int idx = i->second; QString s(i->first.c_str()); MidiDevice* md = midiDevices.find(s, MidiDevice::ALSA_MIDI); if (md) { if (md->deviceType() != MidiDevice::ALSA_MIDI) continue; act = pup->addAction(QT_TRANSLATE_NOOP("@default", md->name())); act->setData(idx); act->setCheckable(true); act->setChecked(md == dev); } } pup->addSeparator(); pup->addAction(new MenuTitleItem(QT_TRANSLATE_NOOP("@default", "JACK:"), pup)); for (imap i = mapJACK.begin(); i != mapJACK.end(); ++i) { int idx = i->second; QString s(i->first.c_str()); MidiDevice* md = midiDevices.find(s, MidiDevice::JACK_MIDI); if (md) { if (md->deviceType() != MidiDevice::JACK_MIDI) continue; act = pup->addAction(QT_TRANSLATE_NOOP("@default", md->name())); act->setData(idx); act->setCheckable(true); act->setChecked(md == dev); } } act = pup->exec(ppt); if (!act) { delete pup; return; } n = act->data().toInt(); //printf("MPConfig::rbClicked n:%d\n", n); MidiDevice* sdev = 0; if (n < 0x10000000) { delete pup; if (n <= 2) { sdev = MidiJackDevice::createJackMidiDevice(); if (sdev) { int of = 3; switch (n) { case 0: of = 0; //3; Set the open flags of the midiDevice this should be off by default break; case 1: of = 2; break; case 2: of = 1; break; } sdev->setOpenFlags(of); } } } else { int typ; if (n < 0x20000000) typ = MidiDevice::ALSA_MIDI; else if (n < 0x30000000) typ = MidiDevice::JACK_MIDI; else typ = MidiDevice::UNKNOWN_MIDI; sdev = midiDevices.find(act->text(), typ); delete pup; // Is it the current device? Reset it to <none>. // falkTX, handle synths properly here if (sdev == dev) { sdev = 0; } else { } } midiSeq->msgSetMidiDevice(port, sdev); los->changeConfig(true); // save configuration file song->update(); } } //break; return; case DEVCOL_INSTR: { if (instrPopup == 0) instrPopup = new QMenu(this); instrPopup->clear(); for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { instrPopup->addAction((*i)->iname()); } QAction* act = instrPopup->exec(ppt, 0); if (!act) return; QString s = act->text(); item->tableWidget()->item(item->row(), DEVCOL_INSTR)->setText(s); for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { if ((*i)->iname() == s) { port->setInstrument(*i); break; } } song->update(); } return; } }
void Audio::processMidi() { midiBusy = true; // // TODO: syntis should directly write into recordEventList // for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) { MidiDevice* md = *id; MPEventList* playEvents = md->playEvents(); // // erase already played events: // iMPEvent nextPlayEvent = md->nextPlayEvent(); playEvents->erase(playEvents->begin(), nextPlayEvent); // klumsy hack for synti devices: if (md->isSynti()) { SynthI* s = (SynthI*) md; while (s->eventsPending()) { MidiRecordEvent ev = s->receiveEvent(); md->recordEvent(ev); } } // Is it a Jack midi device? //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md); //if(mjd) // mjd->collectMidiEvents(); md->collectMidiEvents(); // Take snapshots of the current sizes of the recording fifos, // because they may change while here in process, asynchronously. md->beforeProcess(); } MPEventList* playEvents = metronome->playEvents(); iMPEvent nextPlayEvent = metronome->nextPlayEvent(); playEvents->erase(playEvents->begin(), nextPlayEvent); // p3.3.25 bool extsync = extSyncFlag.value(); for (iMidiTrack t = song->midis()->begin(); t != song->midis()->end(); ++t) { MidiTrack* track = *t; int port = track->outPort(); MidiDevice* md = midiPorts[port].device(); // Changed by Tim. p3.3.8 //if(md == 0) // continue; //MPEventList* playEvents = md->playEvents(); //if (playEvents == 0) // continue; //if (!track->isMute()) MPEventList* playEvents = 0; if (md) { playEvents = md->playEvents(); // only add track events if the track is unmuted if (!track->isMute()) { if (isPlaying() && (curTickPos < nextTickPos)) collectEvents(track, curTickPos, nextTickPos); } } // //----------midi recording // if (track->recordFlag()) { //int portMask = track->inPortMask(); // p3.3.38 Removed //unsigned int portMask = track->inPortMask(); //int channelMask = track->inChannelMask(); MPEventList* rl = track->mpevents(); MidiPort* tport = &midiPorts[port]; // p3.3.38 //for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) //{ RouteList* irl = track->inRoutes(); for (ciRoute r = irl->begin(); r != irl->end(); ++r) { //if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE)) //if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE)) if (!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49 continue; int devport = r->midiPort; // p3.3.49 if (devport == -1) continue; //MidiDevice* dev = *id; //MidiDevice* dev = r->device; MidiDevice* dev = midiPorts[devport].device(); // p3.3.49 if (!dev) continue; // p3.3.50 Removed //int channel = r->channel; // NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **. // This would mean having a separate 'System' channel listed in the routing popups. // The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it, // this does not require a 'System' channel listed in the routing popups. // But that requires more code below... Done. //if(channel == -1) //channel = MIDI_CHANNELS; // Special channel '17' // continue; //int devport = dev->midiPort(); // record only from ports marked in portMask: //if (devport == -1 || !(portMask & (1 << devport))) //if (devport == -1) // continue; //MREventList* el = dev->recordEvents(); //MidiFifo& rf = dev->recordEvents(); int channelMask = r->channel; // p3.3.50 if (channelMask == -1 || channelMask == 0) continue; for (int channel = 0; channel < MIDI_CHANNELS; ++channel) // p3.3.50 { if (!(channelMask & (1 << channel))) continue; if (!dev->sysexFIFOProcessed()) { // Set to the sysex fifo at first. MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); // Get the frozen snapshot of the size. int count = dev->tmpRecordCount(MIDI_CHANNELS); for (int i = 0; i < count; ++i) { MidiPlayEvent event(rf.peek(i)); //unsigned time = event.time() + segmentSize*(segmentCount-1); //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); //event.setTime(time); //if(!extsync) // event.setTime(event.time() + segmentSize*(segmentCount-1)); event.setPort(port); // dont't echo controller changes back to software // synthesizer: if (!dev->isSynti() && md && track->recEcho()) playEvents->add(event); // If syncing externally the event time is already in units of ticks, set above. if (!extsync) { //time = tempomap.frame2tick(event.time()); //event.setTime(time); // set tick time event.setTime(tempomap.frame2tick(event.time())); // set tick time } if (recording) rl->add(event); } dev->setSysexFIFOProcessed(true); } // Set to the sysex fifo at first. ///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS); // Get the frozen snapshot of the size. ///int count = dev->tmpRecordCount(MIDI_CHANNELS); // Iterate once for sysex fifo (if needed), once for channel fifos. ///for(int sei = 0; sei < 2; ++sei) { // If on first pass, do sysex fifo. /* if(sei == 0) { // Ignore any further channel routes on this device if already done here. if(dev->sysexFIFOProcessed()) continue; // Go ahead and set this now. dev->setSysexFIFOProcessed(true); // Allow it to fall through with the sysex fifo and count... } else { // We're on the second pass, do channel fifos. rf = dev->recordEvents(channel); // Get the frozen snapshot of the size. count = dev->tmpRecordCount(channel); } */ MidiFifo& rf = dev->recordEvents(channel); int count = dev->tmpRecordCount(channel); //for (iMREvent ie = el->begin(); ie != el->end(); ++ie) for (int i = 0; i < count; ++i) { MidiPlayEvent event(rf.peek(i)); //int channel = ie->channel(); ///int channel = event.channel(); int defaultPort = devport; ///if (!(channelMask & (1 << channel))) ///{ /// continue; ///} //MidiPlayEvent event(*ie); int drumRecPitch = 0; //prevent compiler warning: variable used without initialization MidiController *mc = 0; int ctl = 0; //Hmmm, hehhh... // TODO: Clean up a bit around here when it comes to separate events for rec & for playback. // But not before 0.7 (ml) int prePitch = 0, preVelo = 0; event.setChannel(track->outChannel()); if (event.isNote() || event.isNoteOff()) { // // apply track values // //Apply drum inkey: if (track->type() == Track::DRUM) { int pitch = event.dataA(); //Map note that is played according to drumInmap drumRecPitch = drumMap[(unsigned int) drumInmap[pitch]].enote; devport = drumMap[(unsigned int) drumInmap[pitch]].port; event.setPort(devport); channel = drumMap[(unsigned int) drumInmap[pitch]].channel; event.setA(drumMap[(unsigned int) drumInmap[pitch]].anote); event.setChannel(channel); } else { //Track transpose if non-drum prePitch = event.dataA(); int pitch = prePitch + track->transposition; if (pitch > 127) pitch = 127; if (pitch < 0) pitch = 0; event.setA(pitch); } if (!event.isNoteOff()) { preVelo = event.dataB(); int velo = preVelo + track->velocity; velo = (velo * track->compression) / 100; if (velo > 127) velo = 127; if (velo < 1) velo = 1; event.setB(velo); } } // Added by T356. else if (event.type() == ME_CONTROLLER) { //printf("11111111111111111111111111111111111111111111111111111\n"); if (track->type() == Track::DRUM) { //printf("2222222222222222222222222222222222222222222222222222222222\n"); ctl = event.dataA(); // Regardless of what port the event came from, is it a drum controller event // according to the track port's instrument? mc = tport->drumController(ctl); if (mc) { //printf("333333333333333333333333333333333333333333333333\n"); int pitch = ctl & 0x7f; ctl &= ~0xff; int dmindex = drumInmap[pitch] & 0x7f; //Map note that is played according to drumInmap drumRecPitch = drumMap[dmindex].enote; devport = drumMap[dmindex].port; event.setPort(devport); channel = drumMap[dmindex].channel; event.setA(ctl | drumMap[dmindex].anote); event.setChannel(channel); } } } // p3.3.25 // OOMidi uses a fixed clocks per quarternote of 24. // At standard 384 ticks per quarternote for example, // 384/24=16 for a division of 16 sub-frames (16 OOMidi 'ticks'). // That is what we'll use if syncing externally. //unsigned time = event.time() + segmentSize*(segmentCount-1); //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1)); // p3.3.34 // Oops, use the current tick. //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1)); //event.setTime(time); // p3.3.35 // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice. // p3.3.36 //if(!extsync) // event.setTime(event.time() + segmentSize*(segmentCount-1)); // dont't echo controller changes back to software // synthesizer: if (!dev->isSynti()) { //printf("444444444444444444444444444444444444444444444444444444\n"); //Check if we're outputting to another port than default: if (devport == defaultPort) { //printf("5555555555555555555555555555555555555555555\n"); event.setPort(port); if (md && track->recEcho()) playEvents->add(event); } else { //printf("66666666666666666666666666666666666666\n"); // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent?? MidiDevice* mdAlt = midiPorts[devport].device(); if (mdAlt && track->recEcho()) mdAlt->playEvents()->add(event); } // Shall we activate meters even while rec echo is off? Sure, why not... if (event.isNote() && event.dataB() > track->activity()) track->setActivity(event.dataB()); } // p3.3.25 // If syncing externally the event time is already in units of ticks, set above. if (!extsync) { //printf("7777777777777777777777777777777777777777777\n"); // p3.3.35 //time = tempomap.frame2tick(event.time()); //event.setTime(time); // set tick time event.setTime(tempomap.frame2tick(event.time())); // set tick time } // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml) if (recording) { //printf("888888888888888888888888888888888888888888888888\n"); // In these next steps, it is essential to set the recorded event's port // to the track port so buildMidiEventList will accept it. Even though // the port may have no device "<none>". // if (track->type() == Track::DRUM) { //printf("99999999999999999999999999999999999999999999999999\n"); // Is it a drum controller event? if (mc) { //printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"); MidiPlayEvent drumRecEvent = event; drumRecEvent.setA(ctl | drumRecPitch); // In this case, preVelo is simply the controller value. drumRecEvent.setB(preVelo); drumRecEvent.setPort(port); //rec-event to current port drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel rl->add(drumRecEvent); } else { //printf("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"); MidiPlayEvent drumRecEvent = event; drumRecEvent.setA(drumRecPitch); drumRecEvent.setB(preVelo); // Changed by T356. // Tested: Events were not being recorded for a drum map entry pointing to a // different port. This must have been wrong - buildMidiEventList would ignore this. //drumRecEvent.setPort(devport); drumRecEvent.setPort(port); //rec-event to current port drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel rl->add(drumRecEvent); } } else { //printf("ccccccccccccccccccccccccccccccccccccccccccccc\n"); // Restore record-pitch to non-transposed value since we don't want the note transposed twice next MidiPlayEvent recEvent = event; if (prePitch) recEvent.setA(prePitch); if (preVelo) recEvent.setB(preVelo); recEvent.setPort(port); recEvent.setChannel(track->outChannel()); rl->add(recEvent); } } } } } } } // Added by Tim. p3.3.8 if (md) { //printf("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\n"); md->setNextPlayEvent(playEvents->begin()); } } // // clear all recorded events in midiDevices // process stuck notes // for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) { //printf("--------------------------aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"); MidiDevice* md = *id; ///md->recordEvents()->clear(); // By T356. Done processing this rec buffer, now flip to the other one. ///md->flipRecBuffer(); // We are done with the 'frozen' recording fifos, remove the events. md->afterProcess(); MPEventList* stuckNotes = md->stuckNotes(); MPEventList* playEvents = md->playEvents(); iMPEvent k; for (k = stuckNotes->begin(); k != stuckNotes->end(); ++k) { if (k->time() >= nextTickPos) break; MidiPlayEvent ev(*k); // p3.3.25 //int frame = tempomap.tick2frame(k->time()) + frameOffset; if (extsync) { ev.setTime(k->time()); } else { int frame = tempomap.tick2frame(k->time()) + frameOffset; ev.setTime(frame); } // p3.3.25 //ev.setTime(frame); playEvents->add(ev); } stuckNotes->erase(stuckNotes->begin(), k); md->setNextPlayEvent(playEvents->begin()); } //--------------------------------------------------- // insert metronome clicks //--------------------------------------------------- MidiDevice* md = 0; if (midiClickFlag) md = midiPorts[clickPort].device(); if (song->click() && (isPlaying() || state == PRECOUNT)) { MPEventList* playEvents = 0; MPEventList* stuckNotes = 0; if (md) { playEvents = md->playEvents(); stuckNotes = md->stuckNotes(); } int bar, beat; unsigned tick; bool isMeasure = false; while (midiClick < nextTickPos) { if (isPlaying()) { ///sigmap.tickValues(midiClick, &bar, &beat, &tick); AL::sigmap.tickValues(midiClick, &bar, &beat, &tick); isMeasure = beat == 0; } else if (state == PRECOUNT) { isMeasure = (clickno % clicksMeasure) == 0; } // p3.3.25 //int frame = tempomap.tick2frame(midiClick) + frameOffset; int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset; // p3.3.25 //MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON, beatClickNote, beatClickVelo); if (md) { // p3.3.25 //MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON, beatClickNote, beatClickVelo); if (isMeasure) { ev.setA(measureClickNote); ev.setB(measureClickVelo); } playEvents->add(ev); } if (audioClickFlag) { // p3.3.25 //MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0); MidiPlayEvent ev1(evtime, 0, 0, ME_NOTEON, 0, 0); ev1.setA(isMeasure ? 0 : 1); metronome->playEvents()->add(ev1); } if (md) { ev.setB(0); // p3.3.25 // Removed. Why was this here? //frame = tempomap.tick2frame(midiClick+20) + frameOffset; // // Does it mean this should be changed too? // No, stuck notes are in units of ticks, not frames like (normal, non-external) play events... ev.setTime(midiClick + 10); if (md) stuckNotes->add(ev); } if (isPlaying()) ///midiClick = sigmap.bar2tick(bar, beat+1, 0); midiClick = AL::sigmap.bar2tick(bar, beat + 1, 0); else if (state == PRECOUNT) { midiClick += ticksBeat; if (clickno) --clickno; else state = START_PLAY; } } if (md) md->setNextPlayEvent(playEvents->begin()); if (audioClickFlag) metronome->setNextPlayEvent(metronome->playEvents()->begin()); } if (state == STOP) { //--------------------------------------------------- // end all notes //--------------------------------------------------- for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) { MidiDevice* md = *imd; MPEventList* playEvents = md->playEvents(); MPEventList* stuckNotes = md->stuckNotes(); for (iMPEvent k = stuckNotes->begin(); k != stuckNotes->end(); ++k) { MidiPlayEvent ev(*k); ev.setTime(0); // play now playEvents->add(ev); } stuckNotes->clear(); } } // p3.3.36 //int tickpos = audio->tickPos(); //bool extsync = extSyncFlag.value(); // // Special for Jack midi devices: Play all Jack midi events up to curFrame. // for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) { (*id)->processMidi(); /* int port = md->midiPort(); MidiPort* mp = port != -1 ? &midiPorts[port] : 0; MPEventList* el = md->playEvents(); if (el->empty()) continue; iMPEvent i = md->nextPlayEvent(); for(; i != el->end(); ++i) { // If syncing to external midi sync, we cannot use the tempo map. // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. //if(i->time() > curFrame) if(i->time() > (extsync ? tickpos : curFrame)) { //printf(" curT %d frame %d\n", i->time(), curFrame); break; // skip this event } if(mp) { if(mp->sendEvent(*i)) break; } else { if(md->putEvent(*i)) break; } } md->setNextPlayEvent(i); */ } midiBusy = false; }
void AudioPortConfig::addOutRoute()/*{{{*/ { QListWidgetItem* dstItem = newDstList->currentItem(); QListWidgetItem* tItem = tracksList->currentItem(); if (!_selected || dstItem == 0) return; RouteList* rl = _selected->outRoutes(); int chan = 0; if (_selected->type() == Track::WAVE_OUTPUT_HELPER) { if(!tItem) return; int row = tracksList->row(tItem); QList<QListWidgetItem*> found = tracksList->findItems(tItem->text(), Qt::MatchExactly); if(found.isEmpty()) return; for(int i = 0; i < found.size(); ++i) { QListWidgetItem* item = found.at(i); chan = i; int r = tracksList->row(item); if(r == row) break; } Route srcRoute(_selected, chan); Route dstRoute(dstItem->text(), true, -1, Route::JACK_ROUTE); dstRoute.channel = chan; // check if route src->dst exists: iRoute irl = rl->begin(); for (; irl != rl->end(); ++irl) { if (*irl == dstRoute) break; } audio->msgAddRoute(srcRoute, dstRoute); audio->msgUpdateSoloStates(); song->update(SC_ROUTE); //new QTreeWidgetItem(routeList, QStringList() << srcRoute.name() << dstRoute.name()); btnConnectOut->setEnabled(false); return; } else { Route srcRoute(_selected, chan, _selected->channels()); Route dstRoute(dstItem->text(), true, -1); audio->msgAddRoute(srcRoute, dstRoute); audio->msgUpdateSoloStates(); song->update(SC_ROUTE); //new QTreeWidgetItem(routeList, QStringList() << srcRoute.name() << dstRoute.name()); btnConnectOut->setEnabled(false); } /* audio->msgAddRoute(Route(srcItem->text(), false, -1), Route(dstItem->text(), true, -1)); audio->msgUpdateSoloStates(); //song->update(SC_SOLO); song->update(SC_ROUTE); new QTreeWidgetItem(routeList, QStringList() << srcItem->text() << dstItem->text()); connectButton->setEnabled(false); */ }/*}}}*/