Я работаю с программой java (разработанной другими людьми) для синтеза текста в речь. Синтез осуществляется путем конкатенации «ди-телефонов». В исходной версии не было обработки сигналов. Дифоны были просто собраны и объединены вместе для получения выхода. Чтобы улучшить выход, я попытался выполнить «согласование фаз» конкатенирующих речевых сигналов. Модификация, которую я сделал, приводится здесь:Как уменьшить шум в перекрытии сигнала в Java?
- Аудиоданные собираются из AudioInputStream в массив байтов. Поскольку аудиоданные 16 бит, я преобразовал массив байтов в короткий массив .
- «Обработка сигналов» выполняется на коротком массиве.
- Для вывода аудиоданных короткий массив снова преобразуется в массив байтов.
Вот часть кода, который я изменил в существующей программе:
аудиовхода
Этот сегмент называется для каждого дифона.
Original Version
audioInputStream = AudioSystem.getAudioInputStream(sound);
while ((cnt = audioInputStream.read(byteBuffer, 0, byteBuffer.length)) != -1) {
if (cnt > 0) {
byteArrayPlayStream.write(byteBuffer, 0, cnt);
}
}
Моя версия
// public varialbe declarations
byte byteSoundFile[]; // byteSoundFile will contain a whole word or the diphones of a whole word
short shortSoundFile[] = new short[5000000]; // sound contents are taken in a short[] array for signal processing
short shortBuffer[];
int pos = 0;
int previousPM = 0;
boolean isWord = false;
public static HashMap<String, Integer> peakMap1 = new HashMap<String, Integer>();
public static HashMap<String, Integer> peakMap2 = new HashMap<String, Integer>();
// code for receiving and processing audio data
if(pos == 0) {
// a new word is going to be processed.
// so reset the shortSoundFile array
Arrays.fill(shortSoundFile, (short)0);
}
audioInputStream = AudioSystem.getAudioInputStream(sound);
while ((cnt = audioInputStream.read(byteBuffer, 0, byteBuffer.length)) != -1) {
if (cnt > 0) {
byteArrayPlayStream.write(byteBuffer, 0, cnt);
}
}
byteSoundFile = byteArrayPlayStream.toByteArray();
int nSamples = byteSoundFile.length;
byteArrayPlayStream.reset();
if(nSamples > 80000) { // it is a word
pos = nSamples;
isWord = true;
}
else { // it is a diphone
// audio data is converted from byte to short, so nSamples is halved
nSamples /= 2;
// transfer byteSoundFile contents to shortBuffer using byte-to-short conversion
shortBuffer = new short[nSamples];
for(int i=0; i<nSamples; i++) {
shortBuffer[i] = (short)((short)(byteSoundFile[i<<1]) << 8 | (short)byteSoundFile[(i<<1)+1]);
}
/************************************/
/**** phase-matching starts here ****/
/************************************/
int pm1 = 0;
int pm2 = 0;
String soundStr = sound.toString();
if(soundStr.contains("\\") && soundStr.contains(".")) {
soundStr = soundStr.substring(soundStr.indexOf("\\")+1, soundStr.indexOf("."));
}
if(peakMap1.containsKey(soundStr)) {
// perform overlap and add
System.out.println("we are here");
pm1 = peakMap1.get(soundStr);
pm2 = peakMap2.get(soundStr);
/*
Idea:
If pm1 is located after more than one third of the samples,
then threre will be too much overlapping.
If pm2 is located before the two third of the samples,
then where will also be extra overlapping for the next diphone.
In both of the cases, we will not perform the peak-matching operation.
*/
int idx1 = (previousPM == 0) ? pos : previousPM - pm1;
if((idx1 < 0) || (pm1 > (nSamples/3))) {
idx1 = pos;
}
int idx2 = idx1 + nSamples - 1;
for(int i=idx1, j=0; i<=idx2; i++, j++) {
if(i < pos) {
shortSoundFile[i] = (short) ((shortSoundFile[i] >> 1) + (shortBuffer[j] >> 1));
}
else {
shortSoundFile[i] = shortBuffer[j];
}
}
previousPM = (pm2 < (nSamples/3)*2) ? 0 : idx1 + pm2;
pos = idx2 + 1;
}
else {
// no peak found. simply concatenate the audio data
for(int i=0; i<nSamples; i++) {
shortSoundFile[pos++] = shortBuffer[i];
}
previousPM = 0;
}
аудиовыхода
После сбора всех diphones слова, этот сегмент призван играть аудиовыход ,
Original Version
byte audioData[] = byteArrayPlayStream.toByteArray();
... code for writing audioData to output steam
Моя версия
byte audioData[];
if(isWord) {
audioData = Arrays.copyOf(byteSoundFile, pos);
isWord = false;
}
else {
audioData = new byte[pos*2];
for(int i=0; i<pos; i++) {
audioData[(i<<1)] = (byte) (shortSoundFile[i] >>> 8);
audioData[(i<<1)+1] = (byte) (shortSoundFile[i]);
}
}
pos = 0;
... code for writing audioData to output steam
Но после того, как модификация сделал, выход становится хуже. На выходе много шума.
Вот пример аудио с модификацией: modified output
Вот пример аудио из оригинальной версии: original output
Теперь я бы признателен, если кто-нибудь может указать причину, которая генерирует шум и как его удалить. Я делаю что-то неправильно в коде? Я тестировал свой алгоритм в Mablab, и он отлично работал.
Я думаю, что вы должны быть более откровенными в отношении изменений, которые вы пробовали, и ожидаемого результата. Вы даете нам свою проблему и ожидаете решения путем копирования всего кода. Это также поможет, если вы также выполните некоторые рефакторинги (возможно, даже некоторые OO?) –
убедитесь, что короткий не испортит вещи - я очень рекомендую оставаться с байтами и делать всю обработку с байтами - вы знаете, что вы имеете дело с - без ерунды – gpasch