diff --git a/audio-processors/src/commonMain/kotlin/com/eimsound/audioprocessor/Renderer.kt b/audio-processors/src/commonMain/kotlin/com/eimsound/audioprocessor/Renderer.kt index ffa2d131..05c9e39e 100644 --- a/audio-processors/src/commonMain/kotlin/com/eimsound/audioprocessor/Renderer.kt +++ b/audio-processors/src/commonMain/kotlin/com/eimsound/audioprocessor/Renderer.kt @@ -10,7 +10,8 @@ interface Renderable { fun onRenderEnd() } -enum class RenderFormat(val extend: String, val isLossLess: Boolean = true) { +@Suppress("unused") +enum class RenderFormat(val extension: String, val isLossLess: Boolean = true) { WAV("wav"), MP3("mp3", false), FLAC("flac"), diff --git a/daw/src/jvmMain/kotlin/com/eimsound/daw/impl/clips/audio/AudioClipImpl.kt b/daw/src/jvmMain/kotlin/com/eimsound/daw/impl/clips/audio/AudioClipImpl.kt index 38fc1466..9af3e7b8 100644 --- a/daw/src/jvmMain/kotlin/com/eimsound/daw/impl/clips/audio/AudioClipImpl.kt +++ b/daw/src/jvmMain/kotlin/com/eimsound/daw/impl/clips/audio/AudioClipImpl.kt @@ -179,12 +179,17 @@ class AudioClipImpl( val offset = if (playTime < 0) { time = 0 position = 0 + lastPos = -1 (pos.bufferSize + playTime).coerceAtLeast(0).toInt() } else 0 if (tr == null || tr.isDefaultParams) { + if (pos.timeInSamples != lastPos + bufferSize) { + position = time + } target.getSamples(position, offset, bufferSize, buffers) position += bufferSize pauseProcessor.processPause(buffers, offset, bufferSize, pos.timeToPause) + lastPos = pos.timeInSamples return } else if (pos.timeInSamples != lastPos + bufferSize) { position = (time * tr.speedRatio).roundToLong() diff --git a/daw/src/jvmMain/kotlin/com/eimsound/daw/window/dialogs/RenderDialog.kt b/daw/src/jvmMain/kotlin/com/eimsound/daw/window/dialogs/RenderDialog.kt index 2171d8d7..731d38f2 100644 --- a/daw/src/jvmMain/kotlin/com/eimsound/daw/window/dialogs/RenderDialog.kt +++ b/daw/src/jvmMain/kotlin/com/eimsound/daw/window/dialogs/RenderDialog.kt @@ -111,11 +111,11 @@ val ExportDialog = @Composable { }, renderFormat == it, modifier = Modifier.fillMaxWidth() - ) { Text(it.extend) } + ) { Text(it.extension) } } }) { Text( - renderFormat.extend + renderFormat.extension ) } } @@ -183,7 +183,7 @@ val ExportDialog = @Composable { } - if (renderFormat.extend == "flac") { + if (renderFormat.extension == "flac") { Spacer(Modifier.width(10.dp)) Row( verticalAlignment = Alignment.CenterVertically, @@ -231,7 +231,7 @@ val ExportDialog = @Composable { if (filename.isEmpty()) return@Button val renderer = EchoInMirror.bus?.let { JvmRenderer(it) } val curPosition = EchoInMirror.currentPosition - val audioFile = File("./${filename}.${renderFormat.extend}") + val audioFile = File("./${filename}.${renderFormat.extension}") isRendering = true renderStartTime = System.currentTimeMillis() @@ -273,7 +273,7 @@ val ExportDialog = @Composable { Row { if (isRendering && renderProcess < 1f) Text("取消") else if (isRendering && renderProcess >= 1f) Text("确认") - else Text("导出到 $filename.${renderFormat.extend}") + else Text("导出到 $filename.${renderFormat.extension}") } } } diff --git a/dsp/src/commonMain/kotlin/com/eimsound/dsp/data/AudioThumbnail.kt b/dsp/src/commonMain/kotlin/com/eimsound/dsp/data/AudioThumbnail.kt index 27d421aa..189ea555 100644 --- a/dsp/src/commonMain/kotlin/com/eimsound/dsp/data/AudioThumbnail.kt +++ b/dsp/src/commonMain/kotlin/com/eimsound/dsp/data/AudioThumbnail.kt @@ -12,8 +12,8 @@ import kotlinx.coroutines.launch import org.mapdb.DBMaker import org.mapdb.HTreeMap import java.io.File -import java.io.IOException import java.nio.ByteBuffer +import java.nio.ByteOrder import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths @@ -82,16 +82,15 @@ class AudioThumbnail private constructor( } } - @OptIn(DelicateCoroutinesApi::class) - constructor(data: ByteBuffer): this(data.long, data.get().toInt(), data.long, data.float, data.int, data.int) { - GlobalScope.launch(Dispatchers.IO) { - repeat(channels) { - data.get(minTree[it], 1, size) - data.get(maxTree[it], 1, size) - } - buildTree() - modification++ + constructor(data: ByteBuffer): this( + data.order(ByteOrder.LITTLE_ENDIAN).long, data.get().toInt(), data.long, data.float, data.int, data.int + ) { + repeat(channels) { + data.get(minTree[it], 1, size) + data.get(maxTree[it], 1, size) } + buildTree() + modification++ } fun read() { modification } @@ -153,7 +152,7 @@ class AudioThumbnail private constructor( } fun toByteArray(): ByteArray { - val data = ByteBuffer.allocate(29 + channels * size * 2) + val data = ByteBuffer.allocate(29 + channels * size * 2).order(ByteOrder.LITTLE_ENDIAN) .putLong(modifiedTime) // 8 .put(channels.toByte()) // 1 .putLong(lengthInSamples) // 8 @@ -175,11 +174,10 @@ class AudioThumbnail private constructor( } class AudioThumbnailCache( - file: File, private val samplesPerThumbSample: Int = DEFAULT_SAMPLES_PRE_THUMB_SAMPLE + private val file: File, private val samplesPerThumbSample: Int = DEFAULT_SAMPLES_PRE_THUMB_SAMPLE ): AutoCloseable { @Suppress("UNCHECKED_CAST") - private val db = DBMaker.fileDB(file).fileMmapEnableIfSupported().closeOnJvmShutdown().make() - .hashMap("audioThumbnails").expireMaxSize(200).createOrOpen() as HTreeMap + private val db = DBMaker.memoryDB().make().hashMap("audioThumbnails").expireMaxSize(200).createOrOpen() as HTreeMap operator fun get(key: String) = db[key]?.let { AudioThumbnail(ByteBuffer.wrap(it)) } operator fun set(key: String, time: Long = Files.getLastModifiedTime(Paths.get(key)).toMillis(), value: AudioThumbnail) { @@ -211,7 +209,7 @@ class AudioThumbnailCache( ) set(file.toString(), time, value) return value - } catch (e: IOException) { + } catch (e: Throwable) { e.printStackTrace() onComplete?.invoke(e) return null