commit 07/10/2025
This commit is contained in:
@@ -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()}" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -553,18 +553,32 @@ 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 logmessage =
|
val br = StreamerOutputs[ip]
|
||||||
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
|
br?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) })
|
||||||
Logger.info { logmessage }
|
}
|
||||||
db.Add_Log("AAS", logmessage)
|
|
||||||
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
|
val logmessage =
|
||||||
|
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
|
||||||
|
Logger.info { logmessage }
|
||||||
|
db.Add_Log("AAS", logmessage)
|
||||||
|
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
|
||||||
|
|
||||||
|
return
|
||||||
|
} 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"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
// file tidak valid, delete from queue paging
|
// file tidak valid, delete from queue paging
|
||||||
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
|
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
|
||||||
@@ -587,10 +601,18 @@ class MainExtension01 {
|
|||||||
listfile ->
|
listfile ->
|
||||||
val listafi = mutableListOf<AudioFileInfo>()
|
val listafi = mutableListOf<AudioFileInfo>()
|
||||||
listfile.forEach { filenya ->
|
listfile.forEach { filenya ->
|
||||||
val afi = audioPlayer.LoadAudioFile(filenya)
|
val afi = contentCache.getAudioFile(filenya)
|
||||||
if (afi.isValid()) {
|
if (afi!=null && afi.isValid()){
|
||||||
listafi.add(afi)
|
listafi.add(afi)
|
||||||
|
} else {
|
||||||
|
val afi = audioPlayer.LoadAudioFile(filenya)
|
||||||
|
if (afi.isValid()) {
|
||||||
|
listafi.add(afi)
|
||||||
|
contentCache.addAudioFile(filenya, afi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
val targetfile = SoundbankResult_directory.resolve(
|
val targetfile = SoundbankResult_directory.resolve(
|
||||||
Make_WAV_FileName(
|
Make_WAV_FileName(
|
||||||
@@ -728,10 +750,17 @@ class MainExtension01 {
|
|||||||
Get_Soundbank_Files(mb, variables ?: emptyMap(), {
|
Get_Soundbank_Files(mb, variables ?: emptyMap(), {
|
||||||
listfile ->
|
listfile ->
|
||||||
listfile.forEach { filenya ->
|
listfile.forEach { filenya ->
|
||||||
val afi = audioPlayer.LoadAudioFile(filenya)
|
val afi = contentCache.getAudioFile(filenya)
|
||||||
if (afi.isValid()) {
|
if (afi!=null && afi.isValid()){
|
||||||
listafi.add(afi)
|
listafi.add(afi)
|
||||||
|
} else {
|
||||||
|
val afi = audioPlayer.LoadAudioFile(filenya)
|
||||||
|
if (afi.isValid()) {
|
||||||
|
listafi.add(afi)
|
||||||
|
contentCache.addAudioFile(filenya, afi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -794,10 +823,17 @@ class MainExtension01 {
|
|||||||
listfile ->
|
listfile ->
|
||||||
val listafi = mutableListOf<AudioFileInfo>()
|
val listafi = mutableListOf<AudioFileInfo>()
|
||||||
listfile.forEach { filenya ->
|
listfile.forEach { filenya ->
|
||||||
val afi = audioPlayer.LoadAudioFile(filenya)
|
val afi = contentCache.getAudioFile(filenya)
|
||||||
if (afi.isValid()) {
|
if (afi!=null && afi.isValid()){
|
||||||
listafi.add(afi)
|
listafi.add(afi)
|
||||||
|
} else {
|
||||||
|
val afi = audioPlayer.LoadAudioFile(filenya)
|
||||||
|
if (afi.isValid()) {
|
||||||
|
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,
|
||||||
|
|||||||
@@ -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
55
src/audio/ContentCache.kt
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user