commit 07/10/2025

This commit is contained in:
2025-10-07 09:28:48 +07:00
parent a8e5b027ef
commit 748301a5cb
5 changed files with 114 additions and 103 deletions

View File

@@ -1,5 +1,5 @@
import audio.AudioFileInfo
import audio.AudioPlayer import audio.AudioPlayer
import audio.ContentCache
import audio.UDPReceiver import audio.UDPReceiver
import barix.BarixConnection import barix.BarixConnection
import barix.TCP_Barix_Command_Server import barix.TCP_Barix_Command_Server
@@ -43,11 +43,8 @@ val urutan_bahasa = listOf(
Language.ARABIC.name Language.ARABIC.name
) )
/**
* Common audio files, seperti chimeup, chimedown, silence1s, silencehalf
*/
val commonAudio : MutableMap<String, AudioFileInfo> = HashMap()
val contentCache = ContentCache()
/** /**
* Create necessary folders if not exist * Create necessary folders if not exist
*/ */
@@ -75,7 +72,7 @@ fun files_preparation(){
if (afi.isValid()){ if (afi.isValid()){
Logger.info { "Common audio $it loaded from ${pp.toAbsolutePath()}" } Logger.info { "Common audio $it loaded from ${pp.toAbsolutePath()}" }
val key = it.substring(0, it.length - 4) // buang .wav val key = it.substring(0, it.length - 4) // buang .wav
commonAudio[key] = afi contentCache.addAudioFile(key, afi)
} else { } else {
Logger.error { "Failed to load common audio $it from ${pp.toAbsolutePath()}" } Logger.error { "Failed to load common audio $it from ${pp.toAbsolutePath()}" }
} }

View File

@@ -553,11 +553,16 @@ class MainExtension01 {
if (qp.Source == "PAGING") { if (qp.Source == "PAGING") {
// nama file ada di Message // nama file ada di Message
if (ValidFile(qp.Message)) { if (ValidFile(qp.Message)) {
// file ketemu di path
val afi = audioPlayer.LoadAudioFile(qp.Message) val afi = audioPlayer.LoadAudioFile(qp.Message)
zz.forEach { z1 -> if (afi.isValid()){
StreamerOutputs.values.find { it.channel == z1 } // file bisa di load, kirim ke masing masing Streamer Output by IP address
?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) }) ips.forEach {
ip ->
val br = StreamerOutputs[ip]
br?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) })
} }
val logmessage = val logmessage =
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}" "Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
Logger.info { logmessage } Logger.info { logmessage }
@@ -573,6 +578,15 @@ class MainExtension01 {
"Cancelled paging message with index ${qp.index} due to invalid audio file" "Cancelled paging message with index ${qp.index} due to invalid audio file"
) )
} }
} else {
// file tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log(
"AAS",
"Cancelled paging message with index ${qp.index} due to invalid audio file"
)
}
} else if (qp.Source == "SHALAT") { } else if (qp.Source == "SHALAT") {
val ann_id = Get_ANN_ID(qp.Message) val ann_id = Get_ANN_ID(qp.Message)
if (ann_id > 0) { if (ann_id > 0) {
@@ -587,11 +601,19 @@ class MainExtension01 {
listfile -> listfile ->
val listafi = mutableListOf<AudioFileInfo>() val listafi = mutableListOf<AudioFileInfo>()
listfile.forEach { filenya -> listfile.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){
listafi.add(afi)
} else {
val afi = audioPlayer.LoadAudioFile(filenya) val afi = audioPlayer.LoadAudioFile(filenya)
if (afi.isValid()) { if (afi.isValid()) {
listafi.add(afi) listafi.add(afi)
contentCache.addAudioFile(filenya, afi)
} }
} }
}
val targetfile = SoundbankResult_directory.resolve( val targetfile = SoundbankResult_directory.resolve(
Make_WAV_FileName( Make_WAV_FileName(
"Shalat", "Shalat",
@@ -728,11 +750,18 @@ class MainExtension01 {
Get_Soundbank_Files(mb, variables ?: emptyMap(), { Get_Soundbank_Files(mb, variables ?: emptyMap(), {
listfile -> listfile ->
listfile.forEach { filenya -> listfile.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){
listafi.add(afi)
} else {
val afi = audioPlayer.LoadAudioFile(filenya) val afi = audioPlayer.LoadAudioFile(filenya)
if (afi.isValid()) { if (afi.isValid()) {
listafi.add(afi) listafi.add(afi)
contentCache.addAudioFile(filenya, afi)
} }
} }
}
}, },
{ {
err -> err ->
@@ -794,11 +823,18 @@ class MainExtension01 {
listfile -> listfile ->
val listafi = mutableListOf<AudioFileInfo>() val listafi = mutableListOf<AudioFileInfo>()
listfile.forEach { filenya -> listfile.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){
listafi.add(afi)
} else {
val afi = audioPlayer.LoadAudioFile(filenya) val afi = audioPlayer.LoadAudioFile(filenya)
if (afi.isValid()) { if (afi.isValid()) {
listafi.add(afi) listafi.add(afi)
contentCache.addAudioFile(filenya, afi)
} }
} }
}
val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Timer","")).toString() val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Timer","")).toString()
audioPlayer.WavWriter(listafi, targetfile, true, audioPlayer.WavWriter(listafi, targetfile, true,
) { success, message -> ) { success, message ->

View File

@@ -1,23 +1,19 @@
package audio package audio
import audio.Bass.BASS_ACTIVE_PLAYING
import audio.Bass.BASS_DEVICE_ENABLED import audio.Bass.BASS_DEVICE_ENABLED
import audio.Bass.BASS_DEVICE_INIT import audio.Bass.BASS_DEVICE_INIT
import audio.Bass.BASS_POS_BYTE import audio.Bass.BASS_POS_BYTE
import audio.Bass.BASS_STREAM_DECODE import audio.Bass.BASS_STREAM_DECODE
import audio.Bass.BASS_SAMPLE_MONO import audio.Bass.BASS_SAMPLE_MONO
import audio.Bass.STREAMPROC_PUSH
import audio.BassEnc.BASS_ENCODE_PCM import audio.BassEnc.BASS_ENCODE_PCM
import codes.Somecodes.Companion.ValidFile import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidString import codes.Somecodes.Companion.ValidString
import com.sun.jna.Memory import com.sun.jna.Memory
import com.sun.jna.Pointer import com.sun.jna.Pointer
import commonAudio import contentCache
import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.tinylog.Logger import org.tinylog.Logger
import java.util.function.BiConsumer import java.util.function.BiConsumer
@@ -162,7 +158,7 @@ class AudioPlayer (var samplingrate: Int) {
} }
val job = CoroutineScope(Dispatchers.IO).launch(CoroutineName("WavWriter $target")) { CoroutineScope(Dispatchers.IO).launch(CoroutineName("WavWriter $target")) {
bass.BASS_SetDevice(0) // Set to No Sound device for writing bass.BASS_SetDevice(0) // Set to No Sound device for writing
val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null) val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null)
if (streamhandle==0){ if (streamhandle==0){
@@ -191,7 +187,7 @@ class AudioPlayer (var samplingrate: Int) {
var allsuccess = true var allsuccess = true
if (withChime){ if (withChime){
val chup = commonAudio["chimeup"] val chup = contentCache.getAudioFile("chimeup")
if (chup!=null && chup.isValid()){ if (chup!=null && chup.isValid()){
if (pushData(chup.bytes)){ if (pushData(chup.bytes)){
println("Chime up pushed") println("Chime up pushed")
@@ -217,7 +213,7 @@ class AudioPlayer (var samplingrate: Int) {
} }
if (withChime){ if (withChime){
val chdn = commonAudio["chimedown"] val chdn = contentCache.getAudioFile("chimedown")
if (chdn!=null && chdn.isValid()){ if (chdn!=null && chdn.isValid()){
if (pushData(chdn.bytes)){ if (pushData(chdn.bytes)){
println("Chime down pushed") println("Chime down pushed")

55
src/audio/ContentCache.kt Normal file
View File

@@ -0,0 +1,55 @@
package audio
/**
* Cache for audio content to avoid reloading from disk
*/
@Suppress("unused")
class ContentCache {
private val map: MutableMap<String, AudioFileInfo> = HashMap()
/**
* Clear the cache, but keep essential sounds : chimeup, chimedown, silence1s, silencehalf
*/
fun clear(){
// dont clear chimeup, chimedown, silence1s, silencehalf
val keysToKeep = setOf("chimeup", "chimedown", "silence1s", "silencehalf")
map.keys.retainAll(keysToKeep)
}
/**
* Add an audio file to the cache
* @param key The key to identify the audio file
* @param audioFile The AudioFileInfo object
*/
fun addAudioFile(key: String, audioFile: AudioFileInfo) {
map[key] = audioFile
}
/**
* Retrieve an audio file from the cache
* @param key The key to identify the audio file
* @return The AudioFileInfo object, or null if not found
*/
fun getAudioFile(key: String): AudioFileInfo? {
return map[key]
}
/**
* Remove an audio file from the cache
* @param key The key to identify the audio file
*/
fun removeAudioFile(key: String) {
map.remove(key)
}
/**
* Check if the cache contains the specified key
* @param key The key to check in the cache
* @return True if the key exists, false otherwise
*/
fun haveKey(key: String): Boolean {
return map.containsKey(key)
}
}

View File

@@ -1,73 +0,0 @@
package content
import audio.AudioFileInfo
/**
* Class to manage loaded content in the application.
* This class provides methods to retrieve and add soundbank data based on specific criteria.
*/
@Suppress("unused")
class ContentCache {
private val contentList = ArrayList<SoundbankData>()
/**
* Clears all loaded content from the cache.
*/
fun Clear(){
contentList.clear()
}
/**
* Removes the specified SoundbankData from the content list.
* @param SoundbankData The SoundbankData to be removed.
*/
fun Remove(SoundbankData: SoundbankData){
contentList.remove(SoundbankData)
}
/**
* Removes the specified SoundbankData from the content list based on tag, category, language, and voiceType.
* @param tag The tag of the SoundbankData to be removed.
* @param category The category of the SoundbankData to be removed.
* @param language The language of the SoundbankData to be removed.
* @param voiceType The voice type of the SoundbankData to be removed.
*/
fun Remove(tag: String, category: Category, language: Language, voiceType: VoiceType){
val existing = Get(tag, category, language, voiceType)
if (existing!=null) contentList.remove(existing)
}
/**
* Get the specified SoundbankData from tag, category, language, and voiceType.
* @return SoundbankData if found, null otherwise.
*/
fun Get(tag: String, category: Category, language: Language, voiceType: VoiceType): SoundbankData? {
return contentList.find {
it.TAG == tag &&
it.Category == category &&
it.Language == language &&
it.VoiceType == voiceType &&
it.audio.isValid()
}
}
/**
* Adds a new soundbank to the content list if it does not already exist.
*
* @param tag The unique identifier for the soundbank.
* @param category The category of the soundbank.
* @param language The language of the soundbank.
* @param voiceType The voice type of the soundbank.
* @param audio The audio file information for the soundbank.
* @return True if the soundbank was added, false if it already exists.
*/
fun Add(tag: String, category: Category, language: Language, voiceType: VoiceType, audio: AudioFileInfo): Boolean {
val existing = Get(tag, category, language, voiceType)
if (existing!=null) return false
contentList.add(SoundbankData(tag, category, language, voiceType, audio))
return true
}
}