moved to public git repo

This commit is contained in:
Settel 2023-01-08 16:58:00 +01:00
commit e4f9405f62
24 changed files with 982 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
src/*.o
src/vocoder

16
AUTHORS.md Normal file
View File

@ -0,0 +1,16 @@
# Authors and people who have helped
## idea, main code
Achim Settelmeier <vocoder@m1.sirlab.de>
## ported to LADSPA
Josh Green <jgreen@users.NOSPAM-sourceforge.net>, <br />
available at https://www.sirlab.de/linux/vocoder/
## contributions
Vincent Neuville - ported to jackd 0.116.1

11
COPYRIGHT Normal file
View File

@ -0,0 +1,11 @@
Copyright (C) 2007-2012 Achim Settelmeier <vocoder@m1.sirlab.de>
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.

19
INSTALL.md Normal file
View File

@ -0,0 +1,19 @@
## Requirements
* libsndfile development files<br />
tested with version 1.0.16 and 1.0.31
* GNU C++ compiler<br />
Ubuntu: `g++-12`<br />
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`

11
Makefile Normal file
View File

@ -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

13
README.md Normal file
View File

@ -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 <vocoder@m1.sirlab.de>

BIN
data/carrier.wav Normal file

Binary file not shown.

BIN
data/formant.wav Normal file

Binary file not shown.

40
src/Makefile Normal file
View File

@ -0,0 +1,40 @@
# Settings
CPPFLAGS= -O2 -Wall -W
LFLAGS= -lm -lsndfile
VERSION=$(shell cat VERSION)
CPPFLAGS+= '-DVERSION="$(VERSION)"'
CC=g++
LD=g++
OBJECTS=main.o vocoder.o engine.o track.o inputtrack.o outputtrack.o
.SUFFIXES: .cpp .h .o
.PHONY: all clean libvocoder
# Rules
%.o: %.cpp
$(CC) $(CPPFLAGS) -o $@ -c $<
vocoder: $(OBJECTS)
$(LD) -o $@ $(OBJECTS) $(LFLAGS)
# Tool rules
run:
$(MAKE) vocoder
clean:
rm -f *~ *.bak
rm -f *.o
rm -f vocoder
# Dependencies
main.o: engine.h options.h
vocoder.o: vocoder.h types.h
engine.o: engine.h vocoder.h options.h types.h track.h inputtrack.h outputtrack.h
track.o: track.h types.h
inputtrack.o: track.h inputtrack.h types.h
outputtrack.o: track.h outputtrack.h types.h

1
src/VERSION Normal file
View File

@ -0,0 +1 @@
0.31

111
src/engine.cpp Normal file
View File

@ -0,0 +1,111 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// Includes
#include <string>
#include <iostream>
#include <stdexcept>
#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<VOCODER_MAXBANDS; i++){
vocoderLeft.setBandVolume(i, options.volume, options.volume);
vocoderRight.setBandVolume(i, options.volume, options.volume);
}
while(1){
nframes_t numFramesFormant=formantTrack.readBlock(maxFrames);
if(numFramesFormant==0)
break;
nframes_t numFramesCarrier=carrierTrack.readBlock(numFramesFormant);
if(numFramesCarrier==0)
break;
nframes_t numFramesToProcess=numFramesCarrier;
cout << "processing " << numFramesCarrier << " frames" << endl;
processBlock(formantTrack,
carrierTrack,
outputTrack,
vocoderLeft,
vocoderRight,
numFramesToProcess);
nframes_t numFramesWritten=outputTrack.writeBlock(numFramesToProcess);
if(numFramesWritten!=numFramesToProcess)
throw runtime_error(options.outputFile + ": write error");
// no full block processed? then we're done here
if(numFramesToProcess<maxFrames)
break;
}
}catch(exception &e){
cerr << e.what() << endl;
}
}
void Engine::processBlock(InputTrack &formantTrack,
InputTrack &carrierTrack,
OutputTrack &outputTrack,
Vocoder &vocoderLeft,
Vocoder &vocoderRight,
nframes_t numFramesToProcess){
sample_t *formantBufferPtr=formantTrack.getBufferPtr();
sample_t *carrierBufferPtr=carrierTrack.getBufferPtr();
sample_t *outputBufferPtr=outputTrack.getBufferPtr();
for(nframes_t framePos=0; framePos<numFramesToProcess; framePos++){
sample_t dummySample;
vocoderLeft.process(formantBufferPtr + (framePos * 2),
carrierBufferPtr + (framePos * 2),
outputBufferPtr + (framePos * 2),
&dummySample,
1);
vocoderRight.process(formantBufferPtr + (framePos * 2) + 1,
carrierBufferPtr + (framePos * 2) + 1,
&dummySample,
outputBufferPtr + (framePos * 2) + 1,
1);
}
}

32
src/engine.h Normal file
View File

@ -0,0 +1,32 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* 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

77
src/inputtrack.cpp Normal file
View File

@ -0,0 +1,77 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// Includes
#include <string>
#include <stdexcept>
#include <math.h>
#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<numFrames; dstFrameNr++){
if(sndFileInfo.channels==1){
// mono input
nframes_t srcFrameNr=lround(dstFrameNr / stretchFactor);
sampleBufferPtr[dstFrameNr * 2]=inputBufferPtr[srcFrameNr];
sampleBufferPtr[dstFrameNr * 2 + 1]=inputBufferPtr[srcFrameNr];
}else{
// stereo input
nframes_t srcFrameNr=lround(dstFrameNr / stretchFactor);
sampleBufferPtr[dstFrameNr * 2]=inputBufferPtr[srcFrameNr * 2 ];
sampleBufferPtr[dstFrameNr * 2 + 1]=inputBufferPtr[srcFrameNr * 2 + 1];
}
}
return numFramesAvailable;
}

30
src/inputtrack.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* representation of a stereo input track
*/
#ifndef __INPUTTRACK_H__
#define __INPUTTRACK_H__
#include <string>
#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

86
src/main.cpp Normal file
View File

@ -0,0 +1,86 @@
/*
* Vocoder
* © 2007-2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// Includes
#include <getopt.h>
#include <stdlib.h>
#include <iostream>
#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 <file> -c <file> [-o <file>] [ -v <volume> ]" << endl;
cout << " -f <file> name of input formant WAV file" << endl;
cout << " -c <file> name of input carrier WAV file" << endl;
cout << " -o <file> name of output WAV file" << endl;
cout << " -v <vol> 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;
}

25
src/options.h Normal file
View File

@ -0,0 +1,25 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* structure that stores the command line options
*/
#ifndef __OPTIONS_H__
#define __OPTIONS_H__
#include <string>
#include "types.h"
struct options_t{
std::string formantFile;
std::string carrierFile;
std::string outputFile;
double volume;
nframes_t fps;
};
#endif

43
src/outputtrack.cpp Normal file
View File

@ -0,0 +1,43 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// Includes
#include <string>
#include <stdexcept>
#include <math.h>
#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;
}

28
src/outputtrack.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* representation of a stereo output track
*/
#ifndef __OUTPUTTRACK_H__
#define __OUTPUTTRACK_H__
#include <string>
#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

185
src/play_loop.cpp Normal file
View File

@ -0,0 +1,185 @@
/**
* play_loop
* © 2007 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// Includes /*fold00*/
#include <string.h>
#include <getopt.h>
#include <sndfile.h>
#include <jack/jack.h>
#include <string>
#include <iostream>
#include <list>
using std::string;
using std::cout;
using std::endl;
using std::list;
// Globals /*fold00*/
jack_client_t *jackClient=NULL;
list<string> 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(pos<nframes){
double stretch=sndFileInfo.samplerate/(double)sampleRate;
jack_nframes_t maxcount=int(SAMPLEBUFFERSIZE/sndFileInfo.channels);
if(int((nframes-pos)*stretch)<maxcount) maxcount=int((nframes-pos)*stretch);
sf_count_t count=sf_readf_double(sndFileFD, sampleBuffer, maxcount);
if(count<=0){
// fill the rest of the buffer with silence and set the flag we're done
playSampleFlag=false;
for(; pos<nframes; pos++){
outLeft[pos]=0;
outRight[pos]=0;
}
return 0;
}
// copy sample to output buffer. Does convert sample rates but no interpolation is done
jack_nframes_t channel=(sndFileInfo.channels>1) ? 1 : 0;
for(jack_nframes_t i=0; pos<nframes; i++, pos++){
jack_nframes_t srcPos=int(i*stretch);
if(srcPos>=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 [<options>] <file> [<file> ...]\n");
printf(" available options are:\n");
printf(" -h, --help show help\n");
printf(" -l, --loop loop sample forever\n");
printf(" -p, --port <name> set name of JACK port\n");
printf(" -c, --connect <name> 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<argc; optind++){
files.push_back(argv[optind]);
}
// set up jack client
jackClient=jack_client_new(port.c_str());
if(jackClient==0){
std::cerr << "Can't connect to jack, jack_client_new() failed" << std::endl;
return 1;
}
jack_on_shutdown(jackClient, jackExit, NULL);
jack_set_process_callback(jackClient, jackProcess, NULL);
jackPortOutLeft=jack_port_register(jackClient, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
jackPortOutRight=jack_port_register(jackClient, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
sampleRate=jack_get_sample_rate(jackClient);
if(jack_activate(jackClient)){
std::cerr << "cannot activate client" << std::endl;
jack_client_close(jackClient);
return 1;
}
// main loop: play sample(s)
while(!exitFlag){
for(list<string>::iterator i=files.begin(); i!=files.end(); i++){
playSample(*i);
}
if(!loop) break;
}
// cleanup
jack_client_close(jackClient);
return 0;
}

31
src/track.cpp Normal file
View File

@ -0,0 +1,31 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// 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;
}

33
src/track.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* representation of one input or output stereo track
*/
#ifndef __TRACK_H__
#define __TRACK_H__
#include <sndfile.h>
#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

15
src/types.h Normal file
View File

@ -0,0 +1,15 @@
/*
* Vocoder
* © 2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* basic type definitions
*/
#ifndef __TYPES_H__
#define __TYPES_H__
typedef float sample_t;
typedef unsigned int nframes_t;
#endif

111
src/vocoder.cpp Normal file
View File

@ -0,0 +1,111 @@
/*
* Vocoder
* © 2007-2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
*/
// Includes
#include <string.h>
#include <iostream>
#include <math.h>
#include "vocoder.h"
// Vocoder
Vocoder::Vocoder(){
volumeMain=16.0;
setSampleRate(48000);
}
// init
void Vocoder::init(){
for(int i=0; i<VOCODER_MAXBANDS; i++){
memset(&bands[i], 0, sizeof(band_t));
bands[i].volumeLeft=1.0;
bands[i].volumeRight=1.0;
bands[i].oldval=0.0;
bands[i].decay=1/(100.0+i*10.0);
if(i<4){
bands[i].freq=150+420*i/4.0;
}else{
bands[i].freq=600*pow(1.23,i-4.0);
}
double steps=bands[i].freq/(double)sampleRate;
double c=steps*2*M_PI;
bands[i].c=c*c;
bands[i].f=0.4/c;
bands[i].att=1/(6.0+((exp(steps)-1)*10.0));
bands[i].formant.low1=0.0;
bands[i].formant.low2=0.0;
bands[i].formant.mid1=0.0;
bands[i].formant.mid2=0.0;
bands[i].formant.high1=0.0;
bands[i].formant.high2=0.0;
bands[i].formant.y=0.0;
bands[i].carrier.low1=0.0;
bands[i].carrier.low2=0.0;
bands[i].carrier.mid1=0.0;
bands[i].carrier.mid2=0.0;
bands[i].carrier.high1=0.0;
bands[i].carrier.high2=0.0;
bands[i].carrier.y=0.0;
}
}
// setSampleRate
void Vocoder::setSampleRate(const nframes_t _sampleRate){
if(sampleRate==_sampleRate) return;
sampleRate=_sampleRate;
init();
}
// setBandVolume
void Vocoder::setBandVolume(unsigned int bandNr,
double volumeLeft,
double volumeRight){
bands[bandNr].volumeLeft=volumeLeft;
bands[bandNr].volumeRight=volumeRight;
}
// process
void Vocoder::process(sample_t *formant,
sample_t *carrier,
sample_t *outLeft,
sample_t *outRight,
const nframes_t nframes){
for(nframes_t pos=0; pos<nframes; pos++){
sample_t l=0.0;
sample_t r=0.0;
sample_t x;
for(int i=0; i<VOCODER_MAXBANDS; i++){
Vocoder::doBandpass(&bands[i], &bands[i].formant, formant[pos]);
Vocoder::doBandpass(&bands[i], &bands[i].carrier, carrier[pos]);
bands[i].oldval+=(fabs(bands[i].formant.y)-bands[i].oldval)*bands[i].decay;
x=bands[i].carrier.y*bands[i].oldval;
l+=x*bands[i].volumeLeft;
r+=x*bands[i].volumeRight;
}
outLeft[pos]=l*volumeMain;
outRight[pos]=r*volumeMain;
}
}
// doBandpass
void Vocoder::doBandpass(band_t *b, bandpass_t *bp, sample_t sample){
bp->high1=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;
}

62
src/vocoder.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Vocoder
* © 2007-2012 Achim Settelmeier <vocoder@m1.sirlab.de>
*
* 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