123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- /*
- This file is part of QTau
- Copyright (C) 2013-2019 Tobias "Tomoko" Platen <tplaten@posteo.de>
- Copyright (C) 2013 digited <https://github.com/digited>
- Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
- QTau 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.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: GPL-3.0+
- */
- // a simple demo synth using the EpR voice model
- // using freqs from https://en.wikipedia.org/wiki/Formant
- #include "epr_synth.h"
- #include <sekai/midi.h>
- #define __devloglevel__ 4
- QString EpRSynth::name() { return "EpR"; }
- QString EpRSynth::description() { return "Based on the Klatt synthesizer"; }
- QString EpRSynth::version() { return "19.04"; }
- bool EpRSynth::synthIsRealtime() { return true; }
- void __devlog__(QString logtype,QString filename,int line,QString msg)
- {
- QString logmsg = logtype+": "+filename.replace("../../","").replace("../","")+":"+QVariant(line).toString()+": "+msg;
- fprintf(stderr,"[synth]%s\n",logmsg.toUtf8().data());
- }
- void EpRSynth::setup(IController* ctrl) {
- this->_ctrl = ctrl;
- this->_jack_samplerate = ctrl->sampleRate();
- connect(this,&EpRSynth::logDebug,this,&EpRSynth::on_logDebug);
- connect(this,&EpRSynth::logError,this,&EpRSynth::on_logError);
- connect(this,&EpRSynth::logSuccess,this,&EpRSynth::on_logSuccess);
- connect(this,&EpRSynth::endOfThread,this,&EpRSynth::on_endOfThread);
- fprintf(stderr,"ringbuffer allocate %i\n",_jack_samplerate);
- _src.gaindb = 40;
- _src.slope = -0.00001;
- _src.slopedepthdb = 77;
- _osc.fs=_jack_samplerate;
- formant fo;
- fo.f1 = 860;
- fo.f2 = 1610;
- _formantMap["a"]=fo;
- fo.f1 = 360;
- fo.f2 = 640;
- _formantMap["o"]=fo;
- fo.f1 = 390;
- fo.f2 = 2300;
- _formantMap["e"]=fo;
- fo.f1 = 240;
- fo.f2 = 2400;
- _formantMap["i"]=fo;
- fo.f1 = 250;
- fo.f2 = 595;
- _formantMap["u"]=fo;
- }
- bool EpRSynth::synthesize(IScore* score)
- {
- _pos = 0;
- _currentNote = 0;
- _stop = false;
- _notes.clear();
- for(int i=0;i<score->getNoteCount();i++)
- {
- auto n = score->getNote(i);
- DEVLOG_DEBUG("note "+STR(i));
- DEVLOG_DEBUG("rest "+STR(n.rest)+" length "+STR(n.lenght));
- noteEvent evt;
- evt.startPos = n.start;
- evt.endPos = n.start+n.lenght;
- evt.f0 = frequencyFromNote(n.pitch);
- evt.fo = _formantMap[n.lyric];
- _notes.push_back(evt);
- }
- return true;
- }
- void EpRSynth::genOneFrame()
- {
- float f0 = 0;
- formant fo;
- if(_stop) return;
- //update EpR on specific timestamps
- float current_time = _pos*1.0/_jack_samplerate;
- if(current_time>_notes[_currentNote].startPos && current_time<_notes[_currentNote].endPos)
- {
- f0 = _notes[_currentNote].f0;
- fo = _notes[_currentNote].fo;
- }
- int nharmonics = 50;
- if(f0){
- _res[0].gain_db = 20;
- _res[0].bw = fo.f1/10.0;
- _res[0].f = fo.f1;
- _res[0].enabled = 1;
- _res[1].gain_db = 20;
- _res[1].bw = fo.f2/10.0;
- _res[1].f = fo.f2;
- _res[1].enabled = 1;
- for(int i=2;i<RES_COUNT;i++)
- {
- _res[i].gain_db = 5;
- _res[i].bw = 10;
- _res[i].f = i*1500;
- _res[i].enabled = 1;
- }
- for(int i=0;i<6;i++)
- {
- EprResonanceUpdate(&_res[i],_osc.fs);
- }
- for(int i=0;i<nharmonics;i++)
- {
- float factor = 0.1;
- float f = f0*(i+1);
- double gain = EprAtFrequency(&_src,f,_osc.fs,_res,RES_COUNT);
- _osc.amp[i] = pow(M_E,(gain/TWENTY_OVER_LOG10))/nharmonics*factor;
- _osc.frq[i] = f;
- }
- }
- else {
- for(int i=0;i<nharmonics;i++)
- {
- _osc.amp[i]=0;
- _osc.frq[i]=0;
- }
- }
- if(current_time>=_notes[_currentNote].endPos)
- {
- _currentNote++;
- if(_currentNote==_notes.count()) _stop=true;
- }
- }
- int EpRSynth::readData(float *data, int size)
- {
- static jack_ringbuffer_t* my_ringbuffer=nullptr;
- int padding = 256;
- if(my_ringbuffer==nullptr)
- {
- my_ringbuffer = jack_ringbuffer_create(4096*16*sizeof(float));
- }
- while(jack_ringbuffer_read_space(my_ringbuffer)<(size+padding)*sizeof(float) && _stop==false )
- {
- genOneFrame();
- _pos += FFT_SIZE/2;
- _osc.processOneFrame();
- float output_buffer[FFT_SIZE/2];
- for(int i=0;i<FFT_SIZE/2;i++)
- {
- output_buffer[i] = _osc.output_buffer[i]*0.9;
- }
- if(jack_ringbuffer_write_space(my_ringbuffer)>FFT_SIZE/2*sizeof(float))
- jack_ringbuffer_write(my_ringbuffer,(char*)output_buffer,FFT_SIZE/2*sizeof(float));
- else
- fprintf(stderr,"buffer full\n");
- }
- if(jack_ringbuffer_read_space(my_ringbuffer)>(size+padding)*sizeof(float))
- {
- jack_ringbuffer_read(my_ringbuffer,(char*)data,size*sizeof(float));
- }
- else
- {
- if(_stop) return 1;
- }
- return 0;
- }
- QString EpRSynth::getTranscription(QString txt)
- {
- return txt;
- }
- bool EpRSynth::doPhonemeTransformation(QStringList& list)
- {
- (void) list;
- return false;
- }
- bool EpRSynth::setVoice(QString voiceName)
- {
- if(voiceName=="Klatt") return true;
- return false;
- }
- QStringList EpRSynth::listVoices()
- {
- QStringList voices;
- voices << "Klatt";
- return voices;
- }
- //??
- void EpRSynth::on_logError(QString error)
- {
- _ctrl->logError(error);
- }
- void EpRSynth::on_logSuccess(QString success)
- {
- _ctrl->logSuccess(success);
- }
- void EpRSynth::on_logDebug(QString debug)
- {
- _ctrl->logDebug(debug);
- }
- void EpRSynth::on_endOfThread()
- {
- }
- bool EpRSynth::setCacheDir(QString cacheDir)
- {
- (void) cacheDir;
- return true;
- }
|