From e4f9405f629d8731daf4deb022fa95ec8076a391 Mon Sep 17 00:00:00 2001 From: Settel Date: Sun, 8 Jan 2023 16:58:00 +0100 Subject: [PATCH] moved to public git repo --- .gitignore | 2 + AUTHORS.md | 16 ++++ COPYRIGHT | 11 +++ INSTALL.md | 19 +++++ Makefile | 11 +++ README.md | 13 ++++ data/carrier.wav | Bin 0 -> 34660 bytes data/formant.wav | Bin 0 -> 49754 bytes src/Makefile | 40 ++++++++++ src/VERSION | 1 + src/engine.cpp | 111 ++++++++++++++++++++++++++ src/engine.h | 32 ++++++++ src/inputtrack.cpp | 77 ++++++++++++++++++ src/inputtrack.h | 30 +++++++ src/main.cpp | 86 ++++++++++++++++++++ src/options.h | 25 ++++++ src/outputtrack.cpp | 43 ++++++++++ src/outputtrack.h | 28 +++++++ src/play_loop.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++++ src/track.cpp | 31 ++++++++ src/track.h | 33 ++++++++ src/types.h | 15 ++++ src/vocoder.cpp | 111 ++++++++++++++++++++++++++ src/vocoder.h | 62 +++++++++++++++ 24 files changed, 982 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS.md create mode 100644 COPYRIGHT create mode 100644 INSTALL.md create mode 100644 Makefile create mode 100644 README.md create mode 100644 data/carrier.wav create mode 100644 data/formant.wav create mode 100644 src/Makefile create mode 100644 src/VERSION create mode 100644 src/engine.cpp create mode 100644 src/engine.h create mode 100644 src/inputtrack.cpp create mode 100644 src/inputtrack.h create mode 100644 src/main.cpp create mode 100644 src/options.h create mode 100644 src/outputtrack.cpp create mode 100644 src/outputtrack.h create mode 100644 src/play_loop.cpp create mode 100644 src/track.cpp create mode 100644 src/track.h create mode 100644 src/types.h create mode 100644 src/vocoder.cpp create mode 100644 src/vocoder.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..adc312b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +src/*.o +src/vocoder diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..21388db --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,16 @@ +# Authors and people who have helped + +## idea, main code + +Achim Settelmeier + + +## ported to LADSPA + +Josh Green ,
+available at https://www.sirlab.de/linux/vocoder/ + + +## contributions + +Vincent Neuville - ported to jackd 0.116.1 diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..cacd174 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,11 @@ +Copyright (C) 2007-2012 Achim Settelmeier + +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 3 of +the License, or (at your option) any later version. + +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. diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..9f5caf7 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,19 @@ + ## Requirements + + * libsndfile development files
+ tested with version 1.0.16 and 1.0.31 + * GNU C++ compiler
+ Ubuntu: `g++-12`
+ tested with version 4.1.2 and 12.2.0 + * GNU make + +### Ubuntu + +```bash +apt install libsndfile1 libsndfile1-dev g++-12 make +``` + +## Compile + + * run `make` + * find the compiled result in `./src/vocoder` diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7c7b028 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +all: + $(MAKE) -C src/ vocoder + +clean: + rm -f *~ + rm -f output.wav + $(MAKE) -C src/ clean + +test: + rm -f output.wav + src/vocoder -f data/formant.wav -c data/carrier.wav diff --git a/README.md b/README.md new file mode 100644 index 0000000..f48678c --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Sirlab Vocoder + +See file COPYRIGHT for information about copyright status of this package. + +Make sure you visit http://www.sirlab.de/linux/vocoder/ for updates and +further information about vocoder. + + +## Contact + +I'd like to hear from you. If you like the program or not, tell me! +My email address is + Achim Settelmeier diff --git a/data/carrier.wav b/data/carrier.wav new file mode 100644 index 0000000000000000000000000000000000000000..314fe020adfad16b92dc91fe5e99586becff2203 GIT binary patch literal 34660 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 literal 0 HcmV?d00001 diff --git a/data/formant.wav b/data/formant.wav new file mode 100644 index 0000000000000000000000000000000000000000..320613d50272f07d2e23bd9f492e2f665387d7f4 GIT binary patch literal 49754 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 z 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 + * + */ + +// Includes +#include +#include +#include +#include "options.h" +#include "types.h" +#include "vocoder.h" +#include "track.h" +#include "inputtrack.h" +#include "outputtrack.h" +#include "vocoder.h" +#include "engine.h" + +using std::cout; +using std::cerr; +using std::endl; +using std::exception; +using std::runtime_error; + +// Engine +Engine::Engine(const options_t &_options): + options(_options) +{ + +} + +// run +void Engine::run(){ + const nframes_t maxFrames=65536; + + try{ + InputTrack formantTrack(options.formantFile, maxFrames, options.fps); + InputTrack carrierTrack(options.carrierFile, maxFrames, options.fps); + OutputTrack outputTrack(options.outputFile, maxFrames, options.fps); + Vocoder vocoderLeft; + Vocoder vocoderRight; + vocoderLeft.setSampleRate(options.fps); + vocoderRight.setSampleRate(options.fps); + for(unsigned int i=0; i + * + * brings input and output channels together + */ + +#ifndef __ENGINE_H__ +#define __ENGINE_H__ + +#include "types.h" +#include "inputtrack.h" +#include "outputtrack.h" +#include "vocoder.h" +#include "options.h" + +class Engine{ +public: + Engine(const options_t &options); + void run(); + void processBlock(InputTrack &formantTrack, + InputTrack &carrierTrack, + OutputTrack &outputTrack, + Vocoder &vocoderLeft, + Vocoder &vocoderRight, + nframes_t numFramesToProcess); + +private: + options_t options; +}; + +#endif diff --git a/src/inputtrack.cpp b/src/inputtrack.cpp new file mode 100644 index 0000000..dd2c001 --- /dev/null +++ b/src/inputtrack.cpp @@ -0,0 +1,77 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + */ + +// Includes +#include +#include +#include +#include "inputtrack.h" + +using std::string; +using std::runtime_error; + + +// InputTrack +InputTrack::InputTrack(const string &filename, + const nframes_t _maxFrames, + const nframes_t _fps): + Track(_maxFrames, _fps), + stretchFactor(1.0), + inputBufferSize(0), + inputBufferPtr(NULL) +{ + sndFileInfo.format=0; + sndFileFDPtr=sf_open(filename.c_str(), SFM_READ, &sndFileInfo); + + if(sndFileFDPtr==NULL) + throw runtime_error(filename + ": " + sf_strerror(NULL)); + + if(sndFileInfo.channels>2) + throw runtime_error(filename + ": too many channels (only mono or stereo supported)"); + + stretchFactor=double(fps) / sndFileInfo.samplerate; + inputBufferSize=lround(maxFrames / stretchFactor); + inputBufferPtr=new sample_t[inputBufferSize * sndFileInfo.channels]; +} + +// ~InputTrack +InputTrack::~InputTrack(){ + sf_close(sndFileFDPtr); + + if(inputBufferPtr) + delete inputBufferPtr; +} + +// readBlock +nframes_t InputTrack::readBlock(const nframes_t numFrames){ + + nframes_t numFramesToRead=lround(numFrames / stretchFactor); + nframes_t numFramesRead=sf_readf_float(sndFileFDPtr, + inputBufferPtr, + numFramesToRead); + + nframes_t numFramesAvailable=lround(numFramesRead * stretchFactor); + // level out rouding errors + if(numFramesToRead==numFramesRead) + numFramesAvailable=numFrames; + + // resample from inputBufferPtr to sampleBufferPtr + for(nframes_t dstFrameNr=0; dstFrameNr + * + * representation of a stereo input track + */ + +#ifndef __INPUTTRACK_H__ +#define __INPUTTRACK_H__ + +#include +#include "types.h" +#include "track.h" + +class InputTrack : public Track{ +public: + InputTrack(const std::string &filename, + const nframes_t maxFrames, + const nframes_t fps); + ~InputTrack(); + + nframes_t readBlock(const nframes_t numFrames); + +private: + double stretchFactor; + unsigned int inputBufferSize; + sample_t *inputBufferPtr; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..6e8b7e1 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,86 @@ +/* + * Vocoder + * © 2007-2012 Achim Settelmeier + * + */ + +// Includes +#include +#include +#include +#include "options.h" +#include "engine.h" + +using std::cout; +using std::cerr; +using std::endl; + +void initOptions(options_t &o){ + o.outputFile="output.wav"; + o.fps=44100; + o.volume=1.0; +} + +void printUsage(){ + cout << "usage: vocode -f -c [-o ] [ -v ]" << endl; + cout << " -f name of input formant WAV file" << endl; + cout << " -c name of input carrier WAV file" << endl; + cout << " -o name of output WAV file" << endl; + cout << " -v output volume in percent, eg. -v 50 (=50%) or -v 180 (=180%)" << endl; +} + +void processCommandLineArguments(options_t &o, + int argc, + char **argv){ + int opt; + + while((opt=getopt(argc, argv, "hf:c:o:v:"))!=-1){ + switch(opt){ + case 'f': + o.formantFile=optarg; + break; + case 'c': + o.carrierFile=optarg; + break; + case 'o': + o.outputFile=optarg; + break; + case 'v': + o.volume=atoi(optarg)/100.0; + break; + case 'h': + printUsage(); + exit(0); + default: + cerr << "try vocoder -h for help." << endl; + exit(1); + } + } + + if(o.formantFile.empty()){ + cerr << "no formant file given, aborting." << endl; + cerr << "try vocoder -h for help." << endl; + exit(1); + }else if(o.carrierFile.empty()){ + cerr << "no carrier file given, aborting." << endl; + cerr << "try vocoder -h for help." << endl; + exit(1); + } +} + + +// main +int main(int argc, char **argv){ + options_t options; + initOptions(options); + processCommandLineArguments(options, argc, argv); + + cout << "D " << "input (formant): " << options.formantFile << endl; + cout << "D " << "input (carrier): " << options.carrierFile << endl; + cout << "D " << "output: " << options.outputFile << endl; + + Engine e(options); + e.run(); + + return 0; +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..db69d98 --- /dev/null +++ b/src/options.h @@ -0,0 +1,25 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + * structure that stores the command line options + */ + +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +#include +#include "types.h" + +struct options_t{ + std::string formantFile; + std::string carrierFile; + std::string outputFile; + + double volume; + + nframes_t fps; +}; + + +#endif diff --git a/src/outputtrack.cpp b/src/outputtrack.cpp new file mode 100644 index 0000000..14137df --- /dev/null +++ b/src/outputtrack.cpp @@ -0,0 +1,43 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + */ + +// Includes +#include +#include +#include +#include "outputtrack.h" + +using std::string; +using std::runtime_error; + + +// OutputTrack +OutputTrack::OutputTrack(const string &filename, + const nframes_t _maxFrames, + const nframes_t _fps): + Track(_maxFrames, _fps) +{ + sndFileInfo.samplerate=fps; + sndFileInfo.channels=2; + sndFileInfo.format=SF_FORMAT_WAV + SF_FORMAT_PCM_16; + sndFileFDPtr=sf_open(filename.c_str(), SFM_WRITE, &sndFileInfo); + + if(sndFileFDPtr==NULL) + throw runtime_error(filename + ": " + sf_strerror(NULL)); +} + +// ~OutputTrack +OutputTrack::~OutputTrack(){ + sf_close(sndFileFDPtr); +} + +// writeBlock +nframes_t OutputTrack::writeBlock(const nframes_t numFrames){ + nframes_t numFramesWritten=sf_writef_float(sndFileFDPtr, + sampleBufferPtr, + numFrames); + return numFramesWritten; +} diff --git a/src/outputtrack.h b/src/outputtrack.h new file mode 100644 index 0000000..0ae9ce2 --- /dev/null +++ b/src/outputtrack.h @@ -0,0 +1,28 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + * representation of a stereo output track + */ + +#ifndef __OUTPUTTRACK_H__ +#define __OUTPUTTRACK_H__ + +#include +#include "types.h" +#include "track.h" + +class OutputTrack : public Track{ +public: + OutputTrack(const std::string &filename, + const nframes_t maxFrames, + const nframes_t fps); + ~OutputTrack(); + + nframes_t writeBlock(const nframes_t numFrames); + +private: + +}; + +#endif diff --git a/src/play_loop.cpp b/src/play_loop.cpp new file mode 100644 index 0000000..599157f --- /dev/null +++ b/src/play_loop.cpp @@ -0,0 +1,185 @@ +/** + * play_loop + * © 2007 Achim Settelmeier + * + */ + +// Includes /*fold00*/ +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using std::cout; +using std::endl; +using std::list; + +// Globals /*fold00*/ +jack_client_t *jackClient=NULL; +list files; +string port="play_loop"; +string connectPort=""; +bool loop=false; +bool exitFlag=false; +jack_port_t *jackPortOutLeft=NULL; +jack_port_t *jackPortOutRight=NULL; +jack_nframes_t sampleRate; +SNDFILE *sndFileFD=NULL; +SF_INFO sndFileInfo; +bool playSampleFlag=false; + +#define SAMPLEBUFFERSIZE 4096 +double sampleBuffer[SAMPLEBUFFERSIZE]; + + +// play_sample /*fold00*/ +void playSample(const string &file){ + sndFileInfo.format=0; + sndFileFD=sf_open(file.c_str(), SFM_READ, &sndFileInfo); + if(sndFileFD==NULL){ + std::cerr << file << ": can't open, skipping." << std::endl; + return; + } + + playSampleFlag=true; + while(playSampleFlag) sleep(1); + + + sf_close(sndFileFD); +} + +// jackExit /*fold00*/ +void jackExit(void *arg){ + exitFlag=true; +} + + +// jackProcess /*fold00*/ +int jackProcess(jack_nframes_t nframes, void *arg){ + jack_default_audio_sample_t *outLeft=(jack_default_audio_sample_t *) jack_port_get_buffer(jackPortOutLeft, nframes); + jack_default_audio_sample_t *outRight=(jack_default_audio_sample_t *) jack_port_get_buffer(jackPortOutRight, nframes); + if(!playSampleFlag){ + memset(outLeft, 0, sizeof(jack_default_audio_sample_t) * nframes); + memset(outRight, 0, sizeof(jack_default_audio_sample_t) * nframes); + return 0; + } + + // read file in chunks, just as much as it fits into our buffer + jack_nframes_t pos=0; + while(pos1) ? 1 : 0; + for(jack_nframes_t i=0; pos=count) break; + srcPos*=sndFileInfo.channels; + outLeft[pos]=sampleBuffer[srcPos]; + outRight[pos]=sampleBuffer[srcPos+channel]; + } + } + + return 0; +} + +// main /*fold00*/ +int main(int argc, char **argv){ + // read command line options + while(1){ + int option_index=0; + static struct option long_options[]={ + {"help", 0, 0, 'h'}, + {"port", 1, 0, 'p'}, + {"connect", 1, 0, 'c'}, + {"loop", 0, 0, 'l'} + }; + int c=getopt_long(argc, argv, "hp:l", + long_options, &option_index); + if(c==-1) break; + if(c==0) + c=long_options[option_index].val; + + switch(c){ + case 'h': + printf("usage: play_loop [] [ ...]\n"); + printf(" available options are:\n"); + printf(" -h, --help show help\n"); + printf(" -l, --loop loop sample forever\n"); + printf(" -p, --port set name of JACK port\n"); + printf(" -c, --connect set name of JACK port to connect to\n"); + return 0; + case 'l': + loop=true; + break; + case 'p': + port=optarg; + break; + case 'c': + connectPort=optarg; + break; + } + } + + // error handling + if(optind>=argc){ + std::cerr << "no file to play" << std::endl; + return 1; + } + + // save all non-option arguments as filenames + for(;optind::iterator i=files.begin(); i!=files.end(); i++){ + playSample(*i); + } + if(!loop) break; + } + + // cleanup + jack_client_close(jackClient); + + return 0; +} diff --git a/src/track.cpp b/src/track.cpp new file mode 100644 index 0000000..ca21e76 --- /dev/null +++ b/src/track.cpp @@ -0,0 +1,31 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + */ + +// Includes +#include "track.h" + + +// Track +Track::Track(const nframes_t _maxFrames, + const nframes_t _fps): + maxFrames(_maxFrames), + fps(_fps), + numChannels(2) +{ + sampleBufferPtr=new sample_t[maxFrames * numChannels]; +} + + +// ~Track +Track::~Track(){ + delete sampleBufferPtr; +} + + +// getBufferPtr +sample_t *Track::getBufferPtr(){ + return sampleBufferPtr; +} diff --git a/src/track.h b/src/track.h new file mode 100644 index 0000000..5782bac --- /dev/null +++ b/src/track.h @@ -0,0 +1,33 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + * representation of one input or output stereo track + */ + +#ifndef __TRACK_H__ +#define __TRACK_H__ + +#include +#include "types.h" + +class Track{ +public: + Track(const nframes_t maxFrames, + const nframes_t fps); + ~Track(); + + sample_t *getBufferPtr(); + +protected: + const nframes_t maxFrames; + const nframes_t fps; + const unsigned int numChannels; + + SNDFILE *sndFileFDPtr; + SF_INFO sndFileInfo; + + sample_t *sampleBufferPtr; +}; + +#endif diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..6fa341a --- /dev/null +++ b/src/types.h @@ -0,0 +1,15 @@ +/* + * Vocoder + * © 2012 Achim Settelmeier + * + * basic type definitions + */ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +typedef float sample_t; +typedef unsigned int nframes_t; + + +#endif diff --git a/src/vocoder.cpp b/src/vocoder.cpp new file mode 100644 index 0000000..6f700db --- /dev/null +++ b/src/vocoder.cpp @@ -0,0 +1,111 @@ +/* + * Vocoder + * © 2007-2012 Achim Settelmeier + * + */ + +// Includes +#include +#include +#include +#include "vocoder.h" + +// Vocoder +Vocoder::Vocoder(){ + volumeMain=16.0; + setSampleRate(48000); +} + +// init +void Vocoder::init(){ + for(int i=0; ihigh1=sample - b->f * bp->mid1 - bp->low1; + bp->mid1+=bp->high1 * b->c; + bp->low1+=bp->mid1; + + bp->high2=bp->low1 - b->f * bp->mid2 - bp->low2; + bp->mid2+=bp->high2 * b->c; + bp->low2+=bp->mid2; + bp->y=bp->high2 * b->att; +} diff --git a/src/vocoder.h b/src/vocoder.h new file mode 100644 index 0000000..168c92c --- /dev/null +++ b/src/vocoder.h @@ -0,0 +1,62 @@ +/* + * Vocoder + * © 2007-2012 Achim Settelmeier + * + * vocoder core routine + */ + +#ifndef __VOCODER_H__ +#define __VOCODER_H__ + +#include "types.h" + +#define VOCODER_MAXBANDS 16 + + +struct bandpass_t{ + sample_t low1, low2; + sample_t mid1, mid2; + sample_t high1, high2; + sample_t y; +}; + +struct band_t{ + double volumeLeft, volumeRight; + + double freq; + double c; + double f; + double att; + + double oldval; + double decay; + + bandpass_t formant; + bandpass_t carrier; +}; + +class Vocoder{ +public: + Vocoder(); + void process(sample_t *formant, + sample_t *carrier, + sample_t *outLeft, + sample_t *outRight, + const nframes_t nframes); + + void setSampleRate(const nframes_t sampleRate); + void setBandVolume(const unsigned int bandNr, + const double volumeLeft, + const double volumeRight); + +private: + void init(); + static void doBandpass(band_t *b, bandpass_t *bp, sample_t sample); + + band_t bands[VOCODER_MAXBANDS]; + nframes_t sampleRate; + double volumeMain; +}; + + +#endif