Bonjour à tous,
Après pas mal de recherches sur le net sur le sujet, j'ai pu valider un script permettant de "mixer" 2 flux audio. L'objectif est relativement simple : à partir de 2 fichiers audios encodés de manière identique (fichiers wav, 8KHz, 8 bits, mono) et correspondant pour l'un à des paroles et pour l'autre à une musique de fond, être capable d'écrire dans un 3ème fichier le son résultant du "mixage" des 2. Sachant que l'un des postulats de départ est que le second fichier contenant la musique est toujours plus long que le 1er contenant les paroles, on ne conserve qu'une partie de ce second fichier pour le "mixage" des flux (dont la longueur est identique au 1er).
Je fais pour cela appel à la bibliothèque java MixingAudioInputStream accessible ici.
Voila le code en question qui fonctionne parfaitement (même si ce n'est pas le plus propre qui existe... je suis loin d'être un vrai développeur ) :
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
/**
* Write a description of class main here.
*
* @author (your name)
* @version (a version number or a date)
*/
import java.io.*;
import java.io.FileInputStream;
import java.util.List;
import javax.sound.sampled.*;
public class main
{
public static void main(String arg[ ]) {
try {
// Déclaration des variables utilisées pour le mixage des flux audio
File file1 = new File(arg[0]);
File file2 = new File(arg[1]);
InputStream part1 = new FileInputStream(file1);
InputStream part2 = new FileInputStream(file2);
AudioFormat formatAudio = null;
List audioInputStreamList = new java.util.ArrayList();
AudioInputStream ais1 = null;
AudioInputStream ais2 = null;
AudioInputStream aisTemp = null;
// Déclaration des fichiers
File fichierTemp = File.createTempFile("wav", "tmp");
File f = new File("C:/Users/julien.laffitte/final.wav");
f.setWritable(true);
// Récupération du format audio dans lequel sont enregistrés les prompts
AudioFileFormat formatFichierAudio = AudioSystem.getAudioFileFormat(new BufferedInputStream(part1));
AudioFileFormat.Type targetType = formatFichierAudio.getType();
// Création du 1er flux de type "AudioInputStream" utilisé dans la reconstruction
ais1 = AudioSystem.getAudioInputStream(file1);
// Récupération du format audio dans lequel sont enregistrés les prompts
formatAudio = ais1.getFormat();
// Création d'un flux temporaire de type "AudioInputStream" utilisé dans la reconstruction à partir de la bande son
aisTemp = AudioSystem.getAudioInputStream(file2);
// Récupération de la longueur du fichier audio énonçant les horaires
byte[] bufferTemp = new byte[(int)ais1.getFrameLength()];
int nbOctetsLus = aisTemp.read(bufferTemp, 0, bufferTemp.length);
// Création du 2nd flux de type "AudioInputStream" utilisé dans la reconstruction : il est coupé à la même durée que le 1er fichier
ByteArrayInputStream baisTemp = new ByteArrayInputStream(bufferTemp);
ais2 = new AudioInputStream(baisTemp, formatAudio, bufferTemp.length/formatAudio.getFrameSize());
// Ajout des flux dans une liste
audioInputStreamList.add(ais1);
audioInputStreamList.add(ais2);
// Appel de la classe permettant le mixage des flux contenu dans la liste, et dont le format est spécifié en paramètre
MixingAudioInputStream mixer = new MixingAudioInputStream(formatAudio, audioInputStreamList);
System.out.println("Mixage OK.\n");
System.out.println("Format fichier audio Part1 : " + formatFichierAudio.toString());
System.out.println("Format fichier Part2 : " + ais1.getFormat().toString());
System.out.println("Format fichier Part2 : " + ais2.getFormat().toString());
System.out.println("Format fichier Final : " + mixer.getFormat().toString());
try {
// Ecriture du flux résultant dans un fichier
javax.sound.sampled.AudioSystem.write(mixer, formatFichierAudio.getType(), f);
}
catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
}
}
catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
System.err.println("Cause: " + e.getCause());
System.err.println("toString: " + e.toString());
}
}
} |
Le seul souci qui peut arriver ici est que le volume du fond sonore soit un peu fort par rapport aux paroles et vienne les masquer ou en gêne l'écoute.
J'ai donc cherché à améliorer le code pour réduire le volume automatiquement selon une certaine valeur : j'ai trouvé pour cela la bibliothèque AmplitudeAudioInputStream qui est accessible ici.
Voila le code que j'ai ajouté pour réaliser cette opération :
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
|
[...]
// Création du 2nd flux de type "AudioInputStream" utilisé dans la reconstruction : il est coupé à la même durée que le 1er fichier
ByteArrayInputStream baisTemp = new ByteArrayInputStream(bufferTemp);
ais2 = new AudioInputStream(baisTemp, formatAudio, bufferTemp.length/formatAudio.getFrameSize());
// Création d'un 3ème flux de type "AudioInputStream" dont le volume a été réduit en utilisant le float passé en paramètre de setAmplitudeLinear
org.tritonus.dsp.ais.AmplitudeAudioInputStream amplifiedAudioInputStream = new org.tritonus.dsp.ais.AmplitudeAudioInputStream(ais2, ais2.getFormat());
amplifiedAudioInputStream.setAmplitudeLinear(0.4f);
ais3 = AudioSystem.getAudioInputStream(ais2.getFormat(), amplifiedAudioInputStream);
System.out.println("Réduction volume OK.\n");
// Ajout des flux dans une liste
audioInputStreamList.add(ais1);
audioInputStreamList.add(ais3);
// Appel de la classe permettant le mixage des flux contenu dans la liste, et dont le format est spécifié en paramètre
MixingAudioInputStream mixer = new MixingAudioInputStream(formatAudio, audioInputStreamList);
System.out.println("Mixage OK.\n");
System.out.println("Format fichier audio Part1 : " + formatFichierAudio.toString());
System.out.println("Format fichier Part2 : " + ais1.getFormat().toString());
System.out.println("Format fichier Part2 : " + ais2.getFormat().toString());
System.out.println("Format fichier Final : " + mixer.getFormat().toString());
try {
// Ecriture du flux résultant dans un fichier
javax.sound.sampled.AudioSystem.write(mixer, formatFichierAudio.getType(), f);
}
catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
}
}
catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
System.err.println("Cause: " + e.getCause());
System.err.println("toString: " + e.toString());
}
}
} |
Or ce code ne fonctionne pas, l'erreur suivante remonte systématiquement à l'exécution :
could not write audio file: file type not supported: WAVE; nested exception is: java.lang.IllegalArgumentException: could not write audio file: file type not supported: WAVE
L'erreur semble indiquer qu'il y a un problème de format, or je valide bien que les formats des différents flux audio sont identiques en les affichant.
En cherchant j'ai pu mettre le doigt sur la ligne qui pose souci : il s'agit du write à la toute fin du code, qui pourtant fonctionne parfaitement lorsque je n'essaie pas de réduire le volume.
Est ce que vous auriez une piste pour résoudre ce problème ?
Merci de votre aide !
Partager