ecantorix_synth.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. This file is part of QTau
  3. Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
  4. Copyright (C) 2013 digited <https://github.com/digited>
  5. Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
  6. QTau is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. SPDX-License-Identifier: GPL-3.0+
  17. */
  18. #include "ecantorix_synth.h"
  19. #include "../editor/ustjkeys.h"
  20. #include <QFileInfo>
  21. #include <QDebug>
  22. #include <QDir>
  23. #include <QFile>
  24. #include <QTextStream>
  25. #include <QDebug>
  26. #include <QDirIterator>
  27. #include <QStringList>
  28. #include <QJsonDocument>
  29. #include <math.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <QProcess>
  33. #include <QtConcurrent/QtConcurrent>
  34. #include <sndfile.h>
  35. #include <unistd.h>
  36. #include <sekai/midi.h>
  37. #include <assert.h>
  38. #define __devloglevel__ 4
  39. //utilityfunctions -- move to libkawaii
  40. bool fileExists(QString path) {
  41. QFileInfo check_file(path);
  42. // check if file exists and if yes: Is it really a file and no directory?
  43. return check_file.exists() && check_file.isFile();
  44. }
  45. //ecantorix synth specific
  46. /// manifest
  47. QString eCantorixSynth::name() { return "eCantorix2"; }
  48. QString eCantorixSynth::description() { return "A multilingual KTH-style singing synthesizer"; }
  49. QString eCantorixSynth::version() { return "18.04"; }
  50. /// setup
  51. void eCantorixSynth::setup(IController* ctrl) {
  52. this->_ctrl = ctrl;
  53. this->_jack_samplerate = ctrl->sampleRate();
  54. _wavtool.setOutputRate(this->_jack_samplerate);
  55. //thread queue signaling
  56. connect(this,&eCantorixSynth::logDebug,this,&eCantorixSynth::on_logDebug);
  57. connect(this,&eCantorixSynth::logError,this,&eCantorixSynth::on_logError);
  58. connect(this,&eCantorixSynth::logSuccess,this,&eCantorixSynth::on_logSuccess);
  59. // _voices["Mikulas"]="cs";
  60. _voices["Kurogane"]="en1";
  61. _voices["Anna"]="de1";
  62. // _voices["Lukas"]="sv";
  63. // _voices["Mika"]="fi";
  64. _phoTypes["a"]={0,VOWEL};
  65. _phoTypes["A"]={0,VOWEL};
  66. _phoTypes["{"]={0,VOWEL};
  67. _phoTypes["6"]={0,VOWEL};
  68. _phoTypes["q"]={0,VOWEL};
  69. _phoTypes["Q"]={0,VOWEL};
  70. _phoTypes["e"]={0,VOWEL};
  71. _phoTypes["E"]={0,VOWEL};
  72. _phoTypes["@"]={0,VOWEL};
  73. _phoTypes["3"]={0,VOWEL};
  74. _phoTypes["i"]={0,VOWEL};
  75. _phoTypes["I"]={0,VOWEL};
  76. _phoTypes["o"]={0,VOWEL};
  77. _phoTypes["O"]={0,VOWEL};
  78. _phoTypes["O:"]={0,VOWEL};
  79. _phoTypes["2"]={0,VOWEL};
  80. _phoTypes["9"]={0,VOWEL};
  81. _phoTypes["&"]={0,VOWEL};
  82. _phoTypes["u"]={0,VOWEL};
  83. _phoTypes["U"]={0,VOWEL};
  84. _phoTypes["}"]={0,VOWEL};
  85. _phoTypes["v"]={0,VOWEL};
  86. _phoTypes["V"]={0,VOWEL};
  87. _phoTypes["y"]={0,VOWEL};
  88. _phoTypes["Y"]={0,VOWEL};
  89. _phoTypes["p"]={100,HCONSONANT};
  90. _phoTypes["b"]={80,VCONSONANT};
  91. _phoTypes["t"]={100,HCONSONANT};
  92. _phoTypes["d"]={80,VCONSONANT};
  93. _phoTypes["k"]={100,HCONSONANT};
  94. _phoTypes["g"]={80,VCONSONANT};
  95. _phoTypes["pf"]={160,HCONSONANT};
  96. _phoTypes["ts"]={160,HCONSONANT};
  97. _phoTypes["tS"]={160,HCONSONANT};
  98. _phoTypes["f"]={50,HCONSONANT};
  99. _phoTypes["v"]={50,VCONSONANT};
  100. _phoTypes["s"]={60,HCONSONANT};
  101. _phoTypes["z"]={60,VCONSONANT};
  102. _phoTypes["S"]={60,HCONSONANT};
  103. _phoTypes["Z"]={60,VCONSONANT};
  104. _phoTypes["C"]={60,HCONSONANT};
  105. _phoTypes["j"]={60,VCONSONANT};
  106. _phoTypes["x"]={700,VCONSONANT};
  107. _phoTypes["h"]={100,HCONSONANT};
  108. _phoTypes["m"]={60,NASAL};
  109. _phoTypes["n"]={60,NASAL};
  110. _phoTypes["N"]={60,NASAL};
  111. _phoTypes["l"]={60,LIQUID};
  112. _phoTypes["R"]={60,LIQUID};
  113. }
  114. bool eCantorixSynth::setCacheDir(QString cacheDir)
  115. {
  116. //FIX this
  117. DEVLOG_DEBUG("cacheDir: "+cacheDir);
  118. return true;
  119. }
  120. bool eCantorixSynth::synthIsRealtime()
  121. {
  122. return false;
  123. }
  124. void eCantorixSynth::lookupPho(QString pho)
  125. {
  126. phoEvent e;
  127. e.type = _phoTypes[pho];
  128. e.symbol = pho;
  129. _eventList.push_back(e);
  130. }
  131. void eCantorixSynth::lyricize(QString lyric)
  132. {
  133. _eventList.clear();
  134. _wavtool.clear();
  135. bool inPho=false;
  136. QString pho;
  137. for(int i = 0; i< lyric.length(); i++)
  138. {
  139. QString i0 = lyric.at(i);
  140. if(i0=="["){
  141. inPho=true;
  142. continue;
  143. }
  144. if(i0=="]"){
  145. inPho=false;
  146. continue;
  147. }
  148. if(inPho)
  149. {
  150. pho+=i0;
  151. }
  152. }
  153. QStringList phoList = pho.split(" ");
  154. for(int i=0;i<phoList.count();i++)
  155. {
  156. pho = phoList[i];
  157. lookupPho(pho);
  158. //lookup pho, store result in list
  159. }
  160. }
  161. float eCantorixSynth::getPreutter()
  162. {
  163. int preutter=0;
  164. for(int i=0;i<_eventList.count();i++)
  165. {
  166. phoEvent e=_eventList[i];
  167. preutter += e.type.defaultLength;
  168. //DEVLOG_DEBUG("l: "+e.symbol);
  169. if(e.type.defaultLength==0) break;
  170. }
  171. return 0.001*preutter;
  172. }
  173. QString genPitch(float pitch)
  174. {
  175. int p=pitch;
  176. return "0 "+STR(p)+ " 100 "+STR(p);
  177. }
  178. bool eCantorixSynth::synthesize(IScore *score)
  179. {
  180. _notes.clear();
  181. for(int i=0;i<score->getNoteCount();i++)
  182. {
  183. auto n = score->getNote(i);
  184. //DEVLOG_DEBUG("note "+STR(i));
  185. //DEVLOG_DEBUG("rest "+STR(n.rest)+" length "+STR(n.lenght));
  186. lyricize(n.lyric);
  187. eCantorixNote en;
  188. en.vstart=n.start;
  189. en.rlength=n.lenght;
  190. en.f0=frequencyFromNote(n.pitch);
  191. en.preutter = getPreutter();
  192. DEVLOG_DEBUG("preutter "+STR(en.preutter));
  193. en.eventList= _eventList;
  194. _notes.push_back(en);
  195. }
  196. for(int i=1;i<score->getNoteCount();i++)
  197. {
  198. float a = _notes[i-1].vstart + _notes[i-1].rlength;
  199. float b = _notes[i].vstart - _notes[i].preutter;
  200. if(b<a)
  201. {
  202. _notes[i-1].rlength -= _notes[i].preutter;
  203. }
  204. }
  205. for(int i=0;i<score->getNoteCount();i++)
  206. {
  207. _eventList = _notes[i].eventList;
  208. float f0 = _notes[i].f0;
  209. float fixedLength=0;
  210. int zeros=0;
  211. DEVLOG_DEBUG("rlength: "+STR(_notes[i].rlength));
  212. for(int j=0;j<_eventList.count();j++)
  213. {
  214. phoEvent e=_eventList[j];
  215. fixedLength += e.type.defaultLength;
  216. if(e.type.defaultLength==0) zeros++;
  217. }
  218. fixedLength /= 1000.0;
  219. float totalLength = _notes[i].preutter+_notes[i].rlength;
  220. if(totalLength>fixedLength && zeros>0)
  221. {
  222. QString pho;
  223. for(int j=0;j<_eventList.count();j++)
  224. {
  225. phoEvent e=_eventList[j];
  226. int len = e.type.defaultLength;
  227. bool sustained=false;
  228. if(len==0)
  229. {
  230. len=(totalLength-fixedLength)*1000/zeros;
  231. sustained=true;
  232. }
  233. int lmax=150;
  234. if(sustained && len>lmax)
  235. {
  236. int len2 = len % lmax;
  237. int len3 = len2/2;
  238. int count = len/lmax;
  239. len2-=len3;
  240. DEVLOG_DEBUG("len2 "+STR(len2));
  241. DEVLOG_DEBUG("len3 "+STR(len3));
  242. DEVLOG_DEBUG("count "+STR(count));
  243. assert(count*lmax+len2+len3==len);
  244. pho += e.symbol;
  245. pho += "\t";
  246. pho += STR(len2);
  247. pho += "\t";
  248. pho += genPitch(f0);
  249. pho += "\n";
  250. for(int k=0;k<count;k++)
  251. {
  252. pho += e.symbol;
  253. pho += "\t";
  254. pho += STR(lmax);
  255. pho += "\t";
  256. pho += genPitch(f0);
  257. pho += "\n";
  258. }
  259. pho += e.symbol;
  260. pho += "\t";
  261. pho += STR(len3);
  262. pho += "\t";
  263. pho += genPitch(f0);
  264. pho += "\n";
  265. }
  266. else
  267. {
  268. pho += e.symbol;
  269. pho += "\t";
  270. pho += STR(len);
  271. pho += "\t";
  272. pho += genPitch(f0);
  273. pho += "\n";
  274. }
  275. }
  276. _notes[i].mbrolaPho = pho;
  277. }
  278. }
  279. DEVLOG_DEBUG("voice "+_internalVoice);
  280. QString cacheDir="/tmp/ecantorix_mbrola_"+_internalVoice;
  281. QDir dir(cacheDir);
  282. if (!dir.exists())
  283. dir.mkpath(".");
  284. chdir(cacheDir.toUtf8());
  285. for(int i=0;i<score->getNoteCount();i++)
  286. {
  287. QString basename = STR(i) +"_"+ QString(QCryptographicHash::hash(_notes[i].mbrolaPho.toUtf8(),QCryptographicHash::Md5).toHex());
  288. //DEVLOG_DEBUG("send_to_mbrola\n"+_notes[i].mbrolaPho);
  289. DEVLOG_DEBUG("basename \n"+basename);
  290. {
  291. QString phoFileName = basename+".pho";
  292. QString wavFileName = basename+".wav";
  293. QString tmpFileName = STR(i)+".wav";
  294. QFile file (phoFileName);
  295. if(file.open(QIODevice::WriteOnly))
  296. {
  297. QTextStream outstream(&file);
  298. outstream << _notes[i].mbrolaPho;
  299. }
  300. else
  301. abort();
  302. QString voice = "/home/isengaara/Hacking/Audio/ecantorix-sinsy-ng/mbrola-voices/data/"+_internalVoice+"/"+_internalVoice;
  303. QString mbrola = "mbrola -e "+voice+" "+phoFileName+" "+wavFileName+" 2> mbrola.log";
  304. DEVLOG_DEBUG(mbrola);
  305. system(mbrola.toUtf8());
  306. QFile logfile("mbrola.log");
  307. if(logfile.open(QIODevice::ReadOnly))
  308. {
  309. QTextStream instream(&logfile);
  310. QString text;
  311. do
  312. {
  313. text = instream.readLine();
  314. emit logError(text);
  315. } while(text.length());
  316. }
  317. else
  318. abort();
  319. _wavtool.addNote(wavFileName.toUtf8(),_notes[i].vstart-_notes[i].preutter,_notes[i].preutter+_notes[i].rlength);
  320. //agc(,tmpFileName.toUtf8());
  321. }
  322. //store pho files in cache dir
  323. }
  324. _wavtool.mix();
  325. _ctrl->startOfflinePlayback("/tmp/wavtool.wav");
  326. return true;
  327. }
  328. int eCantorixSynth::readData(float *data, int size)
  329. {
  330. abort();
  331. (void)data;
  332. return size;
  333. }
  334. /// phoneme transformation
  335. QString eCantorixSynth::getTranscription(QString txt)
  336. {
  337. return txt;
  338. }
  339. bool eCantorixSynth::doPhonemeTransformation(QStringList& list)
  340. {
  341. //TODO lyrizer
  342. DEVLOG_DEBUG(STR(list.count()));
  343. return false;
  344. }
  345. /// voice list (fix this there is only one)
  346. bool eCantorixSynth::setVoice(QString voiceName)
  347. {
  348. if(_voices.keys().contains(voiceName))
  349. {
  350. _internalVoice = _voices[voiceName];
  351. return true;
  352. }
  353. else
  354. {
  355. _internalVoice = "";
  356. return false;
  357. }
  358. }
  359. QStringList eCantorixSynth::listVoices()
  360. {
  361. return _voices.keys();
  362. }
  363. /// logging (helper) (refactor this)
  364. void eCantorixSynth::on_logDebug(QString debug)
  365. {
  366. _ctrl->logDebug(debug);
  367. }
  368. void eCantorixSynth::on_logError(QString error)
  369. {
  370. _ctrl->logError(error);
  371. }
  372. void eCantorixSynth::on_logSuccess(QString success)
  373. {
  374. _ctrl->logSuccess(success);
  375. }
  376. //remove cacheDir support
  377. //FIX no sound