Теперь мне нужно найти момент в аудиофайле, который в данный момент записывается через микрофон.
Я полностью понимаю, что простое сравнение явно не вариант, поскольку звук с микрофона далеко не идентичен аудиофайлу. Я пробовал найти наиболее подходящую часть аудиофайла, используя пики формы сигнала, но это работает не очень хорошо.
Вот как я пытался:
Код: Выделить всё
//record waveform peaks from the microphone
suspend fun getWaveformPeakFromMic(): List {
val sampleRate = 44100
val bufferSize = 882 // 200ms buffer size for more frequent peaks
val duration = calculateBufferDuration(bufferSize, sampleRate)
Log.d("WaveformPeaks", "Buffer duration: $duration")
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.RECORD_AUDIO
) != PackageManager.PERMISSION_GRANTED
) {
return emptyList()
}
val audioRecord = AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize
)
val waveformPeaks = mutableListOf()
val buffer = ShortArray(bufferSize)
audioRecord.startRecording()
lifecycleScope.launch {
delay(5000)
Log.d("WaveformPeaks", "Stopping audio recording")
audioRecord.stop()
audioRecord.release()
}
var read = audioRecord.read(buffer, 0, buffer.size)
while (read > 0) {
val peak = buffer.maxOf { abs(it.toInt()) }
waveformPeaks.add(peak)
read = audioRecord.read(buffer, 0, buffer.size)
}
Log.d("WaveformPeaks", "WaveformPeaks size: ${waveformPeaks.size}")
return waveformPeaks
}
//get waveform peaks from the audio file
fun getWaveformPeaksFromPCM(filePath: String, ): List {
val bufferSize = 882 // 200ms buffer size for more frequent peaks
val waveformPeaks = mutableListOf()
val byteArray = readFileFromAssets(this, filePath)
val shortBuffer = ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer()
val buffer = ShortArray(bufferSize)
while (shortBuffer.hasRemaining()) {
val length = minOf(buffer.size, shortBuffer.remaining())
shortBuffer.get(buffer, 0, length)
val peak = buffer.take(length).maxOf { abs(it.toInt()) }
waveformPeaks.add(peak)
}
Log.d("WaveformPeaks", "WaveformPeaks size: ${waveformPeaks.size}")
return waveformPeaks
}
И вот как я пытался найти совпадение время:
Код: Выделить всё
fun findIndex(full:IntArray, part:IntArray) {
val (bestMatchIndex, likenessCoefficient) = findBestMatch(full, part)
if (bestMatchIndex != -1) {
Log.d("FindMic", "Matching subarray found at position ${bestMatchIndex * 0.02}, likeness coefficient: $likenessCoefficient")
} else {
Log.d("FindMic", "Matching subarray not found")
}
}
fun findBestMatch(full: IntArray, part: IntArray): Pair {
var bestMatchIndex = -1
var bestMatchDistance = Double.POSITIVE_INFINITY
for (i in 0..(full.size - part.size)) {
val subArray = full.sliceArray(i until (i + part.size))
val distance = dtwDistance(subArray, part)
if (distance < bestMatchDistance) {
bestMatchDistance = distance
bestMatchIndex = i
}
}
val likenessCoefficient = 1 / (1 + bestMatchDistance) // Example coefficient calculation
return Pair(bestMatchIndex, likenessCoefficient)
}
fun dtwDistance(seq1: IntArray, seq2: IntArray): Double {
val n = seq1.size
val m = seq2.size
val dtw = Array(n + 1) { DoubleArray(m + 1) { Double.POSITIVE_INFINITY } }
dtw[0][0] = 0.0
for (i in 1..n) {
for (j in 1..m) {
val cost = Math.abs(seq1[i - 1] - seq2[j - 1]).toDouble()
dtw[i][j] = cost + minOf(dtw[i - 1][j], dtw[i][j - 1], dtw[i - 1][j - 1])
}
}
return dtw[n][m]
}
И наконец, вопрос: как мне правильно найти момент времени, воспроизводимый через микрофон? Я открыт для любых способов, включая сторонние библиотеки, внешние сервисы, даже платные, предложения по реализации этого на бэкэнде и т. д.
Подробнее здесь: https://stackoverflow.com/questions/790 ... its-positi
Мобильная версия