2016-12-15 11 views
0

Я работаю с программой 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, и он отлично работал.

+0

Я думаю, что вы должны быть более откровенными в отношении изменений, которые вы пробовали, и ожидаемого результата. Вы даете нам свою проблему и ожидаете решения путем копирования всего кода. Это также поможет, если вы также выполните некоторые рефакторинги (возможно, даже некоторые OO?) –

+0

убедитесь, что короткий не испортит вещи - я очень рекомендую оставаться с байтами и делать всю обработку с байтами - вы знаете, что вы имеете дело с - без ерунды – gpasch

ответ

0

Проблема была временно решена. Оказывается, что преобразование между массивом byte и массивом short не требуется. Необходимые операции обработки сигналов могут выполняться непосредственно на массивах byte.
Я хотел бы оставить этот вопрос открытым, если кто-то обнаружит ошибку (-ы) в данном коде.