Lecture d'une partie d'un wav via javasound
Bonjour, je fais une applet qui met en relation du texte et du son, via un XML contenant les mots ainsi que leur timestamps. Ce XML est généré automatiquement.
Code:
<WRD Id="141" Start="79.563" End="80.042" C="500" SRT="maintenir" />
Cela fait quelques jours que je bataille dessus en vain.
Voici le code qui permet de découper mon WAV:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public void readAudioPiece(double start, double stop){
float sampleRate = audioInputStream.getFormat().getSampleRate();
finAudio = (double)audioInputStream.getFrameLength()/sampleRate;
int debutInt=(int)start*22050;
int finInt=(int)Math.min(finAudio,stop+1.0)*22050;
System.out.println("Plage : "+debutInt + " --> "+finInt);
byte[] audioPiece = new byte[finInt-debutInt];
System.arraycopy(audioBytes,debutInt,audioPiece,0,finInt-debutInt);
ByteArrayInputStream bais = new ByteArrayInputStream(audioPiece);
pieceOfAudioInputStream = new AudioInputStream(bais, audioInputStream.getFormat(), audioPiece.length/audioInputStream.getFormat().getFrameSize());
playback.start();
} |
- "start" et "stop" sont les timestamps (79.453 et 80.042 par exemple).
- 22050 correspond au sampleRate * 2, ici en dur.
- debutInt correspond à l'indice dans le tableau de bits du début du mot. finInt correspond à l'indice de fin du mot.
- audioBytes est le tableau de bits correspondant au wav complet.
- la classe playback est celle utilisée dans l'exemple officiel de JavaSound (JavaSoundDemo).
Ce code fonctionne très bien, mais j'arrondis tellement les timestamps qu'au lieu de lire juste le mot, il y a une tolérance qui varie entre 0.01s~0.99s au début et à la fin.
Donc au lieu de lire un mot, dès fois j'en lit 4.
J'ai donc eu une idée, au lieu de tronquer le double ( (int)start ), l'arrondir à la décimale près ( 79.4 par exemple ), car multiplié ensuite par 22050, j'aurais un nombre entier.
J'ai rencontré un soucis à cause de la précision des doubles
Voici donc mon code résultant :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| public void readAudioPiece(double start, double stop){
// Troncage du tableau de bits
float sampleRate = audioInputStream.getFormat().getSampleRate();
finAudio = (double)audioInputStream.getFrameLength() / sampleRate;
//double finDbl=Math.min(finAudio,stop+1.0)*22050.0;
start=uneDecimale(start);
stop=uneDecimale(stop);
System.out.println("Timestamp arr. : "+start+" --> "+stop);
double debutDbl=start*22050.0;
System.out.println("start*22050.0 : "+debutDbl);
// A cause de l'imprécision des doubles, il faut arrondir (ex: 79.6*22050)
DecimalFormat df = new DecimalFormat("0.00" );
String string = df.format(debutDbl);
System.out.println("df.format(debutDbl) : "+string);
string=string.replace(',','.');
System.out.println("string.replace(',','.') : "+string);
float flt= Float.parseFloat(string);
System.out.println("Float.parseFloat(string) : "+flt);
int debutInt=(int)flt;
System.out.println("(int)flt : "+ debutInt);
double finDbl=stop*22050.0;
System.out.println("stop*22050.0 : "+ finDbl);
string = df.format(finDbl);
System.out.println("df.format(finDbl) : "+ string);
string = string.replace(',','.');
System.out.println("string.replace(',','.') : "+ string);
flt= Float.parseFloat(string);
System.out.println("Float.parseFloat(string) : "+ flt);
int finInt=(int)flt;
System.out.println("(int)flt : "+ finInt);
System.out.println("Plage : "+debutInt + " --> "+finInt);
int longueur = finInt-debutInt;
System.out.println("Longueur : "+longueur);
// Création du nouveau tableau de bits qui va contenir juste la partie à lire
byte[] audioPiece = new byte[longueur];
//System.arraycopy(audioBytes,debutInt,audioPiece,0,longueur);
for(int o=0; o<longueur; o++){
audioPiece[o]=audioBytes[debutInt+o];
}
// Lecture
ByteArrayInputStream bais = new ByteArrayInputStream(audioPiece);
pieceOfAudioInputStream = new AudioInputStream(bais, audioInputStream.getFormat(), longueur/audioInputStream.getFormat().getFrameSize());
playback.start();
} |
uneDecimale() retourne un double arrondi à une seule décimale :
Code:
1 2 3 4
| private static double uneDecimale(double value){
double augmentation = Math.pow(10, 1);
return Math.round(value * augmentation) / augmentation;
} |
Avec ce code, j'ai quelques mots qui sont bien lu correctement, mais la plupart sont "bruités" (un bruit très puissant).
Voici ce que dit la console :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| ---------------Gildas---------------
Timestamp : 25.513 --> 26.132
Timestamp arr. : 25.5 --> 26.1
start*22050.0 : 562275.0
df.format(debutDbl) : 562275,00
string.replace(',','.') : 562275.00
Float.parseFloat(string) : 562275.0
(int)flt : 562275
stop*22050.0 : 575505.0
df.format(finDbl) : 575505,00
string.replace(',','.') : 575505.00
Float.parseFloat(string) : 575505.0
(int)flt : 575505
Plage : 562275 --> 575505
Longueur : 13230
---------------activité---------------
Timestamp : 50.895 --> 51.633
Timestamp arr. : 50.9 --> 51.6
start*22050.0 : 1122345.0
df.format(debutDbl) : 1122345,00
string.replace(',','.') : 1122345.00
Float.parseFloat(string) : 1122345.0
(int)flt : 1122345
stop*22050.0 : 1137780.0
df.format(finDbl) : 1137780,00
string.replace(',','.') : 1137780.00
Float.parseFloat(string) : 1137780.0
(int)flt : 1137780
Plage : 1122345 --> 1137780
Longueur : 15435
---------------maintenir---------------
Timestamp : 79.563 --> 80.042
Timestamp arr. : 79.6 --> 80.0
start*22050.0 : 1755179.9999999998
df.format(debutDbl) : 1755180,00
string.replace(',','.') : 1755180.00
Float.parseFloat(string) : 1755180.0
(int)flt : 1755180
stop*22050.0 : 1764000.0
df.format(finDbl) : 1764000,00
string.replace(',','.') : 1764000.00
Float.parseFloat(string) : 1764000.0
(int)flt : 1764000
Plage : 1755180 --> 1764000
Longueur : 8820 |
(Ici, "Gildas" et "activité" sont bruités, pas "maintenir")
Donc la plage à l'air correcte et la longueur aussi.
Merci d'avance de votre aide précieuse !
Bastien.