123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- This file is part of QTau
- Copyright (C) 2013-2018 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+
- */
- #include "ecantorix_synth.h"
- #include "../editor/ustjkeys.h"
- #include <QFileInfo>
- #include <QDebug>
- #include <QDir>
- #include <QFile>
- #include <QTextStream>
- #include <QDebug>
- #include <QDirIterator>
- #include <QStringList>
- #include <QJsonDocument>
- #include <math.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <QProcess>
- #include <QtConcurrent/QtConcurrent>
- #include <sndfile.h>
- #include <unistd.h>
- #define __devloglevel__ 4
- //utilityfunctions -- move to libkawaii
- bool fileExists(QString path) {
- QFileInfo check_file(path);
- // check if file exists and if yes: Is it really a file and no directory?
- return check_file.exists() && check_file.isFile();
- }
- //ecantorix synth specific
- /// manifest
- QString eCantorixSynth::name() { return "eCantorix2"; }
- QString eCantorixSynth::description() { return "A multilingual KTH-style singing synthesizer"; }
- QString eCantorixSynth::version() { return "18.04"; }
- /// setup
- void eCantorixSynth::setup(IController* ctrl) {
- this->_ctrl = ctrl;
- this->_jack_samplerate = ctrl->sampleRate();
- //thread queue signaling
- connect(this,&eCantorixSynth::logDebug,this,&eCantorixSynth::on_logDebug);
- connect(this,&eCantorixSynth::logError,this,&eCantorixSynth::on_logError);
- connect(this,&eCantorixSynth::logSuccess,this,&eCantorixSynth::on_logSuccess);
- _voices["Mikulas"]="cs";
- _voices["Lenny"]="m1";
- _voices["Lukas"]="sv";
- _voices["Mika"]="fi";
- }
- /// input
- bool eCantorixSynth::setScore(const QJsonArray &s)
- {
- if(_synthprocess)
- {
- DEVLOG_ERROR("threadRunning - cannot set score");
- return false;
- }
- _score = s;
- return true;
- }
- //have resampling output engine
- bool eCantorixSynth::synthesize()// refactor interace
- {
- if(_synthprocess)
- {
- DEVLOG_ERROR("synthprocess already running\n");
- return false;
- }
- builduScore();
- QString program = "sinsyNG";
- QStringList arguments;
- arguments << "-u" << "/tmp/uscore.sinsy";
- if(_isRealtime)
- {
- arguments << "-q" << "/tmp/sinsy.rbuf";
- _rb = new RingBuffer((char*)"/tmp/sinsy.rbuf",8*1024);
- }
- else
- {
- arguments << "-o" << "/tmp/ecantorix_sinsy.wav";
- }
- _synthprocess = new QProcess(this);
- connect(_synthprocess,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(synthprocess_finished(int,QProcess::ExitStatus)));
- _synthprocess->start(program, arguments);
- usleep(250*1000);
- return true;
- }
- bool eCantorixSynth::setCacheDir(QString cacheDir)
- {
- (void) cacheDir;
- return true;
- }
- void eCantorixSynth::builduScore()
- {
- int lastNoteEnd=0;
- QString uscore;
- uscore += "voice "+_internalVoice+"\n";
- uscore += "resample "+STR(_jack_samplerate)+"\n";
- DEVLOG_DEBUG("jack_samplerate "+STR(_jack_samplerate));
- for (int i = 0; i < _score.count(); ++i)
- {
- auto o = _score[i].toObject();
- if(!o.contains(NOTE_KEY_NUMBER)) {
- //tempo=o[TEMPO].toInt();
- continue;
- }
- //verfy int keyNumber=o[NOTE_KEY_NUMBER].toInt();
- int noteOffset = o[NOTE_PULSE_OFFSET].toInt();
- int noteLength = o[NOTE_PULSE_LENGTH].toInt();
- QString lyric = o[NOTE_LYRIC].toString();
- int notenum = o[NOTE_KEY_NUMBER].toInt();
- int rest = noteOffset-lastNoteEnd;
- if(rest>0)
- {
- uscore += "rest "+STR(rest)+"\n";
- }
- uscore += "note "+STR(noteLength)+" \""+lyric+"\" "+STR(notenum)+" 0 0 0 0 0\n";
- lastNoteEnd = noteOffset+noteLength;
- }
- QFile file("/tmp/uscore.sinsy");
- file.open(QFile::WriteOnly);
- file.write(uscore.toUtf8());
- }
- void eCantorixSynth::synthprocess_finished(int exitCode, QProcess::ExitStatus exitStatus)
- {
- _synthprocess->deleteLater();
- _synthprocess=nullptr;
- DEVLOG_DEBUG("process end "+STR(exitCode)+" "+STR(int(exitStatus)));
- if(!_isRealtime)
- {
- _ctrl->startOfflinePlayback("/tmp/ecantorix_sinsy.wav");
- }
- }
- bool eCantorixSynth::synthIsRealtime()
- {
- return _isRealtime;
- }
- int eCantorixSynth::readData(float *data, int size)
- {
- int data_length=size*sizeof(float);
- memset(data,0,data_length);
- int count = _rb->read((char*)data,data_length);
- if(!_synthprocess && count==0) return 1;
- return 0;
- }
- /// phoneme transformation
- QString eCantorixSynth::getTranscription(QString txt)
- {
- if(txt.split(" [").length()==2)
- return txt;
- QString program = "espeak-ng";
- QStringList arguments;
- arguments << "-v" << _internalVoice;
- arguments << "-x" << txt;
- QProcess myProcess(this);
- myProcess.start(program, arguments);
- if (!myProcess.waitForStarted())
- return txt;
- if (!myProcess.waitForFinished())
- return txt;
- QByteArray result = myProcess.readAll();
- QString tmp = QString::fromUtf8(result.data());
- return txt+"["+tmp+"]";
- }
- bool eCantorixSynth::doPhonemeTransformation(QStringList& list)
- {
- //TODO lyrizer
- DEVLOG_DEBUG(STR(list.count()));
- return false;
- }
- /// voice list (fix this there is only one)
- bool eCantorixSynth::setVoice(QString voiceName)
- {
- if(_voices.keys().contains(voiceName))
- {
- _internalVoice = _voices[voiceName];
- return true;
- }
- else
- {
- _internalVoice = "";
- return false;
- }
- }
- QStringList eCantorixSynth::listVoices()
- {
- return _voices.keys();
- }
- /// logging (helper) (refactor this)
- void eCantorixSynth::on_logDebug(QString debug)
- {
- _ctrl->logDebug(debug);
- }
- void eCantorixSynth::on_logError(QString error)
- {
- _ctrl->logError(error);
- }
- void eCantorixSynth::on_logSuccess(QString success)
- {
- _ctrl->logSuccess(success);
- }
- //remove cacheDir support
- //FIX no sound
|