2016-12-15 4 views
0

Ich habe mit einem Java-Programm (von anderen Leuten entwickelt) für die Text-zu-Sprache-Synthese gearbeitet. Die Synthese erfolgt durch Verkettung von "Di-Phones". In der ursprünglichen Version gab es keine Signalverarbeitung. Die Diphone wurden nur gesammelt und verkettet, um die Ausgabe zu erzeugen. Um die Ausgabe zu verbessern, habe ich versucht, eine "Phasenanpassung" der verkettenden Sprachsignale durchzuführen. Die von mir vorgenommene Änderung ist hier zusammengefasst:Wie reduziert man Rauschen in Signalüberschneidungen in Java?

  • Audiodaten werden vom AudioInputStream in einem Byte-Array gesammelt. Da die Audiodaten 16 Bit haben, habe ich das Byte-Array in ein kurzes Array konvertiert.
  • Die "Signalverarbeitung" erfolgt auf dem kurzen Array.
  • Um die Audiodaten auszugeben, wird das kurze Array erneut in ein Byte-Array konvertiert.

Hier ist der Teil des Codes, die ich in das bestehende Programm geändert haben:

Audioeingang
Dieses Segment für jedes Diphon genannt wird.

Original Version

audioInputStream = AudioSystem.getAudioInputStream(sound); 
while ((cnt = audioInputStream.read(byteBuffer, 0, byteBuffer.length)) != -1) { 
    if (cnt > 0) { 
     byteArrayPlayStream.write(byteBuffer, 0, cnt); 
    } 
} 

Meine Version

// 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; 
} 

Audioausgang
Nachdem alle Diphone eines Wortes zu sammeln, dieses Segment genannt wird, um die Audioausgabe spielen .
Original Version

byte audioData[] = byteArrayPlayStream.toByteArray(); 
... code for writing audioData to output steam 

Meine Version

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 

Aber nach der Änderung gemacht hat, hat der Ausgang schlechter geworden. Es gibt eine Menge Rauschen in der Ausgabe.

Hier ist ein Beispiel-Audio mit Änderung: modified output

Hier ist ein Beispiel von Audio von der ursprünglichen Version: original output

Jetzt schätzt ich würde es, wenn jemand den Grund kann darauf hinweisen, dass das Rauschen erzeugt und wie man es entfernt. Mache ich etwas falsch im Code? Ich habe meinen Algorithmus in Mablab getestet und es hat gut funktioniert.

+0

Ich denke, Sie sollten etwas expliziter über die Änderungen, die Sie versucht haben, und das Ergebnis, das Sie erwarten. Sie geben uns Ihr Problem und erwarten eine Lösung, indem Sie eine ganze Menge Code kopieren. Es würde auch helfen, wenn Sie einige Refactoring auch durchführen würden (vielleicht sogar einige OO?) –

+0

überprüfen Sie, dass die kurzen Dinge nicht durcheinander bringen - ich empfehle dringend, mit Bytes zu bleiben und die gesamte Verarbeitung mit Bytes - Sie wissen, was Sie beschäftigen mit - kein Unsinn Kurz – gpasch

Antwort

0

Das Problem wurde vorübergehend gelöst. Es stellt sich heraus, dass die Umwandlung zwischen byte Array und short Array nicht notwendig ist. Die erforderlichen Signalverarbeitungsoperationen können direkt an byte Arrays durchgeführt werden.
Ich möchte diese Frage offen lassen, falls jemand den Fehler im angegebenen Code findet.

Verwandte Themen