festvox_synth.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. This file is part of QTau
  3. Copyright (C) 2013-2019 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. // FIXME upgrade to mbrola 3 synth (festvox sucks)
  19. #include "festvox_synth.h"
  20. #include "../editor/ustjkeys.h"
  21. #include "QFile"
  22. #include "QTextStream"
  23. #define __devloglevel__ 4
  24. QString FestvoxSynth::name() { return "FestVox"; }
  25. QString FestvoxSynth::description() { return "Daisy Bell - IBM 7094"; }
  26. QString FestvoxSynth::version() { return "19.04"; }
  27. bool FestvoxSynth::synthIsRealtime() { return false; }
  28. void __devlog__(QString logtype,QString filename,int line,QString msg)
  29. {
  30. QString logmsg = logtype+": "+filename.replace("../../","").replace("../","")+":"+QVariant(line).toString()+": "+msg;
  31. fprintf(stderr,"[synth]%s\n",logmsg.toUtf8().data());
  32. }
  33. class FestvoxScore
  34. {
  35. QString xml;
  36. public:
  37. FestvoxScore()
  38. {
  39. xml = "<SINGING BPM=\"60\">\n";
  40. }
  41. void addNote(int noteNum,float length,float rest,QString lyric)
  42. {
  43. QString noteNames[] = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};
  44. int octave = noteNum/12-2;
  45. int step = noteNum % 12;
  46. QString pitch = QString("%1%2").arg(noteNames[step]).arg(octave);
  47. if(rest>0)
  48. xml += QString("\t<REST BEATS=\"%1\"></REST>\n").arg(rest);
  49. xml += QString("\t<DURATION BEATS=\"%1\"><PITCH NOTE=\"%2\">%3</PITCH></DURATION>\n").arg(length).arg(pitch).arg(lyric);
  50. }
  51. QString getScore()
  52. {
  53. xml += "</SINGING>\n";
  54. return xml;
  55. }
  56. };
  57. void FestvoxSynth::setup(IController* ctrl) {
  58. this->_ctrl = ctrl;
  59. this->_jack_samplerate = ctrl->sampleRate();
  60. connect(this,&FestvoxSynth::logDebug,this,&FestvoxSynth::on_logDebug);
  61. connect(this,&FestvoxSynth::logError,this,&FestvoxSynth::on_logError);
  62. connect(this,&FestvoxSynth::logSuccess,this,&FestvoxSynth::on_logSuccess);
  63. connect(this,&FestvoxSynth::endOfThread,this,&FestvoxSynth::on_endOfThread);
  64. }
  65. bool FestvoxSynth::synthesize(IScore* score)
  66. {
  67. FestvoxScore fvox;
  68. DEVLOG_DEBUG("FestvoxSynth::synthesize");
  69. for(int i=0;i<score->getNoteCount();i++)
  70. {
  71. auto n = score->getNote(i);
  72. DEVLOG_DEBUG("note "+STR(i));
  73. DEVLOG_DEBUG("rest "+STR(n.rest)+" length "+STR(n.lenght));
  74. fvox.addNote(n.pitch,n.lenght,n.rest,n.lyric);
  75. }
  76. QFile file("/tmp/festvox.xml");
  77. file.open(QIODevice::WriteOnly | QIODevice::Text);
  78. QTextStream out(&file);
  79. out << fvox.getScore();
  80. file.close();
  81. return false;
  82. /// return true; //will be scheduled if true
  83. }
  84. void FestvoxSynth::synthThread()
  85. {
  86. SF_INFO info;
  87. memset(&info,0,sizeof(info));
  88. info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
  89. info.samplerate = _jack_samplerate;
  90. info.channels = 1;
  91. SNDFILE* sndfile = sf_open("/tmp/festvox_synth.wav",SFM_WRITE,&info);
  92. int data_count = 1024;
  93. float* data = new float[data_count];
  94. while(1)
  95. {
  96. int result = readData(data,data_count);
  97. if(result) break;
  98. sf_write_float(sndfile,data,data_count);
  99. }
  100. sf_close(sndfile);
  101. delete[] data;
  102. emit endOfThread();
  103. }
  104. int FestvoxSynth::readData(float *data, int size)
  105. {
  106. (void)data;
  107. (void)size;
  108. //FIXME
  109. abort();
  110. }
  111. void FestvoxSynth::buildScore()
  112. {
  113. }
  114. QString FestvoxSynth::getTranscription(QString txt)
  115. {
  116. return txt;
  117. }
  118. bool FestvoxSynth::doPhonemeTransformation(QStringList& list)
  119. {
  120. (void) list;
  121. return false;
  122. }
  123. bool FestvoxSynth::setVoice(QString voiceName)
  124. {
  125. if(voiceName=="(voice_kal_diphone)") return true;
  126. return false;
  127. }
  128. QStringList FestvoxSynth::listVoices()
  129. {
  130. QStringList voices;
  131. voices << "(voice_kal_diphone)";
  132. return voices;
  133. }
  134. //??
  135. void FestvoxSynth::on_logError(QString error)
  136. {
  137. _ctrl->logError(error);
  138. }
  139. void FestvoxSynth::on_logSuccess(QString success)
  140. {
  141. _ctrl->logSuccess(success);
  142. }
  143. void FestvoxSynth::on_logDebug(QString debug)
  144. {
  145. _ctrl->logDebug(debug);
  146. }
  147. void FestvoxSynth::on_endOfThread()
  148. {
  149. //_threadRunning = false;
  150. //_ctrl->startOfflinePlayback("/tmp/festvox_synth.wav");
  151. }
  152. bool FestvoxSynth::setCacheDir(QString cacheDir)
  153. {
  154. (void) cacheDir;
  155. return true;
  156. }