260 lines
8.1 KiB
C++
260 lines
8.1 KiB
C++
//=============================================================================
|
|
// MusE Score
|
|
// Linux Music Score Editor
|
|
// $Id: seq.h 5660 2012-05-22 14:17:39Z wschweer $
|
|
//
|
|
// Copyright (C) 2002-2009 Werner Schweer and others
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//=============================================================================
|
|
|
|
#ifndef __SEQ_H__
|
|
#define __SEQ_H__
|
|
|
|
#include "libmscore/sequencer.h"
|
|
#include "libmscore/fraction.h"
|
|
#include "synthesizer/event.h"
|
|
#include "driver.h"
|
|
#include "libmscore/fifo.h"
|
|
#include "libmscore/tempo.h"
|
|
|
|
class QTimer;
|
|
|
|
namespace Ms {
|
|
|
|
class Note;
|
|
class MasterScore;
|
|
class Score;
|
|
class Painter;
|
|
class Measure;
|
|
class Fraction;
|
|
class Driver;
|
|
class Part;
|
|
struct Channel;
|
|
class ScoreView;
|
|
class MasterSynthesizer;
|
|
class Segment;
|
|
enum class POS : char;
|
|
|
|
//---------------------------------------------------------
|
|
// SeqMsg
|
|
// message format for gui -> sequencer messages
|
|
//---------------------------------------------------------
|
|
|
|
enum class SeqMsgId : char {
|
|
NO_MESSAGE,
|
|
TEMPO_CHANGE,
|
|
PLAY, SEEK,
|
|
MIDI_INPUT_EVENT
|
|
};
|
|
|
|
struct SeqMsg {
|
|
SeqMsgId id;
|
|
union {
|
|
int intVal;
|
|
qreal realVal;
|
|
};
|
|
NPlayEvent event;
|
|
|
|
SeqMsg() {}
|
|
SeqMsg(SeqMsgId _id, int val) : id(_id), intVal(val) {}
|
|
SeqMsg(SeqMsgId _id, qreal val) : id(_id), realVal(val) {}
|
|
SeqMsg(SeqMsgId _id, const NPlayEvent& e) : id(_id), event(e) {}
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// SeqMsgFifo
|
|
//---------------------------------------------------------
|
|
|
|
static const int SEQ_MSG_FIFO_SIZE = 1024*8;
|
|
|
|
class SeqMsgFifo : public FifoBase {
|
|
SeqMsg messages[SEQ_MSG_FIFO_SIZE];
|
|
|
|
public:
|
|
SeqMsgFifo();
|
|
virtual ~SeqMsgFifo() {}
|
|
void enqueue(const SeqMsg&); // put object on fifo
|
|
SeqMsg dequeue(); // remove object from fifo
|
|
};
|
|
|
|
// this are also the jack audio transport states:
|
|
enum class Transport : char {
|
|
STOP=0,
|
|
PLAY=1,
|
|
STARTING=3,
|
|
NET_STARTING=4
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// Seq
|
|
// sequencer
|
|
//---------------------------------------------------------
|
|
|
|
class Seq : public QObject, public Sequencer {
|
|
Q_OBJECT
|
|
|
|
mutable QMutex mutex;
|
|
|
|
MasterScore* cs;
|
|
ScoreView* cv;
|
|
bool running; // true if sequencer is available
|
|
Transport state; // STOP, PLAY, STARTING=3
|
|
bool inCountIn;
|
|
// When we begin playing count in, JACK should play the ticks, but shouldn't run
|
|
// JACK Transport to prevent playing in other applications. Before playing
|
|
// count in we have to disconnect from JACK Transport by switching to the fake transport.
|
|
// Also we save current preferences.useJackTransport value to useJackTransportSavedFlag
|
|
// to restore it when count in ends. After this all applications start playing in sync.
|
|
bool useJackTransportSavedFlag;
|
|
int maxMidiOutPort; // Maximum count of midi out ports in all opened scores
|
|
Fraction prevTimeSig;
|
|
double prevTempo;
|
|
|
|
bool oggInit;
|
|
bool playlistChanged;
|
|
|
|
SeqMsgFifo toSeq;
|
|
SeqMsgFifo fromSeq;
|
|
Driver* _driver;
|
|
MasterSynthesizer* _synti;
|
|
|
|
double meterValue[2];
|
|
double meterPeakValue[2];
|
|
int peakTimer[2];
|
|
|
|
EventMap events; // playlist for playback mode (pre-rendered)
|
|
EventMap countInEvents;
|
|
QQueue<NPlayEvent> _liveEventQueue; // playlist for score editing and note entry (rendered live)
|
|
|
|
int playTime; // current play position in samples
|
|
int countInPlayTime;
|
|
int endTick;
|
|
|
|
EventMap::const_iterator playPos; // moved in real time thread
|
|
EventMap::const_iterator countInPlayPos;
|
|
EventMap::const_iterator guiPos; // moved in gui thread
|
|
QList<const Note*> markedNotes; // notes marked as sounding
|
|
|
|
uint tackRemain; // metronome state (remaining audio samples)
|
|
uint tickRemain;
|
|
qreal tackVolume; // relative volumes
|
|
qreal tickVolume;
|
|
qreal metronomeVolume; // overall volume
|
|
|
|
QTimer* heartBeatTimer;
|
|
QTimer* noteTimer;
|
|
|
|
void collectMeasureEvents(Measure*, int staffIdx);
|
|
|
|
void setPos(int);
|
|
void playEvent(const NPlayEvent&, unsigned framePos);
|
|
void guiToSeq(const SeqMsg& msg);
|
|
void metronome(unsigned n, float* l, bool force);
|
|
void seekCommon(int utick);
|
|
void unmarkNotes();
|
|
void updateSynthesizerState(int tick1, int tick2);
|
|
void addCountInClicks();
|
|
|
|
inline QQueue<NPlayEvent>* liveEventQueue() { return &_liveEventQueue; }
|
|
|
|
private slots:
|
|
void seqMessage(int msg, int arg = 0);
|
|
void heartBeatTimeout();
|
|
void midiInputReady();
|
|
void setPlaylistChanged() { playlistChanged = true; }
|
|
void handleTimeSigTempoChanged();
|
|
|
|
public slots:
|
|
void setRelTempo(double);
|
|
void seek(int utick);
|
|
void seekRT(int utick);
|
|
void stopNotes(int channel = -1, bool realTime = false);
|
|
void start();
|
|
void stop();
|
|
void setPos(POS, unsigned);
|
|
void setMetronomeGain(float val) { metronomeVolume = val; }
|
|
|
|
signals:
|
|
void started();
|
|
void stopped();
|
|
int toGui(int, int arg = 0);
|
|
void heartBeat(int, int, int);
|
|
void tempoChanged();
|
|
void timeSigChanged();
|
|
|
|
public:
|
|
Seq();
|
|
~Seq();
|
|
bool canStart();
|
|
void rewindStart();
|
|
void loopStart();
|
|
void seekEnd();
|
|
void nextMeasure();
|
|
void nextChord();
|
|
void prevMeasure();
|
|
void prevChord();
|
|
|
|
void collectEvents();
|
|
void guiStop();
|
|
void stopWait();
|
|
void setLoopIn();
|
|
void setLoopOut();
|
|
void setLoopSelection();
|
|
|
|
bool init(bool hotPlug = false);
|
|
void exit();
|
|
bool isRunning() const { return running; }
|
|
bool isPlaying() const { return state == Transport::PLAY; }
|
|
bool isStopped() const { return state == Transport::STOP; }
|
|
|
|
void processMessages();
|
|
void process(unsigned, float*);
|
|
int getEndTick() const { return endTick; }
|
|
bool isRealtime() const { return true; }
|
|
void sendMessage(SeqMsg&) const;
|
|
|
|
void setController(int, int, int);
|
|
virtual void sendEvent(const NPlayEvent&);
|
|
void setScoreView(ScoreView*);
|
|
MasterScore* score() const { return cs; }
|
|
ScoreView* viewer() const { return cv; }
|
|
void initInstruments(bool realTime = false);
|
|
|
|
Driver* driver() { return _driver; }
|
|
void setDriver(Driver* d) { _driver = d; }
|
|
MasterSynthesizer* synti() const { return _synti; }
|
|
void setMasterSynthesizer(MasterSynthesizer* ms) { _synti = ms; }
|
|
|
|
int getCurTick();
|
|
double curTempo() const;
|
|
|
|
void putEvent(const NPlayEvent&, unsigned framePos = 0);
|
|
void startNoteTimer(int duration);
|
|
virtual void startNote(int channel, int, int, double nt) override;
|
|
virtual void startNote(int channel, int, int, int, double nt) override;
|
|
virtual void playMetronomeBeat(BeatType type) override;
|
|
|
|
void eventToGui(NPlayEvent);
|
|
void stopNoteTimer();
|
|
void recomputeMaxMidiOutPort();
|
|
float metronomeGain() const { return metronomeVolume; }
|
|
};
|
|
|
|
extern Seq* seq;
|
|
extern void initSequencer();
|
|
extern bool initMidi();
|
|
|
|
} // namespace Ms
|
|
#endif
|
|
|