diff options
| author | Christian Glöckner <cgloeckner@freenet.de> | 2016-01-21 18:00:28 +0100 | 
|---|---|---|
| committer | André Nusser <andre.nusser@googlemail.com> | 2016-02-09 09:02:18 +0100 | 
| commit | 6253e37c2f0219d61193d0d405e7f23a4bae3287 (patch) | |
| tree | 28f687ca1327cec4cac848a80eb82cd8128ded27 /drumgizmo | |
| parent | 3ab30fd4168217894ee781cf93df522d3565cec8 (diff) | |
Added AlsaOutputEngine
Diffstat (limited to 'drumgizmo')
| -rw-r--r-- | drumgizmo/Makefile.am | 33 | ||||
| -rw-r--r-- | drumgizmo/enginefactory.cc | 25 | ||||
| -rw-r--r-- | drumgizmo/output/alsa.cc | 141 | ||||
| -rw-r--r-- | drumgizmo/output/alsa.h | 62 | 
4 files changed, 253 insertions, 8 deletions
| diff --git a/drumgizmo/Makefile.am b/drumgizmo/Makefile.am index 7044303..654ec77 100644 --- a/drumgizmo/Makefile.am +++ b/drumgizmo/Makefile.am @@ -8,9 +8,11 @@ SUBDIRS = input output  bin_PROGRAMS = drumgizmo -drumgizmo_LDADD = $(DRUMGIZMO_LIBS) $(PTHREAD_LIBS) $(SMF_LIBS) -ldl $(JACK_LIBS) +drumgizmo_LDADD = $(DRUMGIZMO_LIBS) $(PTHREAD_LIBS) -ldl $(JACK_LIBS) -drumgizmo_CXXFLAGS = $(SNDFILE_CXXFLAGS) $(PTHREAD_CFLAGS) $(SMF_CFLAGS) $(EXPAT_CFLAGS) \ +drumgizmo_LDFLAGS =  + +drumgizmo_CXXFLAGS = $(SNDFILE_CXXFLAGS) $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) \  	-I$(top_srcdir)/include -I$(top_srcdir)/src \  	-I$(top_srcdir)/hugin -DWITH_HUG_MUTEX -DWITH_HUG_FILTER \  	$(JACK_CFLAGS) $(SSEFLAGS) \ @@ -23,17 +25,32 @@ drumgizmo_SOURCES = \  	drumgizmoc.cc \  	jackclient.cc \  	enginefactory.cc \ -	input/midifile.cc \ -	output/wavfile.cc \  	$(DRUMGIZMO_SOURCES) \  	$(top_srcdir)/hugin/hugin.c \  	$(top_srcdir)/hugin/hugin_filter.c +#if HAVE_INPUT_MIDIFILE +drumgizmo_CXXFLAGS += $(SMF_CFLAGS) +drumgizmo_LDADD += $(SMF_LIBS) +drumgizmo_SOURCES += input/midifile.cc +#drumgizmo_CXXFLAGS += HAVE_INPUT_MIDIFILE +#endif # HAVE_INPUT_MIDIFILE + +#if HAVE_OUTPUT_WAVFILE +drumgizmo_SOURCES += output/wavfile.cc +#drumgizmo_CXXFLAGS += HAVE_OUTPUT_WAVFILE +#endif # HAVE_OUTPUT_WAVFILE + +#if HAVE_OUTPUT_ALSA +drumgizmo_CXXFLAGS += $(ALSA_CFLAGS) +drumgizmo_LDFLAGS += $(ALSA_LIBS) +drumgizmo_SOURCES += output/alsa.cc +#drumgizmo_CXXFLAGS += HAVE_OUTPUT_ALSA +#endif # HAVE_OUTPUT_ALSA +  EXTRA_DIST = \  	drumgizmoc.h \  	jackclient.h \ -	enginefactory.h \ -	input/midifile.h \ -	output/wavfile.h +	enginefactory.h -endif +endif # ENABLE_CLI diff --git a/drumgizmo/enginefactory.cc b/drumgizmo/enginefactory.cc index b6569e0..4e9bc62 100644 --- a/drumgizmo/enginefactory.cc +++ b/drumgizmo/enginefactory.cc @@ -26,13 +26,30 @@   */  #include "enginefactory.h"  #include "jackclient.h" + +#define HAVE_INPUT_MIDIFILE 1 +#define HAVE_OUTPUT_WAVFILE 1 +#define HAVE_OUTPUT_ALSA 1 + +#ifdef HAVE_INPUT_MIDIFILE  #include "input/midifile.h" +#endif + +#ifdef HAVE_OUTPUT_WAVFILE  #include "output/wavfile.h" +#endif + +#ifdef HAVE_OUTPUT_ALSA +#include "output/alsa.h" +#endif  InputEnginePtr createInputEngine(std::string const & name) { +#ifdef HAVE_INPUT_MIDIFILE  	if (name == "midifile") {  		return std::make_unique<MidifileInputEngine>();  	} +#endif +	  	// todo: add more engines  	printf("Unsupported input engine: %s\n", name.c_str()); @@ -40,9 +57,17 @@ InputEnginePtr createInputEngine(std::string const & name) {  }  OutputEnginePtr createOutputEngine(std::string const & name) { +#ifdef HAVE_OUTPUT_WAVFILE  	if (name == "wavfile") {  		return std::make_unique<WavfileOutputEngine>();  	} +#endif +#ifdef HAVE_OUTPUT_ALSA +	if (name == "alsa") { +		return std::make_unique<AlsaOutputEngine>(); +	} +#endif +  	// todo: add more engines  	printf("Unsupported output engine: %s\n", name.c_str()); diff --git a/drumgizmo/output/alsa.cc b/drumgizmo/output/alsa.cc new file mode 100644 index 0000000..d6a2f19 --- /dev/null +++ b/drumgizmo/output/alsa.cc @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            alsa.cc + * + *  Do 21. Jan 16:48:32 CET 2016 + *  Copyright 2016 Christian Glöckner + *  cgloeckner@freenet.de + ****************************************************************************/ + +/* + *  This file is part of DrumGizmo. + * + *  DrumGizmo 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. + * + *  DrumGizmo 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 DrumGizmo; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#include "alsa.h" + +int const BUFFER_SIZE = 40960; + +struct AlsaInitError { +	int const code; +	std::string const msg; +	 +	AlsaInitError(int op_code, std::string const & msg) +		: code{code} +		, msg{msg} { +	} +	 +	static inline void test(int code, std::string const & msg) { +		if (code < 0) { +			throw AlsaInitError(code, msg); +		} +	} +}; + +AlsaOutputEngine::AlsaOutputEngine() +	: handle{nullptr} +	, params{nullptr} +	, data{} +	, num_channels{0u} +	, dev{"default"} +	, srate{44100} +	, frames{32} { +} + +AlsaOutputEngine::~AlsaOutputEngine() { +	if (params) { +		// snd_pcm_hw_params_alloca uses std alloc +		free(params); +	} +	if (handle != nullptr) { +		snd_pcm_close(handle); +	} +} + +bool AlsaOutputEngine::init(Channels channels) { +	// try to initialize alsa +	try { +		int value = snd_pcm_open(&handle, dev.c_str(), SND_PCM_STREAM_PLAYBACK, 0); +		AlsaInitError::test(value, "snd_pcm_open"); +		num_channels = channels.size(); +		if (handle == nullptr) { +			printf("No handle!\n"); +			return false; +		} +		// Allocate and init a hardware parameters object +		snd_pcm_hw_params_alloca(¶ms); +		value = snd_pcm_hw_params_any(handle, params); +		AlsaInitError::test(value, "snd_pcm_hw_params_any"); +		 +		value = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); +		AlsaInitError::test(value, "snd_pcm_hw_params_set_access"); +		value = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT); +		AlsaInitError::test(value, "snd_pcm_hw_params_set_format"); +		value = snd_pcm_hw_params_set_channels(handle, params, num_channels); +		AlsaInitError::test(value, "snd_pcm_hw_params_set_channels"); +		value = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); +		AlsaInitError::test(value, "snd_pcm_hw_params_set_rate_near"); +		value = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, 0); +		AlsaInitError::test(value, "snd_pcm_hw_params_set_period_size_near"); +		value = snd_pcm_hw_params(handle, params); +		AlsaInitError::test(value, "snd_pcm_hw_params"); +		 +	} catch (AlsaInitError const & error) { +		printf("%s failed: %s\n", error.msg.c_str(), snd_strerror(error.code)); +		fflush(stdout); +		return false; +	} +	 +	data.clear(); +	data.resize(BUFFER_SIZE * num_channels); +	 +	return true; +} + +void AlsaOutputEngine::setParm(std::string parm, std::string value) { +	if (parm == "dev") { +		dev = value; +	} else if (parm == "frames") { +		frames = std::stoi(value); +	} else if (parm == "srate") { +		srate = std::stoi(value); +	} +} + +bool AlsaOutputEngine::start() { +	return true; +} + +void AlsaOutputEngine::stop() { +} + +void AlsaOutputEngine::pre(size_t nsamples) { +} + +void AlsaOutputEngine::run(int ch, sample_t* samples, size_t nsamples) { +	// Write channel data in interleaved buffer +	for (auto i = 0u; i < nsamples; ++i) { +		data[i * num_channels + ch] = samples[i]; +	} +} + +void AlsaOutputEngine::post(size_t nsamples) { +	// Write the interleaved buffer to the soundcard +	snd_pcm_writei(handle, data.data(), nsamples); +} + +size_t AlsaOutputEngine::samplerate() { +	return srate; +} diff --git a/drumgizmo/output/alsa.h b/drumgizmo/output/alsa.h new file mode 100644 index 0000000..c7585e0 --- /dev/null +++ b/drumgizmo/output/alsa.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            alsa.h + * + *  Do 21. Jan 16:48:32 CET 2016 + *  Copyright 2016 Christian Glöckner + *  cgloeckner@freenet.de + ****************************************************************************/ + +/* + *  This file is part of DrumGizmo. + * + *  DrumGizmo 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. + * + *  DrumGizmo 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 DrumGizmo; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#pragma once + +// Use the newer ALSA API +#define ALSA_PCM_NEW_HW_PARAMS_API + +#include <audiotypes.h> +#include <alsa/asoundlib.h> + +#include "audiooutputengine.h" + +class AlsaOutputEngine +	: public AudioOutputEngine { +	public: +		AlsaOutputEngine(); +		~AlsaOutputEngine(); +		 +		// based on AudioOutputEngine +		bool init(Channels chan) override; +		void setParm(std::string parm, 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 samplerate() override; +		 +	private: +		snd_pcm_t* handle; +		snd_pcm_hw_params_t* params; +		std::vector<sample_t> data; +		size_t num_channels; +		 +		std::string dev; +		unsigned int srate; // samplerate +		snd_pcm_uframes_t frames; +}; | 
