IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Multimédia Java Discussion :

Lecture d'une partie d'un wav via javasound


Sujet :

Multimédia Java

  1. #1
    Membre confirmé
    Inscrit en
    Avril 2009
    Messages
    88
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Avril 2009
    Messages : 88
    Par défaut 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 Une ligne du XML : Sélectionner tout - Visualiser dans une fenêtre à part
    <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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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.

  2. #2
    Membre confirmé
    Inscrit en
    Avril 2009
    Messages
    88
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Avril 2009
    Messages : 88
    Par défaut
    En fouillant les forums de Sun, j'ai découvert qu'il serait peut-être judicieux d'utiliser un Clip pour lire le fichier plutôt que de passer par une SourceDataLine. Car un Clip possède une méthode pour définir le début de la lecture (soit en frame, soit en microsecondes).

    setFramePosition() où setMicrosecondPosition()

    Je vais me pencher sur cette solution, voir si ça règle mon problème de bruit.

  3. #3
    Membre confirmé
    Inscrit en
    Avril 2009
    Messages
    88
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Avril 2009
    Messages : 88
    Par défaut
    Je viens encore de tomber sur une autre éventuelle solution.

    Citation Envoyé par Sun
    Here's an example of iterating through chunks of data that are read from a stream, writing one chunk at a time to the SourceDataLine for playback:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     // read chunks from a stream and write them to a source data 
        line 
        line.start();
        while (total < totalToRead && !stopped)}
            numBytesRead = stream.read(myData, 0, numBytesToRead);
            if (numBytesRead == -1) break;
            total += numBytesRead; 
            line.write(myData, 0, numBytesRead);
     
        }
    Ce qui revient à lire une partie du AudioInputStream plutôt que de faire comme je faisais c'est-à-dire, convertir le AudioInputStream en tableau de bits, le tronquer, et le repasser en AudioInputStream.

    Je sens que la journée va être longue :]

  4. #4
    Membre confirmé
    Inscrit en
    Avril 2009
    Messages
    88
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Avril 2009
    Messages : 88
    Par défaut
    Je viens de réussir, via l'utilisation d'un Clip.

    L'utilisation de celui-ci est beaucoup plus facile qu'un AudioInputStream !
    Mon code est réduit de quasiment 200 lignes !

    Voici la nouvelle version de la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public void readAudioPiece(double start, double stop){
    		// Convertir les secondes en micro-secondes
    		long microsecStart = (long)(start * 1000.0d * 1000.0d);
    		long microsecStop = (long)(stop * 1000.0d * 1000.0d);
     
    		// Placement du début
    		soundClip.setMicrosecondPosition(microsecStart);
    		soundClip.start();
    		// Attendre jusqu'à atteindre la fin du mot
    		while(soundClip.getMicrosecondPosition() < microsecStop){} // TODO:  Trouver solution non bloquante
    		soundClip.stop();
    		soundClip.setFramePosition(0); // Rembobine
    	}

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment capturer une partie de l'écran (via coordonnées pixel) ?
    Par Chekov dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 01/09/2020, 11h01
  2. Réponses: 5
    Dernier message: 19/11/2009, 12h23
  3. Lecture d'une partie d'un fichier
    Par radahm dans le forum Programmation et administration système
    Réponses: 7
    Dernier message: 16/04/2009, 08h12
  4. Réponses: 2
    Dernier message: 05/06/2006, 13h39
  5. Comment lire une partie du son *.wav
    Par ryosaebafr2000 dans le forum MFC
    Réponses: 5
    Dernier message: 08/06/2005, 16h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo