You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/sound/JackDriver.h

296 lines
11 KiB

/*
Rosegarden
A sequencer and musical notation editor.
This program is Copyright 2000-2008
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <bownie@bownie.com>
The moral right of the authors to claim authorship of this work
has been asserted.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#ifndef _JACKDRIVER_H_
#define _JACKDRIVER_H_
#ifdef HAVE_ALSA
#ifdef HAVE_LIBJACK
#include "RunnablePluginInstance.h"
#include <jack/jack.h>
#include "SoundDriver.h"
#include "Instrument.h"
#include "RealTime.h"
#include "ExternalTransport.h"
#include <tqstringlist.h>
namespace Rosegarden
{
class AlsaDriver;
class AudioBussMixer;
class AudioInstrumentMixer;
class AudioFileReader;
class AudioFileWriter;
class JackDriver
{
public:
// convenience
typedef jack_default_audio_sample_t sample_t;
JackDriver(AlsaDriver *alsaDriver);
virtual ~JackDriver();
bool isOK() const { return m_ok; }
bool isTransportEnabled() { return m_jackTransportEnabled; }
bool isTransportMaster () { return m_jackTransportMaster; }
void setTransportEnabled(bool e) { m_jackTransportEnabled = e; }
void setTransportMaster (bool m) { m_jackTransportMaster = m; }
// These methods call back on the sound driver if necessary to
// establish the current transport location to start at or
// relocate to. startTransport and relocateTransport return true
// if they have completed and the sound driver can safely call
// startClocks; false if the sound driver should wait for the JACK
// driver to call back on startClocksApproved before starting.
bool startTransport();
bool relocateTransport();
void stopTransport();
RealTime getAudioPlayLatency() const;
RealTime getAudioRecordLatency() const;
RealTime getInstrumentPlayLatency(InstrumentId) const;
RealTime getMaximumPlayLatency() const;
// Plugin instance management
//
virtual void setPluginInstance(InstrumentId id,
TQString identifier,
int position);
virtual void removePluginInstance(InstrumentId id, int position);
// Remove all plugin instances
//
virtual void removePluginInstances();
virtual void setPluginInstancePortValue(InstrumentId id,
int position,
unsigned long portNumber,
float value);
virtual float getPluginInstancePortValue(InstrumentId id,
int position,
unsigned long portNumber);
virtual void setPluginInstanceBypass(InstrumentId id,
int position,
bool value);
virtual TQStringList getPluginInstancePrograms(InstrumentId id,
int position);
virtual TQString getPluginInstanceProgram(InstrumentId id,
int position);
virtual TQString getPluginInstanceProgram(InstrumentId id,
int position,
int bank,
int program);
virtual unsigned long getPluginInstanceProgram(InstrumentId id,
int position,
TQString name);
virtual void setPluginInstanceProgram(InstrumentId id,
int position,
TQString program);
virtual TQString configurePlugin(InstrumentId id,
int position,
TQString key, TQString value);
virtual RunnablePluginInstance *getSynthPlugin(InstrumentId id);
virtual void clearSynthPluginEvents(); // when stopping
virtual unsigned int getSampleRate() const { return m_sampleRate; }
virtual unsigned int getBufferSize() const { return m_bufferSize; }
// A new audio file for storage of our recorded samples - the
// file stays open so we can append samples at will. We must
// explicitly close the file eventually though to make sure
// the integrity is correct (sample sizes must be written).
//
bool openRecordFile(InstrumentId id,
const std::string &fileName);
bool closeRecordFile(InstrumentId id,
AudioFileId &returnedId);
// Set or change the number of audio inputs and outputs.
// The first of these is slightly misnamed -- the submasters
// argument controls the number of busses, not ports (which
// may or may not exist depending on the setAudioPorts call).
//
void setAudioPorts(bool faderOuts, bool submasterOuts);
// Locks used by the disk thread and mix thread. The AlsaDriver
// should hold these locks whenever it wants to modify its audio
// play queue -- at least when adding or removing files or
// resetting status; it doesn't need to hold the locks when
// incrementing their statuses or simply reading them.
//
int getAudioQueueLocks();
int tryAudioQueueLocks();
int releaseAudioQueueLocks();
void prepareAudio(); // when repositioning etc
void prebufferAudio(); // when starting playback (incorporates prepareAudio)
void kickAudio(); // for paranoia only
// Because we don't want to do any lookups that might involve
// locking etc from within the JACK process thread, we instead
// call this regularly from the ALSA driver thread -- it looks up
// various bits of data such as the master fader and monitoring
// levels, number of inputs etc and either processes them or
// writes them into simple records in the JACK driver for process
// to read. Actually quite a lot of work.
//
void updateAudioData();
// Similarly, set data on the buss mixer to avoid the buss mixer
// having to call back on the mapped studio to discover it
//
void setAudioBussLevels(int bussNo, float dB, float pan);
// Likewise for instrument mixer
//
void setAudioInstrumentLevels(InstrumentId instrument, float dB, float pan);
// Called from AlsaDriver to indicate that an async MIDI event is
// being sent to a soft synth. JackDriver uses this to suggest
// that it needs to start processing soft synths, if it wasn't
// already. It will switch this off again itself when things
// fall silent.
//
void setHaveAsyncAudioEvent() { m_haveAsyncAudioEvent = true; }
RealTime getNextSliceStart(const RealTime &now) const;
// For audit purposes only.
size_t getFramesProcessed() const { return m_framesProcessed; }
// Reinitialise if we've been kicked off JACK -- if we can
//
void restoreIfRestorable();
// Report back to GUI via the AlsaDriver
//
void reportFailure(MappedEvent::FailureCode code);
protected:
// static methods for JACK process thread:
static int jackProcessStatic(jack_nframes_t nframes, void *arg);
static int jackBufferSize(jack_nframes_t nframes, void *arg);
static int jackSampleRate(jack_nframes_t nframes, void *arg);
static void jackShutdown(void *arg);
static int jackXRun(void *);
// static JACK transport callbacks
static int jackSyncCallback(jack_transport_state_t,
jack_position_t *, void *);
static int jackTimebaseCallback(jack_transport_state_t,
jack_nframes_t,
jack_position_t *,
int,
void *);
// jackProcessStatic delegates to this
int jackProcess(jack_nframes_t nframes);
int jackProcessRecord(InstrumentId id,
jack_nframes_t nframes,
sample_t *, sample_t *, bool);
int jackProcessEmpty(jack_nframes_t nframes);
// other helper methods:
void initialise(bool reinitialise = false);
bool createMainOutputs();
bool createFaderOutputs(int audioPairs, int synthPairs);
bool createSubmasterOutputs(int pairs);
bool createRecordInputs(int pairs);
bool relocateTransportInternal(bool alsoStart);
// data members:
jack_client_t *m_client;
std::vector<jack_port_t *> m_inputPorts;
std::vector<jack_port_t *> m_outputInstruments;
std::vector<jack_port_t *> m_outputSubmasters;
std::vector<jack_port_t *> m_outputMonitors;
std::vector<jack_port_t *> m_outputMasters;
jack_nframes_t m_bufferSize;
jack_nframes_t m_sampleRate;
sample_t *m_tempOutBuffer;
bool m_jackTransportEnabled;
bool m_jackTransportMaster;
bool m_waiting;
jack_transport_state_t m_waitingState;
ExternalTransport::TransportToken m_waitingToken;
int m_ignoreProcessTransportCount;
AudioBussMixer *m_bussMixer;
AudioInstrumentMixer *m_instrumentMixer;
AudioFileReader *m_fileReader;
AudioFileWriter *m_fileWriter;
AlsaDriver *m_alsaDriver;
float m_masterLevel;
unsigned long m_directMasterAudioInstruments; // bitmap
unsigned long m_directMasterSynthInstruments;
std::map<InstrumentId, RealTime> m_instrumentLatencies;
RealTime m_maxInstrumentLatency;
bool m_haveAsyncAudioEvent;
struct RecordInputDesc {
int input;
int channel;
float level;
RecordInputDesc(int i = 1000, int c = -1, float l = 0.0f) :
input(i), channel(c), level(l) { }
};
typedef std::map<InstrumentId, RecordInputDesc> RecordInputMap;
RecordInputMap m_recordInputs;
time_t m_kickedOutAt;
size_t m_framesProcessed;
bool m_ok;
};
}
#endif
#endif
#endif