| 1 |
/* |
| 2 |
* |
| 3 |
* Vocoder.cpp |
| 4 |
* (c) HAL@shurabaP 2012- |
| 5 |
* |
| 6 |
* This class provides the interface to synthesize wave |
| 7 |
* by Vocoder system. |
| 8 |
* |
| 9 |
* These files are distributed in the hope that it will be useful, |
| 10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| 12 |
* |
| 13 |
*/ |
| 14 |
#include "Vocoder.h" |
| 15 |
|
| 16 |
#include "SequenceModel.h" |
| 17 |
#include "SynthesizerExpression.h" |
| 18 |
#include "SynthesizerTrack.h" |
| 19 |
#include "SynthesizerNote.h" |
| 20 |
#include "SynthesizerPhrase.h" |
| 21 |
#include "AbstractCorpus.h" |
| 22 |
|
| 23 |
#include "audio/AudioChunk.h" |
| 24 |
|
| 25 |
#include "../configure.h" |
| 26 |
#include "Utility.h" |
| 27 |
|
| 28 |
using namespace stand::synthesis; |
| 29 |
using namespace stand::model; |
| 30 |
|
| 31 |
Vocoder::Vocoder(AbstractVocoderEngine *engine, AbstractCorpus *corpus, QObject *parent) : |
| 32 |
AbstractSynthesizer(parent) |
| 33 |
{ |
| 34 |
setEngine(engine); |
| 35 |
setCorpus(corpus); |
| 36 |
} |
| 37 |
|
| 38 |
Vocoder::~Vocoder() |
| 39 |
{ |
| 40 |
} |
| 41 |
|
| 42 |
bool Vocoder::synthesize(stand::io::audio::AudioChunk *dst, SynthesizerPhrase *phrase) |
| 43 |
{ |
| 44 |
if(!_engine || !_corpus || !dst || !dst->format().isValid()) |
| 45 |
{ |
| 46 |
return false; |
| 47 |
} |
| 48 |
|
| 49 |
double msCurrent = phrase->msBegin(); |
| 50 |
dst->setMsLength(phrase->msEnd() - phrase->msBegin()); |
| 51 |
dst->clearBufferToZero(); |
| 52 |
|
| 53 |
const QVector<SynthesizerNote *> ¬es = phrase->track()->notes(); |
| 54 |
|
| 55 |
for(int i = 0; i < notes.size(); i++) |
| 56 |
{ |
| 57 |
if(notes[i]->msBegin() < phrase->msBegin()) |
| 58 |
{ |
| 59 |
continue; |
| 60 |
} |
| 61 |
if(notes[i]->msBegin() >= phrase->msEnd()) |
| 62 |
{ |
| 63 |
break; |
| 64 |
} |
| 65 |
|
| 66 |
if(_corpus->contains(AbstractCorpus::Key(notes[i], 0))) |
| 67 |
{ |
| 68 |
// ������������������������������ |
| 69 |
SynthesizerNote *thisNote = notes[i]; |
| 70 |
SynthesizerNote *nextNote = (i + 1 < notes.size()) ? notes[i+1] : NULL; |
| 71 |
|
| 72 |
msCurrent = qMax(msCurrent, thisNote->msBegin() - _corpus->msPreutterance(AbstractCorpus::Key(thisNote, 0.0))); |
| 73 |
|
| 74 |
// ��������������������������������������������������������������������� |
| 75 |
if(nextNote) |
| 76 |
{ |
| 77 |
msCurrent = _synthesizeOneNote(dst, msCurrent, thisNote, nextNote, phrase); |
| 78 |
} |
| 79 |
else |
| 80 |
{ |
| 81 |
msCurrent = _synthesizeOneNote(dst, msCurrent, thisNote, phrase); |
| 82 |
} |
| 83 |
} |
| 84 |
else |
| 85 |
{ |
| 86 |
msCurrent = notes[i]->msEnd(); |
| 87 |
} |
| 88 |
} |
| 89 |
dst->setReadiness(true); |
| 90 |
|
| 91 |
return true; |
| 92 |
} |
| 93 |
|
| 94 |
double Vocoder::_synthesizeOneNote(stand::io::audio::AudioChunk *dst, double msCurrent, SynthesizerNote *current, SynthesizerNote *next, SynthesizerPhrase *phrase) |
| 95 |
{ |
| 96 |
VocoderFrame currentFrame(_engine->info()), nextFrame(_engine->info()); |
| 97 |
|
| 98 |
QVector<QPair<VocoderFrame *, double> > frames; |
| 99 |
frames.resize(2); |
| 100 |
frames[0].first = ¤tFrame; |
| 101 |
frames[1].first = &nextFrame; |
| 102 |
|
| 103 |
double currentActualMs = current->msBegin() - _corpus->msPreutterance(AbstractCorpus::Key(current, 0)); |
| 104 |
double nextActualMs = next->msBegin() - _corpus->msPreutterance(AbstractCorpus::Key(next, 0)); |
| 105 |
double begin = qMax(currentActualMs, nextActualMs); |
| 106 |
double length = current->msEnd() - begin; |
| 107 |
if(length <= 0.0) |
| 108 |
{ |
| 109 |
return _synthesizeOneNote(dst, msCurrent, current, phrase); |
| 110 |
} |
| 111 |
|
| 112 |
while(msCurrent < phrase->msEnd() && msCurrent < current->msEnd()) |
| 113 |
{ |
| 114 |
double f0 = phrase->track()->f0At(msCurrent); |
| 115 |
if(f0 == 0.0) |
| 116 |
{ |
| 117 |
f0 = stand::DefaultF0Value; |
| 118 |
} |
| 119 |
|
| 120 |
AbstractCorpus::Key currentKey(current, msCurrent - current->msBegin()); |
| 121 |
AbstractCorpus::Key nextKey(next, msCurrent - next->msBegin()); |
| 122 |
|
| 123 |
// ��������������������������������������� |
| 124 |
frames[0].second = qMax(0.0, qMin(1.0, 1.0 - (msCurrent - begin) / length)); |
| 125 |
frames[1].second = 1.0 - frames[0].second; |
| 126 |
|
| 127 |
// ��������������������������������������������������� |
| 128 |
if(frames[0].second == 0.0) |
| 129 |
{ |
| 130 |
_corpus->find(¤tFrame, nextKey, _engine); |
| 131 |
} |
| 132 |
else if(frames[0].second == 1.0) |
| 133 |
{ |
| 134 |
_corpus->find(¤tFrame, currentKey, _engine); |
| 135 |
} |
| 136 |
else |
| 137 |
{ |
| 138 |
_corpus->find(¤tFrame, currentKey, _engine); |
| 139 |
_corpus->find(&nextFrame, nextKey, _engine); |
| 140 |
_engine->morph(¤tFrame, frames); |
| 141 |
} |
| 142 |
|
| 143 |
_engine->synthesize(dst, ¤tFrame, dst->samplesAtMsec(msCurrent)); |
| 144 |
msCurrent += 1000.0 / f0;//_engine->samplesForF0(f0); |
| 145 |
} |
| 146 |
return msCurrent; |
| 147 |
} |
| 148 |
|
| 149 |
double Vocoder::_synthesizeOneNote(stand::io::audio::AudioChunk *dst, double msCurrent, SynthesizerNote *current, SynthesizerPhrase *phrase) |
| 150 |
{ |
| 151 |
VocoderFrame currentFrame(_engine->info()); |
| 152 |
while(msCurrent < phrase->msEnd() && msCurrent < current->msEnd()) |
| 153 |
{ |
| 154 |
double f0 = phrase->track()->f0At(msCurrent); |
| 155 |
if(f0 < stand::utility::NoteFrequency(0) || f0 > stand::utility::NoteFrequency(128)) |
| 156 |
{ |
| 157 |
f0 = stand::DefaultF0Value; |
| 158 |
} |
| 159 |
AbstractCorpus::Key key(current, msCurrent - current->msBegin()); |
| 160 |
_corpus->find(¤tFrame, key, _engine); |
| 161 |
_engine->synthesize(dst, ¤tFrame, dst->samplesAtMsec(msCurrent)); |
| 162 |
msCurrent += 1000.0 / f0;//_engine->samplesForF0(f0) / (double)_engine->info().sampleRate() * 1000.0; |
| 163 |
} |
| 164 |
return msCurrent; |
| 165 |
} |
| 166 |
|
| 167 |
|