Exemplo n.º 1
0
void Song::synthesize(VoiceLibrary library, ofstream& file){
	int sampleRate = library.sampleRate;
	fileio::writeWavHeader( sampleRate, file);

	Phone phoneNow = library.getPhone(notes[0]);
	Speech speech = Speech(phoneNow.sample.startToSound(0).compatibleSound(
		vector<float>(phoneNow.overlap*sampleRate,0)
	));//make empty speech to fill.
	for(int note=0;note<notes.size();note++){
		cerr<<notes[note].lyric; //log each lyric
		float leftoverLength = speech.duration -phoneNow.overlap;
		Phone phoneNext;

		if(note+1<notes.size()){
			phoneNext = library.getPhone(notes[note+1]);
		//stretch next note
			if(phoneNext.preutter>notes[note].length/tempo){
				float newPreutter = notes[note].length/tempo;
				float newOverlap = phoneNext.overlap * newPreutter/phoneNext.preutter;
				phoneNext.sample.stretch(0,phoneNext.preutter,newPreutter);
				phoneNext.preutter = newPreutter;
				phoneNext.overlap = newOverlap;
			}
		}else{
			phoneNext = Phone();
			phoneNext.preutter=phoneNext.overlap=0;
		}
		//stretch current note
		float targetLength = notes[note].length/tempo
			-phoneNext.preutter
			+phoneNext.overlap;
		float vowelLength = min(
			notes[note].duration/tempo,
			targetLength
		);
		phoneNow.sample.stretch(
			phoneNow.preutter,
			phoneNow.sample.duration,
			vowelLength
		);
		//add silence between notes if needed
		float restLength = targetLength - vowelLength;
		if(restLength!=0){
			phoneNow.sample.add(
				Speech(phoneNow.sample.startToSound(0).compatibleSound(
					vector<float>(restLength*sampleRate,0)
				)),
				0
			);
		}

		//add modified note to previous speech sample
		speech.add(phoneNow.sample, phoneNow.overlap);
		//transpose
		float noteBoundary = leftoverLength +phoneNow.preutter;
		float writeLength = noteBoundary +notes[note].length/tempo -phoneNext.preutter;
		float freq1,freq2;
		freq2 = freqFromNum(notes[note].notenum);
		if(note!=0){
			freq1 = freqFromNum(notes[note-1].notenum);
		}else{
			freq1 = freq2;
		}
		function<float (float)> frequency = [noteBoundary,freq1,freq2](float time){
			if(time<noteBoundary){
				return freq1;
			}else{
				return freq2;
			}
		};
		speech.transpose(frequency,writeLength);
		//pop&write
		fileio::append(speech.pop(writeLength),file);
		//reassign
		phoneNow = phoneNext;
	}

	fileio::updateWavHeader(file);
}