package com.suno.android.common_data.media.usecase import android.content.ContentResolver import android.net.Uri import java.io.DataOutputStream import javax.inject.Inject import kotlin.time.Duration class TrimWavUseCase @Inject constructor( private val contentResolver: ContentResolver, ) { operator fun invoke( inputFile: Uri, outputFile: Uri, trimTime: ClosedRange, ): Result = runCatching { // Read WAV file header and data val inputStream = contentResolver.openInputStream(inputFile) ?: error("could not open input") // Read WAV header (44 bytes) val header = ByteArray(44) inputStream.read(header) // Calculate bytes per sample and number of channels from header val bitsPerSample = ((header[35].toInt() and 0xFF) shl 8) or (header[34].toInt() and 0xFF) val bytesPerSample = bitsPerSample / 8 val numChannels = ((header[23].toInt() and 0xFF) shl 8) or (header[22].toInt() and 0xFF) val sampleRate = ((header[27].toInt() and 0xFF) shl 24) or ((header[26].toInt() and 0xFF) shl 16) or ((header[25].toInt() and 0xFF) shl 8) or (header[24].toInt() and 0xFF) // Calculate start and end positions in bytes val startByte = ((trimTime.start.inWholeMilliseconds * sampleRate) / 1000) * bytesPerSample * numChannels + 44 val endByte = ((trimTime.endInclusive.inWholeMilliseconds * sampleRate) / 1000) * bytesPerSample * numChannels + 44 val trimmedSize = endByte - startByte // Update data size in header val newDataSize = trimmedSize header[40] = (newDataSize and 0xFF).toByte() header[41] = ((newDataSize shr 8) and 0xFF).toByte() header[42] = ((newDataSize shr 16) and 0xFF).toByte() header[43] = ((newDataSize shr 24) and 0xFF).toByte() // Write trimmed WAV file val outputStream = DataOutputStream(contentResolver.openOutputStream(outputFile) ?: error("could not open output")) // Write header outputStream.write(header) // Skip to start position inputStream.skip(startByte - 44) // Copy trimmed portion val buffer = ByteArray(8192) var bytesRemaining = trimmedSize while (bytesRemaining > 0) { val bytesToRead = minOf(buffer.size.toLong(), bytesRemaining).toInt() val bytesRead = inputStream.read(buffer, 0, bytesToRead) if (bytesRead == -1) break outputStream.write(buffer, 0, bytesRead) bytesRemaining -= bytesRead } inputStream.close() outputStream.close() } }