diff options
Diffstat (limited to 'attic/muse2-oom/muse2/muse/audio.cpp')
-rw-r--r-- | attic/muse2-oom/muse2/muse/audio.cpp | 1439 |
1 files changed, 0 insertions, 1439 deletions
diff --git a/attic/muse2-oom/muse2/muse/audio.cpp b/attic/muse2-oom/muse2/muse/audio.cpp deleted file mode 100644 index 934a5387..00000000 --- a/attic/muse2-oom/muse2/muse/audio.cpp +++ /dev/null @@ -1,1439 +0,0 @@ -//========================================================= -// MusE -// Linux Music Editor -// $Id: audio.cpp,v 1.59.2.30 2009/12/20 05:00:35 terminator356 Exp $ -// -// (C) Copyright 2001-2004 Werner Schweer (ws@seh.de) -//========================================================= - -#include <cmath> -#include <errno.h> - -#include <QSocketNotifier> - -#include "app.h" -#include "song.h" -#include "node.h" -#include "audiodev.h" -//#include "driver/audiodev.h" // p4.0.2 -#include "mididev.h" -#include "alsamidi.h" -//#include "driver/alsamidi.h" // p4.0.2 -#include "synth.h" -#include "audioprefetch.h" -#include "plugin.h" -#include "audio.h" -#include "wave.h" -#include "midictrl.h" -#include "midiseq.h" -#include "sync.h" -#include "midi.h" -#include "event.h" -#include "gconfig.h" -#include "pos.h" -#include "ticksynth.h" - -extern double curTime(); -Audio* audio; -AudioDevice* audioDevice; // current audio device in use - -// p3.3.25 -extern unsigned int volatile midiExtSyncTicks; - - -//static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; -//static const unsigned char mmcStopMsg[] = { 0x7f, 0x7f, 0x06, 0x01 }; - -const char* seqMsgList[] = { - "SEQM_ADD_TRACK", "SEQM_REMOVE_TRACK", "SEQM_CHANGE_TRACK", "SEQM_MOVE_TRACK", - "SEQM_ADD_PART", "SEQM_REMOVE_PART", "SEQM_CHANGE_PART", - "SEQM_ADD_EVENT", "SEQM_REMOVE_EVENT", "SEQM_CHANGE_EVENT", - "SEQM_ADD_TEMPO", "SEQM_SET_TEMPO", "SEQM_REMOVE_TEMPO", "SEQM_ADD_SIG", "SEQM_REMOVE_SIG", - "SEQM_SET_GLOBAL_TEMPO", - "SEQM_UNDO", "SEQM_REDO", - "SEQM_RESET_DEVICES", "SEQM_INIT_DEVICES", "SEQM_PANIC", - "SEQM_MIDI_LOCAL_OFF", - "SEQM_SET_MIDI_DEVICE", - "SEQM_PLAY_MIDI_EVENT", - "SEQM_SET_HW_CTRL_STATE", - "SEQM_SET_HW_CTRL_STATES", - "SEQM_SET_TRACK_OUT_PORT", - "SEQM_SET_TRACK_OUT_CHAN", - "SEQM_REMAP_PORT_DRUM_CTL_EVS", - "SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS", - "SEQM_SCAN_ALSA_MIDI_PORTS", - "SEQM_SET_AUX", - "SEQM_UPDATE_SOLO_STATES", - "MIDI_SHOW_INSTR_GUI", - "AUDIO_RECORD", - "AUDIO_ROUTEADD", "AUDIO_ROUTEREMOVE", "AUDIO_REMOVEROUTES", - "AUDIO_VOL", "AUDIO_PAN", - "AUDIO_ADDPLUGIN", - "AUDIO_SET_SEG_SIZE", - "AUDIO_SET_PREFADER", "AUDIO_SET_CHANNELS", - "AUDIO_SET_PLUGIN_CTRL_VAL", - "AUDIO_SWAP_CONTROLLER_IDX", - "AUDIO_CLEAR_CONTROLLER_EVENTS", - "AUDIO_SEEK_PREV_AC_EVENT", - "AUDIO_SEEK_NEXT_AC_EVENT", - "AUDIO_ERASE_AC_EVENT", - "AUDIO_ERASE_RANGE_AC_EVENTS", - "AUDIO_ADD_AC_EVENT", - "AUDIO_SET_SOLO", "AUDIO_SET_SEND_METRONOME", - "MS_PROCESS", "MS_STOP", "MS_SET_RTC", "MS_UPDATE_POLL_FD", - "SEQM_IDLE", "SEQM_SEEK" - }; - -const char* audioStates[] = { - "STOP", "START_PLAY", "PLAY", "LOOP1", "LOOP2", "SYNC", "PRECOUNT" - }; - - -//--------------------------------------------------------- -// Audio -//--------------------------------------------------------- - -Audio::Audio() - { - _running = false; - recording = false; - idle = false; - _freewheel = false; - _bounce = false; - //loopPassed = false; - _loopFrame = 0; - _loopCount = 0; - - _pos.setType(Pos::FRAMES); - _pos.setFrame(0); - curTickPos = 0; - - midiClick = 0; - clickno = 0; - clicksMeasure = 0; - ticksBeat = 0; - - syncTime = 0.0; - syncFrame = 0; - frameOffset = 0; - - state = STOP; - msg = 0; - - // Changed by Tim. p3.3.8 - //startRecordPos.setType(Pos::TICKS); - //endRecordPos.setType(Pos::TICKS); - startRecordPos.setType(Pos::FRAMES); - endRecordPos.setType(Pos::FRAMES); - - _audioMonitor = 0; - _audioMaster = 0; - - //--------------------------------------------------- - // establish pipes/sockets - //--------------------------------------------------- - - int filedes[2]; // 0 - reading 1 - writing - if (pipe(filedes) == -1) { - perror("creating pipe0"); - exit(-1); - } - fromThreadFdw = filedes[1]; - fromThreadFdr = filedes[0]; - int rv = fcntl(fromThreadFdw, F_SETFL, O_NONBLOCK); - if (rv == -1) - perror("set pipe O_NONBLOCK"); - - if (pipe(filedes) == -1) { - perror("creating pipe1"); - exit(-1); - } - sigFd = filedes[1]; - QSocketNotifier* ss = new QSocketNotifier(filedes[0], QSocketNotifier::Read); - song->connect(ss, SIGNAL(activated(int)), song, SLOT(seqSignal(int))); - } - -//--------------------------------------------------------- -// start -// start audio processing -//--------------------------------------------------------- - -extern bool initJackAudio(); - -bool Audio::start() - { - //process(segmentSize); // warm up caches - state = STOP; - _loopCount = 0; - muse->setHeartBeat(); - if (audioDevice) { - // Added by Tim. p3.3.6 - //_running = true; - - //audioDevice->start(); - } - else { - if(false == initJackAudio()) { - // Added by Tim. p3.3.6 - //_running = true; - - InputList* itl = song->inputs(); - for (iAudioInput i = itl->begin(); i != itl->end(); ++i) { - //printf("reconnecting input %s\n", (*i)->name().ascii()); - for (int x=0; x < (*i)->channels();x++) - (*i)->setJackPort(x,0); - (*i)->setName((*i)->name()); // restore jack connection - } - - OutputList* otl = song->outputs(); - for (iAudioOutput i = otl->begin(); i != otl->end(); ++i) { - //printf("reconnecting output %s\n", (*i)->name().ascii()); - for (int x=0; x < (*i)->channels();x++) - (*i)->setJackPort(x,0); - //printf("name=%s\n",(*i)->name().toLatin1()); - (*i)->setName((*i)->name()); // restore jack connection - } - //audioDevice->start(); - } - else { - printf("Failed to init audio!\n"); - return false; - } - } - - audioDevice->start(realTimePriority); - - _running = true; - - // shall we really stop JACK transport and locate to - // saved position? - - audioDevice->stopTransport(); - //audioDevice->seekTransport(song->cPos().frame()); - audioDevice->seekTransport(song->cPos()); - return true; - } - -//--------------------------------------------------------- -// stop -// stop audio processing -//--------------------------------------------------------- - -void Audio::stop(bool) - { - if (audioDevice) - audioDevice->stop(); - _running = false; - } - -//--------------------------------------------------------- -// sync -// return true if sync is completed -//--------------------------------------------------------- - -bool Audio::sync(int jackState, unsigned frame) - { - -// Changed by Tim. p3.3.24 -/* - bool done = true; - if (state == LOOP1) - state = LOOP2; - else { - if (_pos.frame() != frame) { - Pos p(frame, false); - seek(p); - } - state = State(jackState); - if (!_freewheel) - //done = audioPrefetch->seekDone; - done = audioPrefetch->seekDone(); - } - - return done; -*/ - bool done = true; - if (state == LOOP1) - state = LOOP2; - else { - State s = State(jackState); - // - // STOP -> START_PLAY start rolling - // STOP -> STOP seek in stop state - // PLAY -> START_PLAY seek in play state - - if (state != START_PLAY) { - //Pos p(frame, AL::FRAMES); - // seek(p); - Pos p(frame, false); - seek(p); - if (!_freewheel) - done = audioPrefetch->seekDone(); - if (s == START_PLAY) - state = START_PLAY; - } - else { - //if (frame != _seqTime.pos.frame()) { - if (frame != _pos.frame()) { - // seek during seek - //seek(Pos(frame, AL::FRAMES)); - seek(Pos(frame, false)); - } - done = audioPrefetch->seekDone(); - } - } - return done; - - } - -//--------------------------------------------------------- -// setFreewheel -//--------------------------------------------------------- - -void Audio::setFreewheel(bool val) - { -// printf("JACK: freewheel callback %d\n", val); - _freewheel = val; - } - -//--------------------------------------------------------- -// shutdown -//--------------------------------------------------------- - -void Audio::shutdown() - { - _running = false; - printf("Audio::shutdown()\n"); - write(sigFd, "S", 1); - } - -//--------------------------------------------------------- -// process -// process one audio buffer at position "_pos " -// of size "frames" -//--------------------------------------------------------- - -void Audio::process(unsigned frames) - { - // Disabled by Tim. p3.3.22 -// extern int watchAudio; -// ++watchAudio; // make a simple watchdog happy - - if (!checkAudioDevice()) return; - if (msg) { - processMsg(msg); - int sn = msg->serialNo; - msg = 0; // dont process again - int rv = write(fromThreadFdw, &sn, sizeof(int)); - if (rv != sizeof(int)) { - fprintf(stderr, "audio: write(%d) pipe failed: %s\n", - fromThreadFdw, strerror(errno)); - } - } - - OutputList* ol = song->outputs(); - if (idle) { - // deliver no audio - for (iAudioOutput i = ol->begin(); i != ol->end(); ++i) - (*i)->silence(frames); - return; - } - - int jackState = audioDevice->getState(); - - //if(debugMsg) - // printf("Audio::process Current state:%s jackState:%s\n", audioStates[state], audioStates[jackState]); - - if (state == START_PLAY && jackState == PLAY) { - _loopCount = 0; - startRolling(); - if (_bounce) - write(sigFd, "f", 1); - } - else if (state == LOOP2 && jackState == PLAY) { - ++_loopCount; // Number of times we have looped so far - Pos newPos(_loopFrame, false); - seek(newPos); - startRolling(); - } - else if (isPlaying() && jackState == STOP) { - // p3.3.43 Make sure to stop bounce and freewheel mode, for example if user presses stop - // in QJackCtl before right-hand marker is reached (which is handled below). - //printf("Audio::process isPlaying() && jackState == STOP\n"); - //if (_bounce) - //{ - //printf(" stopping bounce...\n"); - // _bounce = false; - // write(sigFd, "F", 1); - //} - - stopRolling(); - } - else if (state == START_PLAY && jackState == STOP) { - state = STOP; - if (_bounce) { - audioDevice->startTransport(); - } - else - write(sigFd, "3", 1); // abort rolling - } - else if (state == STOP && jackState == PLAY) { - _loopCount = 0; - startRolling(); - } - else if (state == LOOP1 && jackState == PLAY) - ; // treat as play - else if (state == LOOP2 && jackState == START_PLAY) { - ; // sync cycle - } - else if (state != jackState) - printf("JACK: state transition %s -> %s ?\n", - audioStates[state], audioStates[jackState]); - -// printf("p %s %s %d\n", audioStates[jackState], audioStates[state], _pos.frame()); - - // - // clear aux send buffers - // - AuxList* al = song->auxs(); - for (unsigned i = 0; i < al->size(); ++i) { - AudioAux* a = (AudioAux*)((*al)[i]); - float** dst = a->sendBuffer(); - for (int ch = 0; ch < a->channels(); ++ch) - memset(dst[ch], 0, sizeof(float) * segmentSize); - } - - for (iAudioOutput i = ol->begin(); i != ol->end(); ++i) - (*i)->processInit(frames); - int samplePos = _pos.frame(); - int offset = 0; // buffer offset in audio buffers - - if (isPlaying()) { - if (!freewheel()) - audioPrefetch->msgTick(); - - if (_bounce && _pos >= song->rPos()) { - _bounce = false; - write(sigFd, "F", 1); - return; - } - - // - // check for end of song - // - if ((curTickPos >= song->len()) - && !(song->record() - || _bounce - || song->loop())) { - //if(debugMsg) - // printf("Audio::process curTickPos >= song->len\n"); - - audioDevice->stopTransport(); - return; - } - - // - // check for loop end - // - if (state == PLAY && song->loop() && !_bounce && !extSyncFlag.value()) { - const Pos& loop = song->rPos(); - unsigned n = loop.frame() - samplePos - (3 * frames); - if (n < frames) { - // loop end in current cycle - unsigned lpos = song->lPos().frame(); - // adjust loop start so we get exact loop len - if (n > lpos) - n = 0; - state = LOOP1; - _loopFrame = lpos - n; - - // clear sustain - for (int i = 0; i < MIDI_PORTS; ++i) { - MidiPort* mp = &midiPorts[i]; - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - if (mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127) { - if (mp->device()!=NULL) { - //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch); - MidiPlayEvent ev(0, i, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); - // may cause problems, called from audio thread - mp->device()->putEvent(ev); - } - } - } - } - - //audioDevice->seekTransport(_loopFrame); - Pos lp(_loopFrame, false); - audioDevice->seekTransport(lp); - - -// printf(" process: seek to %d, end %d\n", _loopFrame, loop.frame()); - } - } - - - // p3.3.25 - if(extSyncFlag.value()) - { - nextTickPos = curTickPos + midiExtSyncTicks; - // Probably not good - interfere with midi thread. - midiExtSyncTicks = 0; - } - else - { - - Pos ppp(_pos); - ppp += frames; - nextTickPos = ppp.tick(); - } - } - // - // resync with audio interface - // - syncFrame = audioDevice->framePos(); - syncTime = curTime(); - frameOffset = syncFrame - samplePos; - - //printf("Audio::process calling process1:\n"); - - process1(samplePos, offset, frames); - for (iAudioOutput i = ol->begin(); i != ol->end(); ++i) - (*i)->processWrite(); - if (isPlaying()) { - _pos += frames; - curTickPos = nextTickPos; - } - } - -//--------------------------------------------------------- -// process1 -//--------------------------------------------------------- - -void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames) - { - if (midiSeqRunning) { - processMidi(); - } - //midiSeq->msgProcess(); - - // - // process not connected tracks - // to animate meter display - // - TrackList* tl = song->tracks(); - AudioTrack* track; - int channels; - for(ciTrack it = tl->begin(); it != tl->end(); ++it) - { - if((*it)->isMidiTrack()) - continue; - track = (AudioTrack*)(*it); - - // Added by T356. - // For audio track types, synths etc. which need some kind of non-audio - // (but possibly audio-affecting) processing always, even if their output path - // is ultimately unconnected. - // Example: A fluidsynth instance whose output path ultimately led to nowhere - // would not allow us to load a font. Since process() was driven by audio output, - // in this case there was nothing driving the process() function which responds to - // such gui commands. So I separated the events processing from process(), into this. - // It should be used for things like midi events, gui events etc. - things which need to - // be done BEFORE all the AudioOutput::process() are called below. That does NOT include - // audio processing, because THAT is done at the very end of this routine. - // This will also reset the track's processed flag. - track->preProcessAlways(); - - // Removed by T356 - /* - if (track->noOutRoute() && !track->noInRoute() && - track->type() != Track::AUDIO_AUX && track->type() != Track::AUDIO_OUTPUT) { - channels = track->channels(); - float* buffer[channels]; - float data[frames * channels]; - for (int i = 0; i < channels; ++i) - buffer[i] = data + i * frames; - track->copyData(samplePos, channels, frames, buffer); - } - */ - - } - // Pre-process the metronome. - ((AudioTrack*)metronome)->preProcessAlways(); - - OutputList* ol = song->outputs(); - for (ciAudioOutput i = ol->begin(); i != ol->end(); ++i) - (*i)->process(samplePos, offset, frames); - - // Removed by T356 - /* - AuxList* auxl = song->auxs(); - for (ciAudioAux ia = auxl->begin(); ia != auxl->end(); ++ia) { - track = (AudioTrack*)(*ia); - if (track->noOutRoute()) { - channels = track->channels(); - float* buffer[channels]; - float data[frames * channels]; - for (int i = 0; i < channels; ++i) - buffer[i] = data + i * frames; - track->copyData(samplePos, channels, frames, buffer); - } - } - */ - - // Added by T356. - // Were ANY tracks unprocessed as a result of processing all the AudioOutputs, above? - // Not just unconnected ones, as previously done, but ones whose output path ultimately leads nowhere. - // Those tracks were missed, until this fix. - // Do them now. This will animate meters, and 'quietly' process some audio which needs to be done - - // for example synths really need to be processed, 'quietly' or not, otherwise the next time - // processing is 'turned on', if there was a backlog of events while it was off, then they all happen at once. - for(ciTrack it = tl->begin(); it != tl->end(); ++it) - { - if((*it)->isMidiTrack()) - continue; - track = (AudioTrack*)(*it); - // Ignore unprocessed tracks which have an output route, because they will be processed by - // whatever track(s) they are routed to. - if(!track->processed() && track->noOutRoute() && (track->type() != Track::AUDIO_OUTPUT)) - { - channels = track->channels(); - // Just a dummy buffer. - float* buffer[channels]; - float data[frames * channels]; - for (int i = 0; i < channels; ++i) - buffer[i] = data + i * frames; - //printf("Audio::process1 calling track->copyData for track:%s\n", track->name().toLatin1()); - - // p3.3.38 - //track->copyData(samplePos, channels, frames, buffer); - track->copyData(samplePos, channels, -1, -1, frames, buffer); - } - } - } - -//--------------------------------------------------------- -// processMsg -//--------------------------------------------------------- - -void Audio::processMsg(AudioMsg* msg) - { - switch(msg->id) { - case AUDIO_RECORD: - msg->snode->setRecordFlag2(msg->ival); - break; - case AUDIO_ROUTEADD: - addRoute(msg->sroute, msg->droute); - break; - case AUDIO_ROUTEREMOVE: - removeRoute(msg->sroute, msg->droute); - break; - case AUDIO_REMOVEROUTES: // p3.3.55 - removeAllRoutes(msg->sroute, msg->droute); - break; - case AUDIO_VOL: - msg->snode->setVolume(msg->dval); - break; - case AUDIO_PAN: - msg->snode->setPan(msg->dval); - break; - case SEQM_SET_AUX: - msg->snode->setAuxSend(msg->ival, msg->dval); - break; - case AUDIO_SET_PREFADER: - msg->snode->setPrefader(msg->ival); - break; - case AUDIO_SET_CHANNELS: - msg->snode->setChannels(msg->ival); - break; - case AUDIO_ADDPLUGIN: - msg->snode->addPlugin(msg->plugin, msg->ival); - break; - case AUDIO_SET_PLUGIN_CTRL_VAL: - //msg->plugin->track()->setPluginCtrlVal(msg->ival, msg->dval); - // p3.3.43 - msg->snode->setPluginCtrlVal(msg->ival, msg->dval); - break; - case AUDIO_SWAP_CONTROLLER_IDX: - msg->snode->swapControllerIDX(msg->a, msg->b); - break; - case AUDIO_CLEAR_CONTROLLER_EVENTS: - msg->snode->clearControllerEvents(msg->ival); - break; - case AUDIO_SEEK_PREV_AC_EVENT: - msg->snode->seekPrevACEvent(msg->ival); - break; - case AUDIO_SEEK_NEXT_AC_EVENT: - msg->snode->seekNextACEvent(msg->ival); - break; - case AUDIO_ERASE_AC_EVENT: - msg->snode->eraseACEvent(msg->ival, msg->a); - break; - case AUDIO_ERASE_RANGE_AC_EVENTS: - msg->snode->eraseRangeACEvents(msg->ival, msg->a, msg->b); - break; - case AUDIO_ADD_AC_EVENT: - msg->snode->addACEvent(msg->ival, msg->a, msg->dval); - break; - case AUDIO_SET_SOLO: - msg->track->setSolo((bool)msg->ival); - break; - - case AUDIO_SET_SEND_METRONOME: - msg->snode->setSendMetronome((bool)msg->ival); - break; - - case AUDIO_SET_SEG_SIZE: - segmentSize = msg->ival; - sampleRate = msg->iival; -#if 0 //TODO - audioOutput.segmentSizeChanged(); - for (int i = 0; i < mixerGroups; ++i) - audioGroups[i].segmentSizeChanged(); - for (iSynthI ii = synthiInstances.begin(); ii != synthiInstances.end();++ii) - (*ii)->segmentSizeChanged(); -#endif - break; - - case SEQM_RESET_DEVICES: - for (int i = 0; i < MIDI_PORTS; ++i) - midiPorts[i].instrument()->reset(i, song->mtype()); - break; - case SEQM_INIT_DEVICES: - initDevices(); - break; - case SEQM_MIDI_LOCAL_OFF: - sendLocalOff(); - break; - case SEQM_PANIC: - panic(); - break; - case SEQM_PLAY_MIDI_EVENT: - { - MidiPlayEvent* ev = (MidiPlayEvent*)(msg->p1); - midiPorts[ev->port()].sendEvent(*ev); - // Record?? - } - break; - case SEQM_SET_HW_CTRL_STATE: - { - MidiPort* port = (MidiPort*)(msg->p1); - port->setHwCtrlState(msg->a, msg->b, msg->c); - } - break; - case SEQM_SET_HW_CTRL_STATES: - { - MidiPort* port = (MidiPort*)(msg->p1); - port->setHwCtrlStates(msg->a, msg->b, msg->c, msg->ival); - } - break; - case SEQM_SCAN_ALSA_MIDI_PORTS: - alsaScanMidiPorts(); - break; - case MIDI_SHOW_INSTR_GUI: - midiSeq->msgUpdatePollFd(); - break; - case SEQM_ADD_TEMPO: - case SEQM_REMOVE_TEMPO: - case SEQM_SET_GLOBAL_TEMPO: - case SEQM_SET_TEMPO: - song->processMsg(msg); - if (isPlaying()) { - if (!checkAudioDevice()) return; - _pos.setTick(curTickPos); - int samplePos = _pos.frame(); - syncFrame = audioDevice->framePos(); - syncTime = curTime(); - frameOffset = syncFrame - samplePos; - } - break; - case SEQM_ADD_TRACK: - case SEQM_REMOVE_TRACK: - case SEQM_CHANGE_TRACK: - case SEQM_ADD_PART: - case SEQM_REMOVE_PART: - case SEQM_CHANGE_PART: - case SEQM_SET_TRACK_OUT_CHAN: - case SEQM_SET_TRACK_OUT_PORT: - case SEQM_REMAP_PORT_DRUM_CTL_EVS: - case SEQM_CHANGE_ALL_PORT_DRUM_CTL_EVS: - midiSeq->sendMsg(msg); - break; - - case SEQM_IDLE: - idle = msg->a; - midiSeq->sendMsg(msg); - break; - - default: - song->processMsg(msg); - break; - } - } - -//--------------------------------------------------------- -// seek -// - called before start play -// - initiated from gui -//--------------------------------------------------------- - -void Audio::seek(const Pos& p) - { - if (_pos == p) { - if(debugMsg) - printf("Audio::seek already there\n"); - return; - } - - // p3.3.23 - //printf("Audio::seek frame:%d\n", p.frame()); - _pos = p; - if (!checkAudioDevice()) return; - syncFrame = audioDevice->framePos(); - frameOffset = syncFrame - _pos.frame(); - curTickPos = _pos.tick(); - - midiSeq->msgSeek(); // handle stuck notes and set - // controller for new position - - // p3.3.31 - // Don't send if external sync is on. The master, and our sync routing system will take care of that. - if(!extSyncFlag.value()) - { - - for(int port = 0; port < MIDI_PORTS; ++port) - { - MidiPort* mp = &midiPorts[port]; - MidiDevice* dev = mp->device(); - //if(!dev || !mp->syncInfo().MCOut()) - if(!dev || !mp->syncInfo().MRTOut()) - continue; - - // Added by T356: Shall we check for device write open flag to see if it's ok to send?... - // This means obey what the user has chosen for read/write in the midi port config dialog, - // which already takes into account whether the device is writable or not. - //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) - //if(!(dev->openFlags() & 1)) - // continue; - - //int port = dev->midiPort(); - - // By checking for no port here (-1), (and out of bounds), it means - // the device must be assigned to a port for these MMC commands to be sent. - // Without this check, interesting sync things can be done by the user without ever - // assigning any devices to ports ! - //if(port < 0 || port > MIDI_PORTS) - //if(port < -1 || port > MIDI_PORTS) - // continue; - - int beat = (curTickPos * 4) / config.division; - - bool isPlaying=false; - if(state == PLAY) - isPlaying = true; - - mp->sendStop(); - mp->sendSongpos(beat); - if(isPlaying) - mp->sendContinue(); - } - } - - /* - if(genMCSync) - { - for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) - { - MidiDevice* dev = (*imd); - if(!dev->syncInfo().MCOut()) - continue; - - // Added by T356: Shall we check for device write open flag to see if it's ok to send?... - // This means obey what the user has chosen for read/write in the midi port config dialog, - // which already takes into account whether the device is writable or not. - //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) - //if(!(dev->openFlags() & 1)) - // continue; - - int port = dev->midiPort(); - - // By checking for no port here (-1), (and out of bounds), it means - // the device must be assigned to a port for these MMC commands to be sent. - // Without this check, interesting sync things can be done by the user without ever - // assigning any devices to ports ! - //if(port < 0 || port > MIDI_PORTS) - if(port < -1 || port > MIDI_PORTS) - continue; - - int beat = (curTickPos * 4) / config.division; - - bool isPlaying=false; - if(state == PLAY) - isPlaying = true; - - if(port == -1) - // Send straight to the device... Copied from MidiPort. - { - MidiPlayEvent event(0, 0, 0, ME_STOP, 0, 0); - dev->putEvent(event); - - event.setType(ME_SONGPOS); - event.setA(beat); - dev->putEvent(event); - - if(isPlaying) - { - event.setType(ME_CONTINUE); - event.setA(0); - dev->putEvent(event); - } - } - else - // Go through the port... - { - MidiPort* mp = &midiPorts[port]; - - mp->sendStop(); - mp->sendSongpos(beat); - if(isPlaying) - mp->sendContinue(); - } - } - } - */ - - //loopPassed = true; // for record loop mode - if (state != LOOP2 && !freewheel()) - { - // Changed by T356 08/17/08. We need to force prefetch to update, - // to ensure the most recent data. Things can happen to a part - // before play is pressed - such as part muting, part moving etc. - // Without a force, the wrong data was being played. - //audioPrefetch->msgSeek(_pos.frame()); - audioPrefetch->msgSeek(_pos.frame(), true); - } - - write(sigFd, "G", 1); // signal seek to gui - } - -//--------------------------------------------------------- -// writeTick -// called from audio prefetch thread context -// write another buffer to soundfile -//--------------------------------------------------------- - -void Audio::writeTick() - { - AudioOutput* ao = song->bounceOutput; - if(ao && song->outputs()->find(ao) != song->outputs()->end()) - { - if(ao->recordFlag()) - ao->record(); - } - WaveTrackList* tl = song->waves(); - for (iWaveTrack t = tl->begin(); t != tl->end(); ++t) { - WaveTrack* track = *t; - if (track->recordFlag()) - track->record(); - } - } - -//--------------------------------------------------------- -// startRolling -//--------------------------------------------------------- - -void Audio::startRolling() - { - // Changed by Tim. p3.3.8 - //startRecordPos = _pos; - if(_loopCount == 0) - startRecordPos = _pos; - - if (song->record()) { - recording = true; - TrackList* tracks = song->tracks(); - for (iTrack i = tracks->begin(); i != tracks->end(); ++i) { - if ((*i)->isMidiTrack()) - continue; - if ((*i)->type() == Track::WAVE) - ((WaveTrack*)(*i))->resetMeter(); - } - } - state = PLAY; - write(sigFd, "1", 1); // Play - - // p3.3.31 - // Don't send if external sync is on. The master, and our sync routing system will take care of that. - if(!extSyncFlag.value()) - { - - // Changed by Tim. p3.3.6 - //if (genMMC) - // midiPorts[txSyncPort].sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); - //if (genMCSync) { - // if (curTickPos) - // midiPorts[txSyncPort].sendContinue(); - // else - // midiPorts[txSyncPort].sendStart(); - // } - for(int port = 0; port < MIDI_PORTS; ++port) - { - MidiPort* mp = &midiPorts[port]; - MidiDevice* dev = mp->device(); - if(!dev) - continue; - - // Shall we check open flags? - //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) - //if(!(dev->openFlags() & 1)) - // continue; - - MidiSyncInfo& si = mp->syncInfo(); - - //if(genMMC && si.MMCOut()) - if(si.MMCOut()) - //mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); - mp->sendMMCDeferredPlay(); - - //if(genMCSync && si.MCOut()) - //if(si.MCOut()) - if(si.MRTOut()) - { - if(curTickPos) - mp->sendContinue(); - else - mp->sendStart(); - } - } - } - - /* - for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) - { - MidiDevice* dev = (*imd); - - // Shall we check open flags? - //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) - //if(!(dev->openFlags() & 1)) - // continue; - - int port = dev->midiPort(); - - // Without this -1 check, interesting sync things can be done by the user without ever - // assigning any devices to ports ! - //if(port < 0 || port > MIDI_PORTS) - if(port < -1 || port > MIDI_PORTS) - continue; - - MidiSyncInfo& si = dev->syncInfo(); - - if(port == -1) - // Send straight to the device... Copied from MidiPort. - { - if(genMMC && si.MMCOut()) - { - MidiPlayEvent event(0, 0, ME_SYSEX, mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); - dev->putEvent(event); - } - - if(genMCSync && si.MCOut()) - { - if(curTickPos) - { - MidiPlayEvent event(0, 0, 0, ME_CONTINUE, 0, 0); - dev->putEvent(event); - } - else - { - MidiPlayEvent event(0, 0, 0, ME_START, 0, 0); - dev->putEvent(event); - } - } - } - else - // Go through the port... - { - MidiPort* mp = &midiPorts[port]; - - if(genMMC && si.MMCOut()) - mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); - - if(genMCSync && si.MCOut()) - { - if(curTickPos) - mp->sendContinue(); - else - mp->sendStart(); - } - } - } - */ - - if (precountEnableFlag - && song->click() - && !extSyncFlag.value() - && song->record()) { -#if 0 - state = PRECOUNT; - int z, n; - if (precountFromMastertrackFlag) - AL::sigmap.timesig(playTickPos, z, n); - else { - z = precountSigZ; - n = precountSigN; - } - clickno = z * preMeasures; - clicksMeasure = z; - ticksBeat = (division * 4)/n; -#endif - } - else { - // - // compute next midi metronome click position - // - int bar, beat; - unsigned tick; - AL::sigmap.tickValues(curTickPos, &bar, &beat, &tick); - if (tick) - beat += 1; - midiClick = AL::sigmap.bar2tick(bar, beat, 0); - } - - // reenable sustain - for (int i = 0; i < MIDI_PORTS; ++i) { - MidiPort* mp = &midiPorts[i]; - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - if (mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127) { - if(mp->device() != NULL) { - //printf("send enable sustain!!!!!!!! port %d ch %d\n", i,ch); - MidiPlayEvent ev(0, i, ch, ME_CONTROLLER, CTRL_SUSTAIN, 127); - - // may cause problems, called from audio thread - mp->device()->playEvents()->add(ev); - } - } - } - } - - //tempomap.clearExtTempoList(); - } - -//--------------------------------------------------------- -// stopRolling -//--------------------------------------------------------- - -void Audio::stopRolling() - { - // Added by Tim. p3.3.20 - //if(debugMsg) - // printf("Audio::stopRolling state %s\n", audioStates[state]); - - state = STOP; - midiSeq->msgStop(); - -#if 1 //TODO - //--------------------------------------------------- - // reset sustain - //--------------------------------------------------- - - - // clear sustain - for (int i = 0; i < MIDI_PORTS; ++i) { - MidiPort* mp = &midiPorts[i]; - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - if (mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127) { - if(mp->device()!=NULL) { - //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch); - MidiPlayEvent ev(0, i, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); - // may cause problems, called from audio thread - mp->device()->putEvent(ev); - } - } - } - } - -#endif - - // p3.3.31 - // Don't send if external sync is on. The master, and our sync routing system will take care of that. - if(!extSyncFlag.value()) - { - - // Changed by Tim. p3.3.6 - //MidiPort* syncPort = &midiPorts[txSyncPort]; - //if (genMMC) { - // unsigned char mmcPos[] = { - // 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, - // 0, 0, 0, 0, 0 - // }; - // int frame = tempomap.tick2frame(curTickPos); - // MTC mtc(double(frame) / double(sampleRate)); - // mmcPos[6] = mtc.h() | (mtcType << 5); - // mmcPos[7] = mtc.m(); - // mmcPos[8] = mtc.s(); - // mmcPos[9] = mtc.f(); - // mmcPos[10] = mtc.sf(); - // syncPort->sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); - // syncPort->sendSysex(mmcPos, sizeof(mmcPos)); - // } - //if (genMCSync) { // Midi Clock - // send STOP and - // "set song position pointer" - // syncPort->sendStop(); - // syncPort->sendSongpos(curTickPos * 4 / config.division); - // } - for(int port = 0; port < MIDI_PORTS; ++port) - { - MidiPort* mp = &midiPorts[port]; - MidiDevice* dev = mp->device(); - if(!dev) - continue; - - // Shall we check open flags? - //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) - //if(!(dev->openFlags() & 1)) - // continue; - - MidiSyncInfo& si = mp->syncInfo(); - - //if(genMMC && si.MMCOut()) - if(si.MMCOut()) - { - //unsigned char mmcPos[] = { - // 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, - // 0, 0, 0, 0, 0 - // }; - - // p3.3.31 - /* - int frame = tempomap.tick2frame(curTickPos); - MTC mtc(double(frame) / double(sampleRate)); - */ - - //mmcPos[6] = mtc.h() | (mtcType << 5); - //mmcPos[7] = mtc.m(); - //mmcPos[8] = mtc.s(); - //mmcPos[9] = mtc.f(); - //mmcPos[10] = mtc.sf(); - - //mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); - mp->sendMMCStop(); - //mp->sendSysex(mmcPos, sizeof(mmcPos)); - - // p3.3.31 - // Added check of option send continue not start. - // Hmm, is this required? Seems to make other devices unhappy. - /* - if(!si.sendContNotStart()) - mp->sendMMCLocate(mtc.h() | (mtcType << 5), - mtc.m(), mtc.s(), mtc.f(), mtc.sf()); - */ - - } - - //if(genMCSync && si.MCOut()) // Midi Clock - //if(si.MCOut()) // Midi Clock - if(si.MRTOut()) // - { - // send STOP and - // "set song position pointer" - mp->sendStop(); - - // p3.3.31 - // Added check of option send continue not start. - // Hmm, is this required? Seems to make other devices unhappy. - /* - if(!si.sendContNotStart()) - mp->sendSongpos(curTickPos * 4 / config.division); - */ - - } - } - } - - /* - for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) - { - MidiDevice* dev = (*imd); - - // Shall we check open flags? - //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1)) - //if(!(dev->openFlags() & 1)) - // continue; - - int port = dev->midiPort(); - - // Without this -1 check, interesting sync things can be done by the user without ever - // assigning any devices to ports ! - //if(port < 0 || port > MIDI_PORTS) - if(port < -1 || port > MIDI_PORTS) - continue; - - MidiSyncInfo& si = dev->syncInfo(); - - MidiPort* mp = 0; - if(port != -1) - mp = &midiPorts[port]; - - if(genMMC && si.MMCOut()) - { - unsigned char mmcPos[] = { - 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, - 0, 0, 0, 0, 0 - }; - int frame = tempomap.tick2frame(curTickPos); - MTC mtc(double(frame) / double(sampleRate)); - mmcPos[6] = mtc.h() | (mtcType << 5); - mmcPos[7] = mtc.m(); - mmcPos[8] = mtc.s(); - mmcPos[9] = mtc.f(); - mmcPos[10] = mtc.sf(); - - if(mp) - // Go through the port... - { - mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); - mp->sendSysex(mmcPos, sizeof(mmcPos)); - } - else - // Send straight to the device... Copied from MidiPort. - { - MidiPlayEvent event(0, 0, ME_SYSEX, mmcStopMsg, sizeof(mmcStopMsg)); - dev->putEvent(event); - - event.setData(mmcPos, sizeof(mmcPos)); - dev->putEvent(event); - } - } - - if(genMCSync && si.MCOut()) // Midi Clock - { - // send STOP and - // "set song position pointer" - if(mp) - // Go through the port... - { - mp->sendStop(); - mp->sendSongpos(curTickPos * 4 / config.division); - } - else - // Send straight to the device... Copied from MidiPort. - { - MidiPlayEvent event(0, 0, 0, ME_STOP, 0, 0); - dev->putEvent(event); - event.setType(ME_SONGPOS); - event.setA(curTickPos * 4 / config.division); - dev->putEvent(event); - } - } - } - */ - - WaveTrackList* tracks = song->waves(); - for (iWaveTrack i = tracks->begin(); i != tracks->end(); ++i) { - WaveTrack* track = *i; - track->resetMeter(); - } - recording = false; - endRecordPos = _pos; - write(sigFd, "0", 1); // STOP - } - -//--------------------------------------------------------- -// recordStop -// execution environment: gui thread -//--------------------------------------------------------- - -void Audio::recordStop() - { - audio->msgIdle(true); // gain access to all data structures - - song->startUndo(); - WaveTrackList* wl = song->waves(); - - for (iWaveTrack it = wl->begin(); it != wl->end(); ++it) { - WaveTrack* track = *it; - if (track->recordFlag() || song->bounceTrack == track) { - song->cmdAddRecordedWave(track, startRecordPos, endRecordPos); - // The track's _recFile pointer may have been kept and turned - // into a SndFileR and added to a new part. - // Or _recFile may have been discarded (no new recorded part created). - // Regardless, we are done with the pointer itself. Set to zero so - // song->setRecordFlag knows about it... - - track->setRecFile(0); // flush out the old file - song->setRecordFlag(track, false); // - //track->setRecordFlag1(true); // and re-arm the track here - //song->setRecordFlag(track, true); // here - } - } - MidiTrackList* ml = song->midis(); - for (iMidiTrack it = ml->begin(); it != ml->end(); ++it) { - MidiTrack* mt = *it; - MPEventList* mpel = mt->mpevents(); - EventList* el = mt->events(); - - //--------------------------------------------------- - // resolve NoteOff events, Controller etc. - //--------------------------------------------------- - - //buildMidiEventList(el, mpel, mt, config.division, true); - // Do SysexMeta. Do loops. - buildMidiEventList(el, mpel, mt, config.division, true, true); - song->cmdAddRecordedEvents(mt, el, startRecordPos.tick()); - el->clear(); - mpel->clear(); - } - - // - // bounce to file operates on the only - // selected output port - // - - AudioOutput* ao = song->bounceOutput; - if(ao && song->outputs()->find(ao) != song->outputs()->end()) - { - if(ao->recordFlag()) - { - song->bounceOutput = 0; - SndFile* sf = ao->recFile(); - if (sf) - delete sf; // close - ao->setRecFile(0); - ao->setRecordFlag1(false); - msgSetRecord(ao, false); - } - } - audio->msgIdle(false); - song->endUndo(0); - song->setRecord(false); - } - -//--------------------------------------------------------- -// curFrame -// extrapolates current play frame on syncTime/syncFrame -//--------------------------------------------------------- - -unsigned int Audio::curFrame() const - { - return lrint((curTime() - syncTime) * sampleRate) + syncFrame; - } - -//--------------------------------------------------------- -// timestamp -//--------------------------------------------------------- - -int Audio::timestamp() const - { - int t = curFrame() - frameOffset; - return t; - } - -//--------------------------------------------------------- -// sendMsgToGui -//--------------------------------------------------------- - -void Audio::sendMsgToGui(char c) - { - write(sigFd, &c, 1); - } - |