diff options
| -rw-r--r-- | drumgizmo/drumgizmoc.cc | 20 | ||||
| -rw-r--r-- | drumgizmo/enginefactory.cc | 50 | ||||
| -rw-r--r-- | drumgizmo/enginefactory.h | 37 | ||||
| -rw-r--r-- | drumgizmo/input/midifile.cc | 160 | ||||
| -rw-r--r-- | drumgizmo/input/midifile.h | 66 | ||||
| -rw-r--r-- | drumgizmo/output/wavfile.cc | 98 | ||||
| -rw-r--r-- | drumgizmo/output/wavfile.h | 223 | ||||
| -rw-r--r-- | src/audiooutputengine.h | 2 | 
8 files changed, 640 insertions, 16 deletions
| diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc index 10dcda5..978b0cc 100644 --- a/drumgizmo/drumgizmoc.cc +++ b/drumgizmo/drumgizmoc.cc @@ -36,9 +36,7 @@  #include "drumgizmo.h"  #include "drumgizmoc.h" - -#include "audiooutputenginedl.h" -#include "audioinputenginedl.h" +#include "enginefactory.h"  #include "event.h" @@ -228,7 +226,7 @@ int CliMain::run(int argc, char *argv[])      return 1;    } -  AudioInputEngine *ie = new AudioInputEngineDL(inputengine); +  auto ie = createInputEngine(inputengine);    if(ie == NULL) {      printf("Invalid input engine: %s\n", inputengine.c_str()); @@ -264,11 +262,10 @@ int CliMain::run(int argc, char *argv[])    if(outputengine == "") {      printf("Missing output engine\n"); -    delete ie;      return 1;    } -  AudioOutputEngineDL *oe = new AudioOutputEngineDL(outputengine); +  auto oe = createOutputEngine(outputengine);    if(oe == NULL) {      printf("Invalid output engine: %s\n", outputengine.c_str()); @@ -309,8 +306,6 @@ int CliMain::run(int argc, char *argv[])        if(kitfile != "") {          printf("Can only handle a single kitfile.\n");          printf(usage_str, argv[0]); -        delete ie; -        delete oe;          return 1;        }        kitfile = argv[optind++]; @@ -319,14 +314,12 @@ int CliMain::run(int argc, char *argv[])    } else {      printf("Missing kitfile.\n");      printf(usage_str, argv[0]); -    delete ie; -    delete oe;      return 1;    }    printf("Using kitfile: %s\n", kitfile.c_str()); -  DrumGizmo gizmo(oe, ie); +  DrumGizmo gizmo(oe.get(), ie.get());  	gizmo.setFrameSize(oe->getBufferSize()); @@ -354,8 +347,6 @@ int CliMain::run(int argc, char *argv[])    if(!gizmo.init()) {      printf("Failed init engine.\n"); -    delete ie; -    delete oe;      return 1;    } @@ -363,9 +354,6 @@ int CliMain::run(int argc, char *argv[])    printf("Quit.\n"); fflush(stdout); -  delete oe; -  delete ie; -    hug_close();    return 0; diff --git a/drumgizmo/enginefactory.cc b/drumgizmo/enginefactory.cc new file mode 100644 index 0000000..b6569e0 --- /dev/null +++ b/drumgizmo/enginefactory.cc @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            enginefactory.cc + * + *  Mi 20. Jan 10:46:07 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 "enginefactory.h" +#include "jackclient.h" +#include "input/midifile.h" +#include "output/wavfile.h" + +InputEnginePtr createInputEngine(std::string const & name) { +	if (name == "midifile") { +		return std::make_unique<MidifileInputEngine>(); +	} +	// todo: add more engines +	 +	printf("Unsupported input engine: %s\n", name.c_str()); +	return nullptr; +} + +OutputEnginePtr createOutputEngine(std::string const & name) { +	if (name == "wavfile") { +		return std::make_unique<WavfileOutputEngine>(); +	} +	// todo: add more engines +	 +	printf("Unsupported output engine: %s\n", name.c_str()); +	return nullptr; +} diff --git a/drumgizmo/enginefactory.h b/drumgizmo/enginefactory.h new file mode 100644 index 0000000..93624b9 --- /dev/null +++ b/drumgizmo/enginefactory.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            enginefactory.h + * + *  Mi 20. Jan 10:46:07 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 +#include <memory> +#include "cpp11fix.h" // required for c++11 + +#include "audioinputengine.h" + +using InputEnginePtr = std::unique_ptr<AudioInputEngine>; +using OutputEnginePtr = std::unique_ptr<AudioOutputEngine>; + +InputEnginePtr createInputEngine(std::string const & name); +OutputEnginePtr createOutputEngine(std::string const & name); diff --git a/drumgizmo/input/midifile.cc b/drumgizmo/input/midifile.cc new file mode 100644 index 0000000..b0685ec --- /dev/null +++ b/drumgizmo/input/midifile.cc @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            midifile.cc + * + *  Mi 20. Jan 16:07:57 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 "midifile.h" + +int const NOTE_ON = 0x90; + +MidifileInputEngine::MidifileInputEngine() +	: smf{nullptr} +	, current_event{nullptr} +	, file{} +	, midimap{} +	, speed{1.f} +	, track{-1} // all tracks +	, loop{false} +	, offset{0.0} { +} + +MidifileInputEngine::~MidifileInputEngine() { +	if (smf != nullptr) { +		smf_delete(smf); +	} +} + +bool MidifileInputEngine::isMidiEngine() { +} + +bool MidifileInputEngine::init(Instruments& instruments) { +	if (file == "") { +		fprintf(stderr, "Missing midifile argument 'file'\n"); +		return false; +	} +	if (midimap == "") { +		fprintf(stderr, "Missing midimapfile argument 'midimap'.\n"); +		return false; +	} +	smf = smf_load(file.c_str()); +	if (sfml == nullptr) { +		fprintf(stderr, "Could not open midifile '%s'.\n", filename.c_str()); +		return false; +	} +	MidiMapParser p{midimap}; +	if (p.parse()) { +		fprintf(stderr, "Could not parse midimapfile '%s'.\n", midimapfile.c_str()); +		return false; +	} +	midiMapper.midimap = std::move(p.midimap); +	for (auto i = 0u; i < instruments.size(); ++i) { +		auto name = instruments[0]->name; +		midiMapper.instrmap[name] = i; +	} +	return true; +} + +void MidifileInputEngine::setParm(std::string parm, std::string value) { +	if(parm == "file") { +		filen = value; +	} else if(parm == "speed") { +		speed = std::stof(value); +	} else if (parm == "midimap") { +		midimap = value; +	} else if (parm == "loop") { +		loop = true; +	} else { +		printf("Unsupported midifile parameter '%s'\n", parm); +	} +} + +bool MidifileInputEngine::start() { +	return true; +} + +void MidifileInputEngine::stop() { +} + +void MidifileInputEngine::pre() { +} + +event_t* MidifileInputEngine::run(size_t pos, size_t len, size_t *nevents) { +	event_t* evs{nullptr}; +	std::size_t nevs{0u}; +	double current_max_time = 1.0 * (pos + len) / (44100.0 / speed); +	current_max_time -= offset; +	if (current_event == nullptr) { +		current_event = smf_get_next_event(smf); +	} +	while(current_event && current_event->time_seconds < cur_max_time) { +		if(!smf_event_is_metadata(current_event)) { +			if((current_event->midi_buffer_length == 3) && +			   ((current_event->midi_buffer[0] & NOTE_ON) == NOTE_ON) && +			   (track == -1 || current_event->track_number == track) && +			    current_event->midi_buffer[2] > 0) { +				if(evs == NULL) { +					evs = (event_t *)malloc(sizeof(event_t) * 1000); +				} +				int key = current_event->midi_buffer[1]; +				int velocity = current_event->midi_buffer[2]; +				 +				evs[nevs].type = TYPE_ONSET; +				size_t evpos = current_event->time_seconds * (44100.0 / speed); +				evs[nevs].offset = evpos - pos; +				 +				int i = midiMap.lookup(key); +				if(i != -1) { +					evs[nevs].instrument = i; +					evs[nevs].velocity = velocity / 127.0; +					nevs++; +					if(nevs > 999) { +						fprintf(stderr, "PANIC!\n"); +						break; +					} +				} +			} +		} +		current_event = smf_get_next_event(smf); +	} +	 +	if(!current_event) { +		if(loop) { +			smf_rewind(smf); +			offset += cur_max_time; +		} else { +			if(evs == NULL) { +				evs = (event_t *)malloc(sizeof(event_t) * 1000); +			} +			evs[nevs].type = TYPE_STOP; +			evs[nevs].offset = len - 1; +			nevs++; +		} +	} +	 +	*nevents = nevs; +	return evs; +} + +void MidifileInputEngine::post() { +} diff --git a/drumgizmo/input/midifile.h b/drumgizmo/input/midifile.h new file mode 100644 index 0000000..c2fcdb6 --- /dev/null +++ b/drumgizmo/input/midifile.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            minifile.h + * + *  Mi 20. Jan 16:07:57 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 +#include <string> + +#include <event.h> +#include <smf.h> + +#include <audioinputengine.h> +#include <midimapper.h> +#include <midimapparser.h> + +#define NOTE_ON 0x90 + +class MidifileInputEngine +	: public AudioInputEngine { +	public: +		MidifileInputEngine(); +		~MidifileInputEngine(); +		 +		// based on AudioInputEngine +		bool isMidiEngine() override; +		bool init(Instruments &instruments) override; +		void setParm(std::string parm, std::string value) override; +		bool start() override; +		void stop() override; +		void pre() override; +		event_t* run(size_t pos, size_t len, size_t* nevents) override; +		void post() override; +		 +	private: +		smf_t* smf; +		smf_event_t* current_event; +		 +		MidiMapper midiMapper; +		 +		std::string file, midimap; +		float speed; +		int track; +		bool loop; +		double offset; +}; diff --git a/drumgizmo/output/wavfile.cc b/drumgizmo/output/wavfile.cc new file mode 100644 index 0000000..e0c18cb --- /dev/null +++ b/drumgizmo/output/wavfile.cc @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            wavfile.cc + * + *  Mi 20. Jan 16:57:16 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 "wavfile.h" + +WavfileOutputEngine::WavfileOutputEngine() +	: info{} +	, channels{} +	, file{"output"} { +	info.frames = 0; +	info.samplerrate = 44100; +	info.channels = 1; +	info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; +	info.sections = 0; +	info.seekable = 0; +} + +WavfileOutputEngine::~WavfileOutputEngine() { +	for (auto& ptr: channels) { +		if (ptr != nullptr) { +			sf_close(ptr); +		} +	} +} + +bool WavfileOutputEngine::init(Channels channels) { +	channels.clear(), +	channels.resize(channels.size(), nullptr); +	for (auto i = 0u; i < channels.size(); ++i) { +		// write channel to file +		auto fname = file + channels[i]->name + "-" + std::to_string(i); +		channels[i] = sf_open(fname, SFM_WRITE, &info); +		if (channels[i] == nullptr) { +			printf("Write error...\n"); +			return false; +		} +	} +	return true; +} + +void WavfileOutputEngine::setParm(std::string parm, std::string value) { +	if (parm == "file") { +		file = value; +	} else if (parm == "srate") {[ +		info.samplerate = std::stoi(value); +	} else { +		printf("Unsupported wavfile parameter '%s'\n", parm); +	} +} + +bool WavfileOutputEngine::start() { +	return true; +} + +void WavfileOutputEngine::stop() { +} + +void WavfileOutputEngine::pre(size_t nsamples) { +} + +void WavfileOutputEngine::run(int ch, sample_t* samples, size_t nsamples) { +	if (ch >= channels.size()) { +		printf("Invalid channel %d (%d channels available)", ch, channels.size()); +		return; +	} +	 +	sf_writef_float(channels[ch], samples, nsampels); +} + +void WavfileOutputEngine::post(size_t nsamples) { +} + +size_t WavfileOutputEngine::samplerate() { +	return info.samplerate; +} diff --git a/drumgizmo/output/wavfile.h b/drumgizmo/output/wavfile.h new file mode 100644 index 0000000..0f93049 --- /dev/null +++ b/drumgizmo/output/wavfile.h @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            wavfile.h + * + *  Mi 20. Jan 16:57:16 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 +#include <string> +#include <vector> + +#include <sndfile.h> + +#include "audiooutputengine.h" + +class WavfileOutputEngine +	: public AudioOutputEngine { +	public: +		WavfileOutputEngine(); +		~WavfileOutputEngine(); +		 +		// based on AudioOutputEngine +		bool init(Channels channels) 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: +		SF_INFO info; +		std::vector<SNDFILE*> channels; +		size_t num_channels; +		 +		std::string file; +}; + + + +#include <stdlib.h> + +#include <audiotypes.h> +#include <string> +#include <memory.h> + + +class WavFile { +public: +  WavFile(); +  ~WavFile(); +  bool init(int channels, char *cnames[]); +  void setParm(std::string parm, std::string value); +  bool start(); +  void stop(); +  void pre(size_t size); +  void run(int channel, sample_t* data, size_t size); +  void post(size_t size); +  size_t samplerate(); + +private: +   +}; + +WavFile::WavFile() +{ +  fh = NULL; +  filename = "output"; + +  memset(&sf_info, 0, sizeof(sf_info)); +  sf_info.channels = 1;//channels; +  sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; +  sf_info.samplerate = 44100; +} + +WavFile::~WavFile() +{ +  if(fh == NULL) return; + +  for(size_t i override; i < channels; i++) { +    if(fh[i]) sf_close(fh[i]); +  } + +  if(fh) free(fh); +} + +bool WavFile::init(int channels, char *cnames[]) +{ +  this->channels = channels; + +  fh = (SNDFILE **)malloc(sizeof(SNDFILE *)*channels); + +  for(size_t i override; i < this->channels; i++) fh[i] = NULL; + +  for(size_t i override; i < this->channels; i++) { +    char fname[512]; + +    sprintf(fname, "%s%s-%d.wav", filename.c_str(), cnames[i], (int)i); +    //    printf("[%s]\n", fname); + +    fh[i] = sf_open(fname, SFM_WRITE, &sf_info); +    if(!fh[i]) { +      printf("Write error...\n"); +      return false; +    } +  } + +  return true; +} + +void WavFile::setParm(std::string parm, std::string value) +{ +  if(parm == "file") filename = value; +  if(parm == "srate") sf_info.samplerate = atoi(value.c_str()); +} + +bool WavFile::start() +{ +  return true; +} + +void WavFile::stop() +{ +} + +void WavFile::pre(size_t size) +{ +} + +void WavFile::run(int channel, sample_t* cdata, size_t csize) +{ +  if(channel < (int)channels) sf_writef_float(fh[channel], cdata, csize);  +} + +void WavFile::post(size_t size) +{ +} + +size_t WavFile::samplerate() +{ +  return sf_info.samplerate; +} + +extern "C" { +  void *create() +  { +    return new WavFile(); +  } +   +  void destroy(void *h) +  { +    WavFile *sndfile = (WavFile*)h; +    delete sndfile; +  } + +  bool init(void *h, int cs, char *cnames[]) +  { +    WavFile *sndfile = (WavFile*)h; +    return sndfile->init(cs, cnames); +  } + +  void setparm(void *h, const char *parm, const char *value) +  { +    WavFile *sndfile = (WavFile*)h; +    sndfile->setParm(parm, value); +  } + +  bool start(void *h) +  { +    WavFile *sndfile = (WavFile*)h; +    return sndfile->start(); +  } + +  void stop(void *h) +  { +    WavFile *sndfile = (WavFile*)h; +    sndfile->stop(); +  } + +  void pre(void *h, size_t s) +  { +    WavFile *sndfile = (WavFile*)h; +    sndfile->pre(s); +  } + +  void run(void *h, int ch, sample_t *data, size_t size) +  { +    WavFile *sndfile = (WavFile*)h; +    sndfile->run(ch, data, size); +  } + +  void post(void *h, size_t s) +  { +    WavFile *sndfile = (WavFile*)h; +    sndfile->post(s); +  } + +  size_t samplerate(void *h) +  { +    WavFile *wavfile = (WavFile*)h; +    return wavfile->samplerate(); +  } +} diff --git a/src/audiooutputengine.h b/src/audiooutputengine.h index 7f15e49..562a46b 100644 --- a/src/audiooutputengine.h +++ b/src/audiooutputengine.h @@ -55,6 +55,8 @@ public:     * Overload this method to force engine to use different buffer size.     */    virtual size_t getBufferSize() { return 1024; } +   +  virtual size_t samplerate() { return 44100; }  };  #endif/*__DRUMGIZMO_AUDIOOUTPUTENGINE_H__*/ | 
