EcritureWav.kt
71 lignes · 2742 octets
package fr.ebii.card2vcf.audio import java.io.File import java.io.RandomAccessFile import java.nio.ByteBuffer import java.nio.ByteOrder /** * Écrit un fichier WAV PCM (16 kHz mono 16 bits par défaut). * * Séparée de [AudioNoteRecorder] pour être testable en JVM pur, sans dépendance Android. * L'en-tête RIFF/fmt/data est réécrit à la clôture avec les tailles exactes. */ class EcritureWav( private val fichier: File, private val frequence: Int = 16_000, ) { private val raf = RandomAccessFile(fichier, "rw") private var octetsData: Long = 0L init { // Réserve 44 octets pour l'en-tête ; sera réécrit à fermer() raf.write(ByteArray(44)) } /** Écrit des échantillons PCM 16 bits signés (little-endian). */ fun ecrireEchantillons(data: ShortArray, longueur: Int) { val buf = ByteArray(longueur * 2) val bb = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN) for (i in 0 until longueur) bb.putShort(data[i]) raf.write(buf) octetsData += longueur * 2L } /** * Finalise l'en-tête WAV et ferme le fichier. * @return Nombre d'octets de données PCM écrits. */ fun fermer(): Long { // 10 min à 16 kHz 16 bits mono ≈ 18,3 Mo — largement sous Int.MAX_VALUE. // La garde protège contre un enregistrement pathologiquement long ou un bug de comptage. check(octetsData <= Int.MAX_VALUE) { "Fichier WAV trop grand : $octetsData octets (max ${Int.MAX_VALUE})" } val tailleData = octetsData.toInt() // tailleFichier = octets après "RIFF"+int32 = 4(WAVE)+8(fmt tag+size)+16(fmt)+8(data tag+size)+data val tailleFichier = tailleData + 36 val canaux = 1 val bitsParEchantillon = 16 val byteRate = frequence * canaux * bitsParEchantillon / 8 val blockAlign = canaux * bitsParEchantillon / 8 val entete = ByteBuffer.allocate(44).order(ByteOrder.LITTLE_ENDIAN) entete.put("RIFF".toByteArray(Charsets.US_ASCII)) entete.putInt(tailleFichier) entete.put("WAVE".toByteArray(Charsets.US_ASCII)) entete.put("fmt ".toByteArray(Charsets.US_ASCII)) entete.putInt(16) // taille du chunk fmt entete.putShort(1) // format PCM entete.putShort(canaux.toShort()) entete.putInt(frequence) entete.putInt(byteRate) entete.putShort(blockAlign.toShort()) entete.putShort(bitsParEchantillon.toShort()) entete.put("data".toByteArray(Charsets.US_ASCII)) entete.putInt(tailleData) raf.seek(0) raf.write(entete.array()) raf.close() return octetsData } }
GitRust