From d64ded05c5d77cdec45a099d589566edfe98be50 Mon Sep 17 00:00:00 2001 From: Werner Schweer Date: Mon, 23 Oct 2006 18:28:50 +0000 Subject: updates --- muse/ChangeLog | 2 + muse/NEWS | 1 + muse/muse/audio.cpp | 43 +- muse/muse/audio.h | 8 +- muse/muse/audiowriteback.cpp | 2 +- muse/muse/driver/audiodev.h | 1 - muse/muse/driver/dummyaudio.cpp | 7 +- muse/muse/driver/jack.cpp | 118 ++- muse/muse/driver/jackaudio.h | 16 +- muse/muse/midiinport.cpp | 2 +- muse/muse/midioutport.cpp | 15 +- muse/muse/midiseq.cpp | 3 +- muse/muse/miditrack.cpp | 10 +- muse/muse/sync.cpp | 4 +- muse/muse/synth.cpp | 4 +- muse/muse/ticksynth.cpp | 3 +- muse/synti/mus/mus.cpp | 1 + muse/synti/organ/organgui.ui | 1647 +++++++++++++++++++-------------------- 18 files changed, 938 insertions(+), 949 deletions(-) diff --git a/muse/ChangeLog b/muse/ChangeLog index b3b4fba2..3056feb6 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,5 @@ +23.10 (ws) + - simple jack midi output now works 20.10 (ws) - add first support for jack midi - jack autostart diff --git a/muse/NEWS b/muse/NEWS index 80dfb2e4..a0e50418 100644 --- a/muse/NEWS +++ b/muse/NEWS @@ -3,6 +3,7 @@ MusE 1.0: - new "project" paradigma - "auto fill" parts - DSSI support + - JACK midi support - controller automation in arranger - audio metronome - support for VST plugins diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index ede753f1..b1185cf8 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -109,9 +109,6 @@ Audio::Audio() ticksBeat = 0; syncTime = 0.0; - syncFrame = 0; - frameOffset = 0; - state = STOP; lmark = 0; // left loop position rmark = 0; // right loop position @@ -163,9 +160,6 @@ bool Audio::start() ticksBeat = 0; syncTime = 0.0; - syncFrame = 0; - frameOffset = 0; - msg = 0; _pos.setFrame(~0); // make sure seek is not optimized away @@ -184,7 +178,7 @@ bool Audio::start() for (iTrack i = tl->begin(); i != tl->end(); ++i) (*i)->activate1(); seek(song->cpos()); - process(segmentSize); // warm up caches; audio must be stopped + process(segmentSize, STOP); // warm up caches; audio must be stopped audioDriver->start(realTimePriority); } else { @@ -309,7 +303,7 @@ printf("JACK: shutdown callback\n"); // of size "frames" //--------------------------------------------------------- -void Audio::process(unsigned frames) +void Audio::process(unsigned frames, int jackState) { // printf("process %d\n", frames); extern int watchAudio; @@ -325,7 +319,6 @@ void Audio::process(unsigned frames) } } - int jackState = audioDriver->getState(); if (jackState != state) { // printf("process %s %s\n", audioStates[state], audioStates[jackState]); if (state == START_PLAY && jackState == PLAY) { @@ -428,12 +421,9 @@ void Audio::process(unsigned frames) // // resync with audio interface - // syncFrame - free running JACK frame counter // syncTime - corresponding wall clock time // - syncFrame = audioDriver->framePos(); syncTime = curTime(); - frameOffset = syncFrame - framePos; // // compute current controller values @@ -464,6 +454,8 @@ void Audio::process(unsigned frames) for (iMidiOutPort i = mol->begin(); i != mol->end(); ++i) audioDriver->startMidiCycle((*i)->jackPort(0)); + processMidi(frames); + GroupList* gl = song->groups(); SynthIList* sl = song->syntis(); InputList* il = song->inputs(); @@ -578,10 +570,8 @@ void Audio::processMsg() song->processMsg(msg); if (isPlaying()) { _pos.setTick(_curTickPos); - int framePos = _pos.frame(); - syncFrame = audioDriver->framePos(); +// int framePos = _pos.frame(); syncTime = curTime(); - frameOffset = syncFrame - framePos; } break; @@ -603,8 +593,6 @@ void Audio::processMsg() void Audio::seek(const Pos& p) { _pos.setFrame(p.frame()); - syncFrame = audioDriver->framePos(); - frameOffset = syncFrame - _pos.frame(); _curTickPos = _pos.tick(); _nextTickPos = _curTickPos; updateController = true; @@ -692,26 +680,6 @@ void Audio::stopRolling() seek(_pos); } -//--------------------------------------------------------- -// curFrame -// extrapolates current play frame on syncTime/syncFrame -//--------------------------------------------------------- - -unsigned int Audio::curFrame() const - { - return audioDriver->framePos(); - } - -//--------------------------------------------------------- -// timestamp -// timestamp has only meaning when rolling -//--------------------------------------------------------- - -int Audio::timestamp() const - { - return (state == PLAY) ? (audioDriver->framePos() - frameOffset) : 0; - } - //--------------------------------------------------------- // sendMsgToGui //--------------------------------------------------------- @@ -720,3 +688,4 @@ void Audio::sendMsgToGui(char c) { write(sigFd, &c, 1); } + diff --git a/muse/muse/audio.h b/muse/muse/audio.h index 985466dd..6934f0db 100644 --- a/muse/muse/audio.h +++ b/muse/muse/audio.h @@ -171,8 +171,7 @@ class Audio { int ticksBeat; double syncTime; // wall clock at last sync point - unsigned syncFrame; // corresponding frame no. to syncTime - unsigned frameOffset; // offset to free running hw frame counter +// unsigned syncFrame; // corresponding frame no. to syncTime State state; bool updateController; @@ -197,7 +196,7 @@ class Audio { Pos startRecordPos; Pos endRecordPos; - void process(unsigned frames); + void process(unsigned frames, int jackState); void processMidi(unsigned frames); bool sync(int state, unsigned frame); void shutdown(); @@ -265,11 +264,8 @@ class Audio { int curTickPos() const { return _curTickPos; } int nextTickPos() const { return _nextTickPos; } - int timestamp() const; - unsigned curFrame() const; bool freewheel() const { return _freewheel; } void setFreewheel(bool val); - int getFrameOffset() const { return frameOffset; } void initDevices(); void sendMsgToGui(char c); diff --git a/muse/muse/audiowriteback.cpp b/muse/muse/audiowriteback.cpp index 0b54e253..87b8f72f 100644 --- a/muse/muse/audiowriteback.cpp +++ b/muse/muse/audiowriteback.cpp @@ -62,7 +62,7 @@ void AudioWriteback::start(int priority) // processMsg //--------------------------------------------------------- -void AudioWriteback::processMsg1(const void* m) +void AudioWriteback::processMsg1(const void*) { while (counter) { q_atomic_decrement(&counter); diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h index 5196375c..0494116f 100644 --- a/muse/muse/driver/audiodev.h +++ b/muse/muse/driver/audiodev.h @@ -41,7 +41,6 @@ class AudioDriver : public Driver { virtual void registerClient() = 0; virtual Port registerOutPort(const QString& name, bool midi) = 0; virtual Port registerInPort(const QString& name, bool midi) = 0; - virtual int getState() = 0; virtual unsigned getCurFrame() = 0; virtual int realtimePriority() const = 0; // return zero if not realtime virtual void startTransport() = 0; diff --git a/muse/muse/driver/dummyaudio.cpp b/muse/muse/driver/dummyaudio.cpp index a55a69bb..7550cc61 100644 --- a/muse/muse/driver/dummyaudio.cpp +++ b/muse/muse/driver/dummyaudio.cpp @@ -35,12 +35,12 @@ static double startTime; class DummyAudio : public AudioDriver { pthread_t dummyThread; float buffer[dummyFrames]; - int state; std::vector oPorts; std::vector iPorts; int realTimePriority; public: + int state; bool seekflag; unsigned pos; @@ -126,7 +126,6 @@ class DummyAudio : public AudioDriver { else return QString(iPorts[long(p)-3000]); } - virtual int getState() { return state; } virtual unsigned getCurFrame() { return pos; } virtual int realtimePriority() const { return 40; } virtual void startTransport() { @@ -234,7 +233,7 @@ static void* dummyLoop(void*) for (;;) { if (audioState == AUDIO_RUNNING) - audio->process(segmentSize); + audio->process(segmentSize, dummyAudio->state); else if (audioState == AUDIO_START1) audioState = AUDIO_START2; usleep(dummyFrames*1000000/AL::sampleRate); @@ -242,7 +241,7 @@ static void* dummyLoop(void*) audio->sync(Audio::STOP, dummyAudio->pos); dummyAudio->seekflag = false; } - if (dummyAudio->getState() == Audio::PLAY) { + if (dummyAudio->state == Audio::PLAY) { dummyAudio->pos += dummyFrames; } } diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp index 56d78de5..e939046d 100644 --- a/muse/muse/driver/jack.cpp +++ b/muse/muse/driver/jack.cpp @@ -86,9 +86,19 @@ static void timebase_callback(jack_transport_state_t /* state */, static int processAudio(jack_nframes_t frames, void*) { +#if 0 + unsigned t1 = jackAudio->frameTime(); + unsigned t2 = jackAudio->lastFrameTime(); + unsigned t3 = jackAudio->framesSinceCyleStart(); + unsigned t4 = jackAudio->getCurFrame(); + +printf("cycle %8d %8d %8d %08d\n", t1, t2, t3, t4); +#endif + + int jackState = jackAudio->getTransportState(); segmentSize = frames; if (audioState == AUDIO_RUNNING) - audio->process((unsigned long)frames); + audio->process((unsigned long)frames, jackState); else if (audioState == AUDIO_STOP) { if (debugMsg) puts("jack calling when audio is stopped!\n"); @@ -98,6 +108,32 @@ static int processAudio(jack_nframes_t frames, void*) return 0; } +//--------------------------------------------------------- +// getTransportState +//--------------------------------------------------------- + +int JackAudio::getTransportState() + { + int jackState; + transportState = jack_transport_query(_client, &pos); + switch (jackAudio->transportState) { + case JackTransportStopped: + jackState = Audio::STOP; + break; + case JackTransportLooping: + case JackTransportRolling: + jackState = Audio::PLAY; + break; + case JackTransportStarting: + jackState = Audio::START_PLAY; + break; + default: + jackState = Audio::STOP; + break; + } + return jackState; + } + //--------------------------------------------------------- // processSync // return TRUE (non-zero) when ready to roll. @@ -473,6 +509,10 @@ Port JackAudio::registerOutPort(const QString& name, bool midi) const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; void* p = jack_port_register(_client, name.toLatin1().data(), type, JackPortIsOutput, 0); // printf("JACK: registerOutPort<%s>: <%s> %p\n", type, name.toLatin1().data(), p); + if (midi) { + jack_nframes_t nframes = jack_get_buffer_size(_client); + jack_midi_reset_new_port(jack_port_get_buffer((jack_port_t*)p, nframes), nframes); + } return p; } @@ -572,15 +612,6 @@ void JackAudio::stop() fprintf (stderr, "JACK: cannot deactivate client\n"); } -//--------------------------------------------------------- -// framePos -//--------------------------------------------------------- - -unsigned JackAudio::framePos() const - { - return _client ? jack_frame_time(_client) : 0; - } - //--------------------------------------------------------- // outputPorts //--------------------------------------------------------- @@ -651,23 +682,6 @@ void JackAudio::unregisterPort(Port p) } } -//--------------------------------------------------------- -// getState -//--------------------------------------------------------- - -int JackAudio::getState() - { - transportState = jack_transport_query(_client, &pos); - switch (transportState) { - case JackTransportStopped: return Audio::STOP; - case JackTransportLooping: - case JackTransportRolling: return Audio::PLAY; - case JackTransportStarting: return Audio::START_PLAY; - default: - return Audio::STOP; - } - } - //--------------------------------------------------------- // setFreewheel //--------------------------------------------------------- @@ -804,16 +818,48 @@ void JackAudio::putEvent(Port port, const MidiEvent& e) printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().data()); e.dump(); } - void* pb = jack_port_get_buffer((jack_port_t*)port, segmentSize); - int pos = 0; - unsigned char* p = jack_midi_event_reserve(pb, pos, 3, segmentSize); - if (p == 0) { - fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); - return; + void* pb = jack_port_get_buffer((jack_port_t*)port, segmentSize); + unsigned ft; + if (transportState == JackTransportRolling) { + ft = e.time() - pos.frame; + if (pos.frame > e.time()) + ft = 0; + else if (ft >= segmentSize) + ft = segmentSize -1; + } + else + ft = 0; + + switch(e.type()) { + case ME_NOTEON: + case ME_NOTEOFF: + { + unsigned char* p = jack_midi_event_reserve(pb, ft, 3, segmentSize); + if (p == 0) { + fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); + return; + } + p[0] = e.type() | e.channel(); + p[1] = e.dataA(); + p[2] = e.dataB(); + } + break; + + case ME_POLYAFTER: + case ME_CONTROLLER: + case ME_PROGRAM: + case ME_AFTERTOUCH: + case ME_PITCHBEND: + case ME_SYSEX: + case ME_META: + case ME_SONGPOS: + case ME_CLOCK: + case ME_START: + case ME_CONTINUE: + case ME_STOP: + printf("JackMidi: event type %x not supported\n", e.type()); + break; } - p[0] = e.type() | e.channel(); - p[1] = e.dataA(); - p[2] = e.dataB(); } //--------------------------------------------------------- diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h index c4611ac6..e350ca0a 100644 --- a/muse/muse/driver/jackaudio.h +++ b/muse/muse/driver/jackaudio.h @@ -31,20 +31,20 @@ class JackAudio : public AudioDriver { jack_client_t* _client; - jack_transport_state_t transportState; jack_position_t pos; char jackRegisteredName[8]; + jack_transport_state_t transportState; public: JackAudio(jack_client_t* cl, char * jack_id_string); virtual ~JackAudio(); + + int getTransportState(); virtual bool init(); virtual void start(int); virtual bool restart(); virtual void stop (); virtual void zeroClientPtr() { _client = 0; } - virtual unsigned framePos() const; - virtual float* getBuffer(Port port, unsigned long nframes) { return (float*)jack_port_get_buffer((jack_port_t*)port, nframes); } @@ -67,13 +67,12 @@ class JackAudio : public AudioDriver { } virtual Port findPort(const QString& name); virtual QString portName(Port); - virtual int getState(); - virtual unsigned int getCurFrame() { return pos.frame; } virtual int realtimePriority() const; virtual void startTransport(); virtual void stopTransport(); virtual void seekTransport(unsigned frame); virtual void setFreewheel(bool f); + jack_transport_state_t transportQuery(jack_position_t* pos) { return jack_transport_query(_client, pos); } @@ -81,6 +80,13 @@ class JackAudio : public AudioDriver { virtual bool equal(Port a, Port b) { return a == b; } virtual void putEvent(Port, const MidiEvent&); virtual void startMidiCycle(Port); + virtual unsigned int getCurFrame() { return pos.frame; } + + virtual unsigned framePos() const { + return pos.frame + jack_frames_since_cycle_start(_client); + } + unsigned lastFrameTime() { return jack_last_frame_time(_client); } + unsigned framesSinceCyleStart() { return jack_frames_since_cycle_start(_client); } }; #endif diff --git a/muse/muse/midiinport.cpp b/muse/muse/midiinport.cpp index 2a67ea2e..25a2faee 100644 --- a/muse/muse/midiinport.cpp +++ b/muse/muse/midiinport.cpp @@ -94,7 +94,7 @@ void MidiInPort::eventReceived(snd_seq_event_t* ev) { MidiEvent event; event.setB(0); - event.setTime(audio->timestamp()); + event.setTime(audioDriver->framePos()); switch(ev->type) { case SND_SEQ_EVENT_NOTEON: diff --git a/muse/muse/midioutport.cpp b/muse/muse/midioutport.cpp index 3d96780f..9fadaa71 100644 --- a/muse/muse/midioutport.cpp +++ b/muse/muse/midioutport.cpp @@ -467,7 +467,7 @@ void MidiOutPort::process(unsigned from, unsigned to, const Pos& pos, unsigned f track->getEvents(from, to, 0, &el); int velo = 0; for (iMPEvent i = el.begin(); i != el.end(); ++i) { - MidiEvent ev = *i; + MidiEvent ev(*i); ev.setChannel(ch); _playEvents.insert(ev); if (ev.type() == ME_NOTEON) @@ -494,20 +494,17 @@ void MidiOutPort::process(unsigned from, unsigned to, const Pos& pos, unsigned f // route events to destination // - unsigned endFrame = pos.frame() + frames + audio->getFrameOffset(); + unsigned endFrame = pos.frame() + frames; iMPEvent is = _playEvents.begin(); iMPEvent ie = _playEvents.end(); for (_nextPlayEvent = is; _nextPlayEvent != ie; _nextPlayEvent++) { - if ((from != to) && (_nextPlayEvent->time() >= endFrame)) { - ++_nextPlayEvent; // ?? + if ((from != to) && (_nextPlayEvent->time() >= endFrame)) break; - } routeEvent(*_nextPlayEvent); } } - //--------------------------------------------------------- // setInstrument //--------------------------------------------------------- @@ -537,13 +534,13 @@ void MidiOutPort::routeEvent(const MidiEvent& event) for (iRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r) { switch (r->type) { case Route::MIDIPORT: - midiDriver->putEvent(alsaPort(0), *_nextPlayEvent); + midiDriver->putEvent(alsaPort(0), event); break; case Route::SYNTIPORT: - ((SynthI*)(r->track))->playEvents()->insert(*_nextPlayEvent); + ((SynthI*)(r->track))->playEvents()->insert(event); break; case Route::JACKMIDIPORT: - audioDriver->putEvent(jackPort(0), *_nextPlayEvent); + audioDriver->putEvent(jackPort(0), event); break; default: fprintf(stderr, "MidiOutPort::process(): invalid routetype\n"); diff --git a/muse/muse/midiseq.cpp b/muse/muse/midiseq.cpp index 892db5c6..47d70cb2 100644 --- a/muse/muse/midiseq.cpp +++ b/muse/muse/midiseq.cpp @@ -24,6 +24,7 @@ #include "midictrl.h" #include "audio.h" #include "driver/mididev.h" +#include "driver/audiodev.h" #ifdef __APPLE__ #include "driver/coretimer.h" @@ -516,7 +517,7 @@ void MidiSeq::processTimerTick() // miss this timer tick return; } - unsigned curFrame = audio->curFrame(); + unsigned curFrame = audioDriver->framePos(); /* if (!extSyncFlag.value()) { int curTick = AL::tempomap.frame2tick(curFrame); diff --git a/muse/muse/miditrack.cpp b/muse/muse/miditrack.cpp index da7b02cd..a249114c 100644 --- a/muse/muse/miditrack.cpp +++ b/muse/muse/miditrack.cpp @@ -524,7 +524,7 @@ void MidiTrack::getEvents(unsigned from, unsigned to, int, MPEventList* dst) if (ev.type() == Meta) // ignore meta events continue; unsigned tick = ev.tick() + offset; - unsigned frame = AL::tempomap.tick2frame(tick) + audio->getFrameOffset(); + unsigned frame = AL::tempomap.tick2frame(tick); if (ev.type() == Note) { if (dm) { if (dm->entry(dm->outmap(ev.pitch()))->mute) @@ -547,13 +547,13 @@ void MidiTrack::getEvents(unsigned from, unsigned to, int, MPEventList* dst) if (velo < 1) // no off event velo = 1; int elen = (ev.lenTick() * len)/100; - if (elen <= 0) // donī allow zero length + if (elen <= 0) // dont allow zero length elen = 1; int veloOff = ev.veloOff(); - unsigned eframe = AL::tempomap.tick2frame(tick+elen) + audio->getFrameOffset(); - dst->add(MidiEvent(frame, 0, 0x90, pitch, velo)); - dst->add(MidiEvent(eframe, 0, veloOff ? 0x80 : 0x90, pitch, veloOff)); + unsigned eframe = AL::tempomap.tick2frame(tick+elen); + dst->add(MidiEvent(frame, 0, ME_NOTEON, pitch, velo)); + dst->add(MidiEvent(eframe, 0, veloOff ? ME_NOTEOFF : ME_NOTEON, pitch, veloOff)); _meter[0] += velo/2; if (_meter[0] > 127.0f) _meter[0] = 127.0f; diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp index e0c1861b..98946a9b 100644 --- a/muse/muse/sync.cpp +++ b/muse/muse/sync.cpp @@ -409,7 +409,7 @@ void MidiSeq::realtimeSystemInput(int port, int c) if (!audio->isPlaying() /*state == IDLE*/) { //seek(0); audioDriver->seekTransport(0); - unsigned curFrame = audio->curFrame(); + unsigned curFrame = audioDriver->framePos(); recTick = recTick1 = recTick2 = 0; mclock1 = 0.0; mclock2 = 0.0; songtick1 = songtick2 = 0; @@ -427,7 +427,7 @@ void MidiSeq::realtimeSystemInput(int port, int c) if (debugSync) printf(" continue\n"); if (!audio->isPlaying() /*state == IDLE */) { - unsigned curFrame = audio->curFrame(); + unsigned curFrame = audioDriver->framePos(); recTick = AL::tempomap.frame2tick(curFrame); // don't think this will work... (ml) audio->msgPlay(true); } diff --git a/muse/muse/synth.cpp b/muse/muse/synth.cpp index 421e0a96..693ad92c 100644 --- a/muse/muse/synth.cpp +++ b/muse/muse/synth.cpp @@ -495,14 +495,12 @@ iMPEvent MessSynthIF::getData(MPEventList* el, iMPEvent i, unsigned pos, int por // seems to be negative when sequencer not running, still // working when entering notes from editor though. weird :-) (ml) - int frameOffset = audio->getFrameOffset(); int curPos = pos; int endPos = pos + n; if (ports >= channels()) { for (; i != el->end(); ++i) { - int frame = i->time() - frameOffset; - // printf("\t510: frame=%d endPos=%d curPos=%d pos=%d\n", frame, endPos, curPos, pos); + int frame = i->time(); if (frame >= endPos) break; if (frame > curPos) { diff --git a/muse/muse/ticksynth.cpp b/muse/muse/ticksynth.cpp index 1d9b0c4a..472cadc4 100644 --- a/muse/muse/ticksynth.cpp +++ b/muse/muse/ticksynth.cpp @@ -94,10 +94,9 @@ iMPEvent MetronomeSynthIF::getData(MPEventList* el, iMPEvent i, unsigned pos, in unsigned curPos = pos; unsigned endPos = pos + n; unsigned off = pos; - unsigned frameOffset = audio->getFrameOffset(); for (; i != el->end(); ++i) { - unsigned frame = i->time() - frameOffset; + unsigned frame = i->time(); if (frame >= endPos) break; if (frame > curPos) { diff --git a/muse/synti/mus/mus.cpp b/muse/synti/mus/mus.cpp index fbc59334..635bd53d 100644 --- a/muse/synti/mus/mus.cpp +++ b/muse/synti/mus/mus.cpp @@ -58,6 +58,7 @@ static int processAudio(jack_nframes_t nFrames, void*) void* midi = jack_port_get_buffer(inPort, nFrames); int n = jack_midi_port_get_info(midi, nFrames)->event_count; unsigned offset = 0; + for (int i = 0; i < n; ++i) { jack_midi_event_t event; jack_midi_event_get(&event, midi, i, nFrames); diff --git a/muse/synti/organ/organgui.ui b/muse/synti/organ/organgui.ui index aeea79b3..bfd9ee85 100644 --- a/muse/synti/organ/organgui.ui +++ b/muse/synti/organ/organgui.ui @@ -1,15 +1,12 @@ - - - OrganGuiBase 0 0 - 534 - 366 + 563 + 392 @@ -23,841 +20,819 @@ MusE: Organ - - - - 5 - 162 - 252 - 199 - + + + 9 - - - 7 - 7 - 0 - 0 - + + 6 - - Drawbars - - - - 6 - - - 2 - - - - - 16' - - - - - - - 4' - - - - - - - 2 2/3' - - - - - - - 2' - - - - - - - 5 1/3' - - - - - - - 8' - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - - 7 - 0 - 0 - 0 - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - 0 - - - -960 - - - - - - - 0 - - - -960 - - - 10 - - - - - - - 0 - - - -960 - - - 10 - - - - - - - 0 - - - -960 - - - 10 - - - - - - - 0 - - - -960 - - - 10 - - - - - - - 0 - - - -960 - - - 10 - - - - - - - - - 263 - 5 - 266 - 151 - - - - - 7 - 7 - 0 - 0 - - - - Envelope Lo - - - Qt::AlignLeading - - - - 11 - - - 2 - - - - - Attack - - - - - - - Decay - - - - - - - Sustain - - - - - - - Release - - - - - - - - 7 - 0 - 0 - 0 - - - - - 80 - 0 - - - - 500 - - - 1 - - - Qt::Horizontal - - - 50 - - - - - - - 5000 - - - 1 - - - Qt::Horizontal - - - 500 - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - 500 - - - 1 - - - Qt::Horizontal - - - 50 - - - - - - - - 1 - 0 - 0 - 0 - - - - ms - - - 500 - - - - - - - - 1 - 0 - 0 - 0 - - - - ms - - - 5000 - - - - - - - - 1 - 0 - 0 - 0 - - - - cB - - - 0 - - - -960 - - - 0 - - - - - - - - 1 - 0 - 0 - 0 - - - - ms - - - 500 - - - - - - - - - 0 - - - 6 - - - - - - 7 - 5 - 0 - 0 - - - - - - 48 - 50 - false - false - false - false - - - - O-1 - - - Qt::AlignCenter - - - - - - - - 7 - 7 - 0 - 0 - - - - Oscillator - - - - 11 - - - 2 - - - - - - 5 - 1 - 0 - 0 - - - - Brass - - - - - - - - 5 - 1 - 0 - 0 - - - - Reed - - - - - - - - 5 - 1 - 0 - 0 - - - - Flute - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Velocity - - - - - - - - - - - - 263 - 162 - 266 - 199 - - - - - 7 - 7 - 0 - 0 - - - - Envelope Hi - - - - 8 - - - 6 - - - - - 500 - - - 1 - - - Qt::Horizontal - - - 50 - - - - - - - Sustain - - - - - - - Release - - - - - - - - 5 - 0 - 0 - 0 - - - - ms - - - 500 - - - - - - - - 5 - 0 - 0 - 0 - - - - cB - - - 0 - - - -960 - - - - - - - - 5 - 0 - 0 - 0 - - - - ms - - - 5000 - - - - - - - - 7 - 0 - 0 - 0 - - - - 500 - - - 1 - - - Qt::Horizontal - - - 50 - - - - - - - - 5 - 0 - 0 - 0 - - - - ms - - - 500 - - - - - - - 5000 - - - 1 - - - Qt::Horizontal - - - 500 - - - - - - - -960 - - - 0 - - - 1 - - - Qt::Horizontal - - - 10 - - - - - - - - 5 - 4 - 0 - 0 - - - - Attack - - - - - - - Decay - - - - - + + + + + 7 + 7 + 0 + 0 + + + + Oscillator + + + + 11 + + + 2 + + + + + + 5 + 1 + 0 + 0 + + + + Brass + + + + + + + + 5 + 1 + 0 + 0 + + + + Reed + + + + + + + + 5 + 1 + 0 + 0 + + + + Flute + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Velocity + + + + + + + + + + + 7 + 5 + 0 + 0 + + + + + 48 + 50 + false + false + false + false + + + + O-1 + + + Qt::AlignCenter + + + + + + + + 7 + 7 + 0 + 0 + + + + Drawbars + + + + 6 + + + 2 + + + + + 16' + + + + + + + 4' + + + + + + + 2 2/3' + + + + + + + 2' + + + + + + + 5 1/3' + + + + + + + 8' + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + + 7 + 0 + 0 + 0 + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + 0 + + + -960 + + + + + + + 0 + + + -960 + + + 10 + + + + + + + 0 + + + -960 + + + 10 + + + + + + + 0 + + + -960 + + + 10 + + + + + + + 0 + + + -960 + + + 10 + + + + + + + 0 + + + -960 + + + 10 + + + + + + + + + + + 7 + 7 + 0 + 0 + + + + Envelope Lo + + + Qt::AlignLeading + + + + 11 + + + 2 + + + + + Attack + + + + + + + Decay + + + + + + + Sustain + + + + + + + Release + + + + + + + + 7 + 0 + 0 + 0 + + + + + 80 + 0 + + + + 500 + + + 1 + + + Qt::Horizontal + + + 50 + + + + + + + 5000 + + + 1 + + + Qt::Horizontal + + + 500 + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + 500 + + + 1 + + + Qt::Horizontal + + + 50 + + + + + + + + 1 + 0 + 0 + 0 + + + + ms + + + 500 + + + + + + + + 1 + 0 + 0 + 0 + + + + ms + + + 5000 + + + + + + + + 1 + 0 + 0 + 0 + + + + cB + + + 0 + + + -960 + + + 0 + + + + + + + + 1 + 0 + 0 + 0 + + + + ms + + + 500 + + + + + + + + + + + 7 + 7 + 0 + 0 + + + + Envelope Hi + + + + 8 + + + 6 + + + + + 500 + + + 1 + + + Qt::Horizontal + + + 50 + + + + + + + Sustain + + + + + + + Release + + + + + + + + 5 + 0 + 0 + 0 + + + + ms + + + 500 + + + + + + + + 5 + 0 + 0 + 0 + + + + cB + + + 0 + + + -960 + + + + + + + + 5 + 0 + 0 + 0 + + + + ms + + + 5000 + + + + + + + + 7 + 0 + 0 + 0 + + + + 500 + + + 1 + + + Qt::Horizontal + + + 50 + + + + + + + + 5 + 0 + 0 + 0 + + + + ms + + + 500 + + + + + + + 5000 + + + 1 + + + Qt::Horizontal + + + 500 + + + + + + + -960 + + + 0 + + + 1 + + + Qt::Horizontal + + + 10 + + + + + + + + 5 + 4 + 0 + 0 + + + + Attack + + + + + + + Decay + + + + + + + - p1 p3 -- cgit v1.2.3