summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drumgizmo/drumgizmoc.cc1
-rw-r--r--drumgizmo/jackclient.cc20
-rw-r--r--drumgizmo/jackclient.h3
-rw-r--r--drumgizmo/output/jackaudio.cc36
-rw-r--r--drumgizmo/output/jackaudio.h4
-rw-r--r--drumgizmo/output/wavfile.cc35
-rw-r--r--drumgizmo/output/wavfile.h14
-rw-r--r--src/audiooutputengine.h45
8 files changed, 125 insertions, 33 deletions
diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc
index 6433d9d..4f3123b 100644
--- a/drumgizmo/drumgizmoc.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -383,6 +383,7 @@ int main(int argc, char* argv[])
}
gizmo.setSamplerate(oe->getSamplerate());
+ oe->onLatencyChange(gizmo.getLatency());
if(!gizmo.init())
{
diff --git a/drumgizmo/jackclient.cc b/drumgizmo/jackclient.cc
index e493e1b..fb71b1b 100644
--- a/drumgizmo/jackclient.cc
+++ b/drumgizmo/jackclient.cc
@@ -57,6 +57,12 @@ int JackClient::wrapJackProcess(jack_nframes_t nframes, void* arg)
return static_cast<JackClient*>(arg)->process(nframes);
}
+void JackClient::latencyCallback(jack_latency_callback_mode_t mode,
+ void* arg)
+{
+ static_cast<JackClient*>(arg)->jackLatencyCallback(mode);
+}
+
JackClient::JackClient()
: client{nullptr}
, processes{}
@@ -65,6 +71,12 @@ JackClient::JackClient()
jack_status_t status;
client = jack_client_open("DrumGizmo", JackNullOption, &status);
jack_set_process_callback(client, JackClient::wrapJackProcess, this);
+
+ // Register callback which is called by jack when it wants to know about the
+ // current port latency.
+ jack_set_latency_callback(client,
+ JackClient::latencyCallback,
+ this);
}
JackClient::~JackClient()
@@ -103,6 +115,14 @@ int JackClient::process(jack_nframes_t num_frames)
return 0;
}
+void JackClient::jackLatencyCallback(jack_latency_callback_mode_t mode)
+{
+ for(auto& ptr : processes)
+ {
+ ptr->jackLatencyCallback(mode);
+ }
+}
+
std::size_t JackClient::getBufferSize() const
{
return jack_get_buffer_size(client);
diff --git a/drumgizmo/jackclient.h b/drumgizmo/jackclient.h
index 82cc0ed..83e5339 100644
--- a/drumgizmo/jackclient.h
+++ b/drumgizmo/jackclient.h
@@ -40,6 +40,7 @@ class JackProcess
public:
virtual ~JackProcess();
virtual void process(jack_nframes_t num_frames) = 0;
+ virtual void jackLatencyCallback(jack_latency_callback_mode_t mode) {}
};
// --------------------------------------------------------------------
@@ -78,6 +79,8 @@ private:
bool is_active;
int process(jack_nframes_t num_frames);
+ void jackLatencyCallback(jack_latency_callback_mode_t mode);
static int wrapJackProcess(jack_nframes_t nframes, void* arg);
+ static void latencyCallback(jack_latency_callback_mode_t mode, void* arg);
};
diff --git a/drumgizmo/output/jackaudio.cc b/drumgizmo/output/jackaudio.cc
index abd7d4f..75766d1 100644
--- a/drumgizmo/output/jackaudio.cc
+++ b/drumgizmo/output/jackaudio.cc
@@ -33,6 +33,7 @@ JackAudioOutputEngine::JackAudioOutputEngine(JackClient& client)
: AudioOutputEngine{}
, client(client)
, channels{}
+ , latency{0}
{
client.add(*this);
}
@@ -122,6 +123,11 @@ size_t JackAudioOutputEngine::getSamplerate() const
return client.getSampleRate();
}
+void JackAudioOutputEngine::onLatencyChange(std::size_t latency)
+{
+ this->latency = latency;
+}
+
JackAudioOutputEngine::Channel::Channel(JackClient& client,
const std::string& name,
std::size_t buffer_size)
@@ -130,3 +136,33 @@ JackAudioOutputEngine::Channel::Channel(JackClient& client,
{
samples.resize(buffer_size);
}
+
+void JackAudioOutputEngine::jackLatencyCallback(jack_latency_callback_mode_t mode)
+{
+ jack_latency_range_t range;
+ switch(mode)
+ {
+ case JackCaptureLatency:
+ // We do not have any audio input ports. Use this for when we do...
+// jack_port_get_latency_range(port_feeding_input_port,
+// JackPlaybackLatency,
+// &range);
+// range.min += 0;
+// range.max += 0;
+// jack_port_set_latency_range(input_port, JackPlaybackLatency, &range);
+ break;
+ case JackPlaybackLatency:
+ for(auto& channel : channels)
+ {
+ jack_port_get_latency_range(channel.port.port,
+ JackPlaybackLatency,
+ &range);
+ range.min += latency;
+ range.max += latency;
+ jack_port_set_latency_range(channel.port.port,
+ JackPlaybackLatency,
+ &range);
+ }
+ break;
+ }
+}
diff --git a/drumgizmo/output/jackaudio.h b/drumgizmo/output/jackaudio.h
index 324e95a..b8fbcab 100644
--- a/drumgizmo/output/jackaudio.h
+++ b/drumgizmo/output/jackaudio.h
@@ -49,11 +49,14 @@ public:
void post(size_t nsamples) override;
size_t getBufferSize() const override;
size_t getSamplerate() const override;
+ void onLatencyChange(std::size_t latency) override;
// based on JackProcess
void process(jack_nframes_t num_frames) override;
+ void jackLatencyCallback(jack_latency_callback_mode_t mode) override;
private:
+
struct Channel
{
JackPort port;
@@ -66,4 +69,5 @@ private:
JackClient& client;
std::vector<Channel> channels;
Semaphore sema;
+ std::size_t latency{0};
};
diff --git a/drumgizmo/output/wavfile.cc b/drumgizmo/output/wavfile.cc
index a9d8b0b..20b63bd 100644
--- a/drumgizmo/output/wavfile.cc
+++ b/drumgizmo/output/wavfile.cc
@@ -33,6 +33,7 @@ WavfileOutputEngine::WavfileOutputEngine()
, info{}
, channels{}
, file{"output"}
+ , latency{0}
{
info.samplerate = 44100;
info.channels = 1;
@@ -69,7 +70,8 @@ bool WavfileOutputEngine::init(const Channels& data)
return true;
}
-void WavfileOutputEngine::setParm(const std::string& parm, const std::string& value)
+void WavfileOutputEngine::setParm(const std::string& parm,
+ const std::string& value)
{
if(parm == "file")
{
@@ -105,11 +107,11 @@ void WavfileOutputEngine::stop()
{
}
-void WavfileOutputEngine::pre(size_t nsamples)
+void WavfileOutputEngine::pre(std::size_t nsamples)
{
}
-void WavfileOutputEngine::run(int ch, sample_t* samples, size_t nsamples)
+void WavfileOutputEngine::run(int ch, sample_t* samples, std::size_t nsamples)
{
if(static_cast<unsigned int>(ch) >= channels.size())
{
@@ -118,14 +120,35 @@ void WavfileOutputEngine::run(int ch, sample_t* samples, size_t nsamples)
return;
}
- sf_writef_float(channels[ch], samples, nsamples);
+ // Skip the initial 'latency' samples.
+ if(nsamples <= latency)
+ {
+ return;
+ }
+
+ nsamples -= latency;
+
+ sf_writef_float(channels[ch], samples + latency, nsamples);
}
-void WavfileOutputEngine::post(size_t nsamples)
+void WavfileOutputEngine::post(std::size_t nsamples)
{
+ if(latency > nsamples)
+ {
+ latency -= nsamples;
+ }
+ else
+ {
+ latency = 0;
+ }
}
-size_t WavfileOutputEngine::getSamplerate() const
+std::size_t WavfileOutputEngine::getSamplerate() const
{
return info.samplerate;
}
+
+void WavfileOutputEngine::onLatencyChange(std::size_t latency)
+{
+ this->latency = latency;
+}
diff --git a/drumgizmo/output/wavfile.h b/drumgizmo/output/wavfile.h
index dfe422c..656c0cd 100644
--- a/drumgizmo/output/wavfile.h
+++ b/drumgizmo/output/wavfile.h
@@ -25,6 +25,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#pragma once
+
+#include <cstddef>
#include <string>
#include <vector>
@@ -44,15 +46,17 @@ public:
void setParm(const std::string& parm, const std::string& value) override;
bool start() override;
void stop() override;
- void pre(size_t nsamples) override;
- void run(int ch, sample_t* samples, size_t nsamples) override;
- void post(size_t nsamples) override;
- size_t getSamplerate() const override;
+ void pre(std::size_t nsamples) override;
+ void run(int ch, sample_t* samples, std::size_t nsamples) override;
+ void post(std::size_t nsamples) override;
+ std::size_t getSamplerate() const override;
+ void onLatencyChange(std::size_t latency) override;
private:
SF_INFO info;
std::vector<SNDFILE*> channels;
- size_t num_channels;
+ std::size_t num_channels;
std::string file;
+ std::size_t latency;
};
diff --git a/src/audiooutputengine.h b/src/audiooutputengine.h
index df8b0ee..338b5cd 100644
--- a/src/audiooutputengine.h
+++ b/src/audiooutputengine.h
@@ -24,39 +24,40 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __DRUMGIZMO_AUDIOOUTPUTENGINE_H__
-#define __DRUMGIZMO_AUDIOOUTPUTENGINE_H__
+#pragma once
+#include <cstddef>
#include <string>
-#include <stdlib.h>
+
#include <audiotypes.h>
#include "channel.h"
-class AudioOutputEngine {
+class AudioOutputEngine
+{
public:
- virtual ~AudioOutputEngine() {}
+ virtual ~AudioOutputEngine() = default;
- virtual bool init(const Channels& channels) = 0;
+ virtual bool init(const Channels& channels) = 0;
- virtual void setParm(const std::string& parm, const std::string& value) = 0;
+ virtual void setParm(const std::string& parm, const std::string& value) = 0;
- virtual bool start() = 0;
- virtual void stop() = 0;
+ virtual bool start() = 0;
+ virtual void stop() = 0;
- virtual void pre(size_t nsamples) = 0;
- virtual void run(int ch, sample_t *samples, size_t nsamples) = 0;
- virtual void post(size_t nsamples) = 0;
+ virtual void pre(std::size_t nsamples) = 0;
+ virtual void run(int ch, sample_t *samples, std::size_t nsamples) = 0;
+ virtual void post(std::size_t nsamples) = 0;
- // Reimplement this if you wish to use internal buffer directly.
- virtual sample_t *getBuffer(int ch) const { return NULL; }
+ //! Overload this method to use internal buffer directly.
+ virtual sample_t *getBuffer(int ch) const { return NULL; }
- /*
- * Overload this method to force engine to use different buffer size.
- */
- virtual size_t getBufferSize() const { return 1024; }
-
- virtual size_t getSamplerate() const { return 44100; }
-};
+ //! Overload this method to force engine to use different buffer size.
+ virtual std::size_t getBufferSize() const { return 1024; }
-#endif/*__DRUMGIZMO_AUDIOOUTPUTENGINE_H__*/
+ virtual std::size_t getSamplerate() const { return 44100; }
+
+ //! Overload this method to get notification of latency changes.
+ //! \param latency The new latency in samples.
+ virtual void onLatencyChange(std::size_t latency) {}
+};