first commit 26/07/2025

This commit is contained in:
2025-07-26 10:14:46 +07:00
parent f6ae8e14c0
commit a32a1d3300
4 changed files with 192 additions and 7 deletions

View File

@@ -1,11 +1,11 @@
import audio.AudioPlayer
import codes.Somecodes
import org.tinylog.Logger
val audioPlayer = AudioPlayer()
fun main() {
Logger.info("Application started" as Any)
val audioPlayer = AudioPlayer(44100) // 44100 Hz sampling rate
audioPlayer.InitAudio(1)
}
}

View File

@@ -5,16 +5,27 @@ import audio.Bass.BASS_DEVICE_INIT
import audio.Bass.BASS_POS_BYTE
import audio.Bass.BASS_STREAM_DECODE
import audio.Bass.BASS_SAMPLE_MONO
import audio.Bass.STREAMPROC_PUSH
import audio.BassEnc.BASS_ENCODE_PCM
import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidString
import com.sun.jna.Memory
import org.tinylog.Logger
import java.util.function.BiConsumer
@Suppress("unused")
class AudioPlayer {
var bass: Bass = Bass.Instance
class AudioPlayer (var samplingrate: Int) {
val bass: Bass = Bass.Instance
val bassenc : BassEnc = BassEnc.Instance
var initedDevice = -1
init {
Logger.info("Audio version ${Integer.toHexString(bass.BASS_GetVersion())}" as Any)
if (samplingrate<1) samplingrate = 44100 // Default sampling rate
Logger.info {"Bass version ${Integer.toHexString(bass.BASS_GetVersion())}"}
Logger.info { "BassEnc version ${Integer.toHexString(bassenc.BASS_Encode_GetVersion())}" }
InitAudio(0) // Audio 0 is No Sound, use for reading and writing wav silently
}
@@ -110,5 +121,49 @@ class AudioPlayer {
return result
}
/**
* 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 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>) {
if (sources.isEmpty() || !ValidFile(target)) {
callback.accept(false, " Invalid sources")
return
}
if (!ValidString(target)) {
callback.accept(false, " Invalid target file name")
return
}
bass.BASS_SetDevice(0) // Set to No Sound device for writing
val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, STREAMPROC_PUSH, null)
if (streamhandle==0){
callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
return
}
val encodehandle = bassenc.BASS_Encode_Start(streamhandle, target, BASS_ENCODE_PCM, null, null)
if (encodehandle==0){
bass.BASS_StreamFree(streamhandle)
callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
return
}
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
}
// TODO write each source to the stream
// close the encoding handle
bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_ChannelFree(streamhandle)
callback.accept(true, "WAV file written successfully: $target")
}
}

View File

@@ -416,6 +416,8 @@ public interface Bass extends Library {
int BASS_SYNC_MIXTIME = 0x40000000; // flag: sync at mixtime, else at playtime
int BASS_SYNC_ONETIME = 0x80000000; // flag: sync only once, else continuously
interface SYNCPROC extends Callback
{
void SYNCPROC(int handle, int channel, int data, Pointer user);
@@ -787,5 +789,4 @@ public interface Bass extends Library {
int BASS_StreamCreate(int freq, int chans, int flags, int proc, Pointer user);
}

129
src/audio/BassEnc.java Normal file
View File

@@ -0,0 +1,129 @@
package audio;
import com.sun.jna.*;
@SuppressWarnings("unused")
public interface BassEnc extends Library {
BassEnc Instance = (BassEnc) Native.load("bassenc", BassEnc.class);
// Additional error codes returned by BASS_ErrorGetCode
int BASS_ERROR_CAST_DENIED = 2100; // access denied (invalid password)
int BASS_ERROR_SERVER_CERT = 2101; // missing/invalid certificate
// Additional BASS_SetConfig options
int BASS_CONFIG_ENCODE_PRIORITY = 0x10300;
int BASS_CONFIG_ENCODE_QUEUE = 0x10301;
int BASS_CONFIG_ENCODE_CAST_TIMEOUT = 0x10310;
// Additional BASS_SetConfigPtr options
int BASS_CONFIG_ENCODE_CAST_PROXY = 0x10311;
int BASS_CONFIG_ENCODE_CAST_BIND = 0x10312;
int BASS_CONFIG_ENCODE_SERVER_CERT = 0x10320;
int BASS_CONFIG_ENCODE_SERVER_KEY = 0x10321;
// BASS_Encode_Start flags
int BASS_ENCODE_NOHEAD = 1; // don't send a WAV header to the encoder
int BASS_ENCODE_FP_8BIT = 2; // convert floating-point sample data to 8-bit integer
int BASS_ENCODE_FP_16BIT = 4; // convert floating-point sample data to 16-bit integer
int BASS_ENCODE_FP_24BIT = 6; // convert floating-point sample data to 24-bit integer
int BASS_ENCODE_FP_32BIT = 8; // convert floating-point sample data to 32-bit integer
int BASS_ENCODE_FP_AUTO = 14; // convert floating-point sample data back to channel's format
int BASS_ENCODE_BIGEND = 16; // big-endian sample data
int BASS_ENCODE_PAUSE = 32; // start encording paused
int BASS_ENCODE_PCM = 64; // write PCM sample data (no encoder)
int BASS_ENCODE_RF64 = 128; // send an RF64 header
int BASS_ENCODE_QUEUE = 0x200; // queue data to feed encoder asynchronously
int BASS_ENCODE_WFEXT = 0x400; // WAVEFORMATEXTENSIBLE "fmt" chunk
int BASS_ENCODE_CAST_NOLIMIT = 0x1000; // don't limit casting data rate
int BASS_ENCODE_LIMIT = 0x2000; // limit data rate to real-time
int BASS_ENCODE_AIFF = 0x4000; // send an AIFF header rather than WAV
int BASS_ENCODE_DITHER = 0x8000; // apply dither when converting floating-point sample data to integer
int BASS_ENCODE_AUTOFREE = 0x40000; // free the encoder when the channel is freed
// BASS_Encode_GetCount counts
int BASS_ENCODE_COUNT_IN = 0; // sent to encoder
int BASS_ENCODE_COUNT_OUT = 1; // received from encoder
int BASS_ENCODE_COUNT_CAST = 2; // sent to cast server
int BASS_ENCODE_COUNT_QUEUE = 3; // queued
int BASS_ENCODE_COUNT_QUEUE_LIMIT = 4; // queue limit
int BASS_ENCODE_COUNT_QUEUE_FAIL = 5; // failed to queue
int BASS_ENCODE_COUNT_IN_FP = 6; // sent to encoder before floating-point conversion
// BASS_Encode_CastInit content MIME types
String BASS_ENCODE_TYPE_MP3 = "audio/mpeg";
String BASS_ENCODE_TYPE_OGG = "audio/ogg";
String BASS_ENCODE_TYPE_AAC = "audio/aacp";
// BASS_Encode_CastInit flags
int BASS_ENCODE_CAST_PUBLIC = 1; // add to public directory
int BASS_ENCODE_CAST_PUT = 2; // use PUT method
int BASS_ENCODE_CAST_SSL = 4; // use SSL/TLS encryption
// BASS_Encode_CastGetStats types
int BASS_ENCODE_STATS_SHOUT = 0; // Shoutcast stats
int BASS_ENCODE_STATS_ICE = 1; // Icecast mount-point stats
int BASS_ENCODE_STATS_ICESERV = 2; // Icecast server stats
// BASS_Encode_ServerInit flags
int BASS_ENCODE_SERVER_NOHTTP = 1; // no HTTP headers
int BASS_ENCODE_SERVER_META = 2; // Shoutcast metadata
int BASS_ENCODE_SERVER_SSL = 4; // support SSL/TLS encryption
int BASS_ENCODE_SERVER_SSLONLY = 8; // require SSL/TLS encryption
// Encoder notifications
int BASS_ENCODE_NOTIFY_ENCODER = 1; // encoder died
int BASS_ENCODE_NOTIFY_CAST = 2; // cast server connection died
int BASS_ENCODE_NOTIFY_SERVER = 3; // server died
int BASS_ENCODE_NOTIFY_CAST_TIMEOUT = 0x10000; // cast timeout
int BASS_ENCODE_NOTIFY_QUEUE_FULL = 0x10001; // queue is out of space
int BASS_ENCODE_NOTIFY_FREE = 0x10002; // encoder has been freed
interface ENCODEPROC extends Callback {
/**
* Encoding Callback function.
* @param encoderhandle Encoder handle
* @param channelhandle Channel handle
* @param encodedData Buffer containing the encoded data
* @param length number of bytes
* @param user the user pointer passed to BASS_Encode_Start
*/
void ENCODEPROC(int encoderhandle, int channelhandle, Memory encodedData, int length, Pointer user);
}
interface ENCODEPROCEX extends Callback {
/**
* Encoding Callback function
* @param handle Encoder handle
* @param channel Channel handle
* @param buffer Buffer containing the encoded data
* @param length number of bytes
* @param offset file offset of the data
* @param user the user pointer passed to BASS_Encode_Start
*/
void ENCODEPROCEX(int handle, int channel, Memory buffer, int length, long offset, Object user);
}
interface ENCODERPROC extends Callback {
/**
* Encoder Callback function.
* @param encoderHandle Encoder handle
* @param channelHandle Channel handle
* @param encodedData Buffer containing the PCM Data (input) and receiving the encoded data (output)
* @param length Number of bytes in (-1 = closing)
* @param maxOut Maximum number of bytes out
* @param user the user pointer passed to BASS_Encode_Start
* @return the amount of encoded data (-1 = stop)
*/
int ENCODERPROC(int encoderHandle, int channelHandle, Memory encodedData, int length, int maxOut, Pointer user);
}
int BASS_Encode_GetVersion();
int BASS_Encode_Start(int handle, String cmdline, int flags, ENCODEPROC proc, Pointer user);
boolean BASS_Encode_Stop(int handle);
boolean BASS_Encode_Write(int handle, Pointer buffer, int length);
int BASS_Encode_IsActive(int handle);
boolean BASS_Encode_SetPaused(int handle, boolean paused);
int BASS_Encode_GetChannel(int handle);
}