commit 06/10/2025

This commit is contained in:
2025-10-06 13:50:00 +07:00
parent cfb38556b5
commit 611745439f
7 changed files with 190 additions and 42 deletions

View File

@@ -11,9 +11,13 @@ import audio.BassEnc.BASS_ENCODE_PCM
import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidString
import com.sun.jna.Memory
import com.sun.jna.Pointer
import commonAudio
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.tinylog.Logger
import java.util.function.BiConsumer
@@ -126,21 +130,28 @@ class AudioPlayer (var samplingrate: Int) {
return result
}
/**
* Writes the audio data from a byte array to a WAV file.
* @param data The byte array containing the audio data.
* @param target The target file name for the WAV file.
* @param callback A BiConsumer that accepts a Boolean indicating success or failure and a String message.
*/
fun WavWriter(data: ByteArray, target: String, callback: BiConsumer<Boolean, String>) {
val source = AudioFileInfo()
source.bytes = data
source.fileName = "In-Memory Data"
val sources = listOf(source)
WavWriter(sources, target, callback)
WavWriter(sources, target, false, callback)
}
/**
* Writes the audio data from the sources to a WAV file.
* @param sources List of AudioFileInfo objects containing the audio data to write.
* @param target The target file name for the WAV file.
* @param withChime If true, adds a chime sound at the beginning and end of the audio.
* @param callback A BiConsumer that accepts a Boolean indicating success or failure and a String message.
*/
fun WavWriter(sources: List<AudioFileInfo>, target: String, callback: BiConsumer<Boolean, String>) {
fun WavWriter(sources: List<AudioFileInfo>, target: String, withChime: Boolean, callback: BiConsumer<Boolean, String>) {
if (sources.isEmpty()) {
callback.accept(false, " Invalid sources")
return
@@ -150,10 +161,10 @@ class AudioPlayer (var samplingrate: Int) {
return
}
val job = CoroutineScope(Dispatchers.Default)
job.launch(CoroutineName("WavWriter $target")) {
val job = CoroutineScope(Dispatchers.IO).launch(CoroutineName("WavWriter $target")) {
bass.BASS_SetDevice(0) // Set to No Sound device for writing
val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, STREAMPROC_PUSH, null)
val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null)
if (streamhandle==0){
callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
return@launch
@@ -164,46 +175,82 @@ class AudioPlayer (var samplingrate: Int) {
callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
return@launch
}
val playresult = bass.BASS_ChannelPlay(streamhandle,false)
if (!playresult) {
bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_StreamFree(streamhandle)
callback.accept(false, "BASS_ChannelPlay failed: ${bass.BASS_ErrorGetCode()}")
return@launch
fun pushData(data: ByteArray): Boolean {
val mem = Memory(data.size.toLong())
mem.write(0, data, 0, data.size)
val pushresult = bass.BASS_StreamPutData(streamhandle, mem, data.size)
if (pushresult==-1){
val errcode = bass.BASS_ErrorGetCode()
println("BASS_StreamPutData failed: $errcode")
}
return pushresult != -1
}
var allsuccess = true
if (withChime){
val chup = commonAudio["chimeup"]
if (chup!=null && chup.isValid()){
if (pushData(chup.bytes)){
println("Chime up pushed")
} else {
allsuccess = false
println("Chime up failed")
}
} else println("Chime Up not valid")
}
sources.forEach { source ->
if (source.isValid()) {
// write the bytes to the stream
val mem = Memory(source.bytes.size.toLong())
mem.write(0, source.bytes, 0, source.bytes.size)
val pushresult = bass.BASS_StreamPutData(streamhandle, mem, source.bytes.size)
if (pushresult == -1) {
Logger.error { "Failed to write data from ${source.fileName} to stream: ${bass.BASS_ErrorGetCode()}" }
if (pushData(source.bytes)){
println("Source ${source.fileName} pushed")
} else {
allsuccess = false
println("Source ${source.fileName} push failed")
}
} else {
allsuccess = false
println("Source ${source.fileName} is not valid")
}
}
if (withChime){
val chdn = commonAudio["chimedown"]
if (chdn!=null && chdn.isValid()){
if (pushData(chdn.bytes)){
println("Chime down pushed")
} else {
allsuccess = false
println("Chime down failed")
}
} else println("Chime Down not valid")
}
// now we wait until the stream is finished
while(bassenc.BASS_Encode_IsActive(encodehandle) == BASS_ACTIVE_PLAYING) {
Thread.sleep(100) // Sleep for a short time to avoid busy waiting
}
val readsize: Long = 1024 * 1024 // read 1 MB at a time
var totalread: Long = 0
do{
val p = Memory(readsize)
val read = bass.BASS_ChannelGetData(streamhandle, p, 4096)
if (read > 0) {
totalread += read
}
} while (read > 0)
println("Finished reading stream data, total $totalread bytes read")
// close the encoding handle
bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_ChannelFree(streamhandle)
if (allsuccess){
callback.accept(true, "WAV file written successfully: $target")
} else {
callback.accept(false, "Failed to write some data to WAV file: $target")
}
}
}