Converter.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Converter.h
  3. * Copyright © 2010-2012 HAL, 2012 kbinani
  4. *
  5. * This file is part of vConnect-STAND.
  6. *
  7. * vConnect-STAND is free software; you can redistribute it and/or
  8. * modify it under the terms of the GPL License.
  9. *
  10. * vConnect-STAND 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.
  13. */
  14. #ifndef __vconnect_Converter_h__
  15. #define __vconnect_Converter_h__
  16. //#include <time.h>
  17. //#include <sstream>
  18. //#include <boost/filesystem.hpp>
  19. #include <iostream>
  20. #define BOOST_NO_CXX11_SCOPED_ENUMS
  21. #include <boost/filesystem.hpp>
  22. #undef BOOST_NO_CXX11_SCOPED_ENUMS
  23. #include "TextInputStream.h"
  24. #include "TextOutputStream.h"
  25. #include "vConnectPhoneme.h"
  26. #include "StringUtil.h"
  27. #include "Task.h"
  28. #include "WaveBuffer/WaveBuffer.h"
  29. #include "./utau/Oto.h"
  30. namespace vconnect
  31. {
  32. /**
  33. * UTAU 音源を vConnect-STAND 用の音源に変換するタスク
  34. */
  35. class Converter : public Task
  36. {
  37. public:
  38. Converter( RuntimeOption option )
  39. : Task( option )
  40. {
  41. }
  42. ~Converter()
  43. {
  44. }
  45. /**
  46. * UTAU 音源形式を STAND 音源形式へ変換します. Unicode に対応していない簡易版です.
  47. * @param otoIni 分析する音源の oto.ini へのパス.
  48. * @param dstDir 出力先ディレクトリ名.
  49. * @returns 分析に成功した場合true,それ以外はfalseを返します.
  50. */
  51. void run()
  52. {
  53. namespace fs = boost::filesystem;
  54. string const root_oto_ini = Path::getFullPath(this->option.getInputPath());
  55. string const root_oto_ini_directory = Path::getDirectoryName(root_oto_ini) + Path::getDirectorySeparator();
  56. string encoding = this->option.getEncodingOtoIni();
  57. std::shared_ptr<UtauDB> db = std::make_shared<UtauDB>(root_oto_ini, encoding);
  58. string const destination_directory = this->option.getOutputPath();
  59. copy(root_oto_ini_directory, destination_directory, string("prefix.map"));
  60. copy(root_oto_ini_directory, destination_directory, string("character.txt"));
  61. Oto const* const root_oto = db->getRootOto();
  62. convert(root_oto, destination_directory);
  63. for (size_t i = 0; i < db->getSubDirectorySize(); ++i) {
  64. Oto const* oto = db->getSubDirectoryOto(i);
  65. string const oto_ini = Path::getFullPath(oto->getOtoIniPath());
  66. string const oto_ini_directory = Path::getDirectoryName(oto_ini);
  67. string sub_directory_name = oto_ini_directory.find(root_oto_ini_directory) == 0
  68. ? oto_ini_directory.substr(root_oto_ini_directory.length())
  69. : "";
  70. string destination_sub_directory = Path::combine(destination_directory, sub_directory_name);
  71. boost::system::error_code error;
  72. if (fs::create_directory(destination_sub_directory, error)) {
  73. convert(oto, destination_sub_directory);
  74. }
  75. }
  76. }
  77. private:
  78. void copy(string const& source_directory, string const& destination_directory, std::string const& filename)
  79. {
  80. namespace fs = boost::filesystem;
  81. boost::system::error_code error;
  82. string source = Path::combine(source_directory, filename);
  83. string destination = Path::combine(destination_directory, filename);
  84. if (fs::is_regular_file(source, error) && !fs::is_regular_file(destination)) {
  85. fs::copy_file(source, destination, error);
  86. }
  87. }
  88. void convert(Oto const* const oto, string const& destination_directory)
  89. {
  90. string otoIni = oto->getOtoIniPath();
  91. string sourceDirectory = Path::getDirectoryName(otoIni);
  92. int count = 0;
  93. string encoding = this->option.getEncodingOtoIni();
  94. TextInputStream reader(otoIni, encoding);
  95. string destinationOtoIni = Path::combine(destination_directory, "oto.ini");
  96. TextOutputStream writer(destinationOtoIni, encoding, "\x0D\x0A");
  97. while (reader.ready()) {
  98. string buffer = reader.readLine();
  99. if( buffer.length() == 0 ){
  100. continue;
  101. }
  102. count++;
  103. string line = this->processRecord(buffer, count, sourceDirectory, destination_directory);
  104. if (line.length() > 0) {
  105. writer.writeLine(line);
  106. }
  107. }
  108. writer.close();
  109. reader.close();
  110. }
  111. /**
  112. * 変換元の oto.ini ファイルの1行分のデータを処理する
  113. * @param record 1 行分のデータ
  114. * @param count oto.ini の何行目のデータかを表す
  115. * @param sourceDirectory 変換元音源のディレクトリ
  116. * @param destinationDirectory 変換後の音源の保存ディレクトリ
  117. * @return 変換後の oto.ini ファイルに書きこむ行データ
  118. */
  119. string processRecord( std::string record, int count, string sourceDirectory, string destinationDirectory )
  120. {
  121. vector<string> splitted = StringUtil::explode( "=", record, 2 );
  122. string fileName = splitted[0];
  123. string parametersString = splitted[1];
  124. vector<string> parameters = StringUtil::explode( ",", parametersString );
  125. string alias = parameters[0];
  126. float leftBlank = atof( parameters[1].c_str() );
  127. float fixedLength = atof( parameters[2].c_str() );
  128. float rightBlank = atof( parameters[3].c_str() );
  129. float preUtterance = atof( parameters[4].c_str() );
  130. float voiceOverlap = atof( parameters[5].c_str() );
  131. ostringstream buf;
  132. buf << count << ".vvd";
  133. string vvdName = buf.str();
  134. string line = vvdName + "=" + parametersString;
  135. cerr << "====" << endl;
  136. cerr << "Begin analysis : " << alias << " @ " << fileName << endl;
  137. WaveBuffer waveFile;
  138. string waveFilePath = Path::combine( sourceDirectory, fileName );
  139. if( waveFile.readWaveFile( waveFilePath ) != 1 ){
  140. cout << "error ; can't open the file, " << waveFilePath << endl;
  141. return "";
  142. }
  143. int waveLength = waveFile.getWaveLength( leftBlank, rightBlank );
  144. std::auto_ptr<double> wave_ptr(new double[waveLength]);
  145. double * wave = wave_ptr.get();
  146. waveFile.getWaveBuffer( wave, leftBlank, rightBlank, waveLength );
  147. // 音量の正規化を行う.
  148. long index = (long)(44100.0 * fixedLength / 1000.0);
  149. double sum1 = 0.0;
  150. double sum2 = 0.0;
  151. // 固定長終了位置の音量を得る.
  152. for( int i = index - 1024; 0 <= i && i < index + 1024 && i < waveLength; i++ ){
  153. sum1 += wave[i] * wave[i];
  154. }
  155. // 左ブランク終了位置の音量を得る.
  156. for( int i = 0; i < 2048 && i < waveLength; i++ ){
  157. sum2 += wave[i] * wave[i];
  158. }
  159. // 大きい方が正規化のための音量.
  160. sum1 = max( sum1, sum2 );
  161. sum1 = VOL_NORMALIZE / sqrt( (sum1 / 2048.0) );
  162. for( int i = 0; i < waveLength; i++ ){
  163. wave[i] *= sum1;
  164. }
  165. cerr << " computing wave...." << endl;
  166. clock_t cl = clock();
  167. vConnectPhoneme phoneme;
  168. phoneme.computeWave( wave, waveLength, 44100, 2.0 );
  169. cerr << " Done. Elapsed time = " << (clock() - cl) << "[ms]" << endl;
  170. string vvdFilePath = Path::combine( destinationDirectory, vvdName );
  171. if( phoneme.writePhoneme( vvdFilePath.c_str() ) ){
  172. cerr << "Wrote file : " << vvdFilePath << endl;
  173. }else{
  174. cerr << "Error. Failed to write : " << vvdFilePath << endl;
  175. }
  176. cerr << "====" << endl;
  177. return line;
  178. }
  179. };
  180. }
  181. #endif