Mercurial > games > semicongine
changeset 681:f20965f1d7fa
add: loading *.au audio files
author | Sam <sam@basx.dev> |
---|---|
date | Sat, 13 May 2023 19:31:48 +0700 |
parents | d3e62cd055d1 |
children | 9767dec81193 |
files | src/semicongine/audio.nim src/semicongine/core/audiotypes.nim src/semicongine/resources/audio.nim |
diffstat | 3 files changed, 74 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/src/semicongine/audio.nim Fri May 12 00:34:32 2023 +0700 +++ b/src/semicongine/audio.nim Sat May 13 19:31:48 2023 +0700 @@ -135,20 +135,22 @@ return false func applyLevel(sample: Sample, levelLeft, levelRight: Level): Sample = - (int16(float(sample[0]) * levelLeft), int16(float(sample[1]) * levelRight)) + [int16(float(sample[0]) * levelLeft), int16(float(sample[1]) * levelRight)] +func clip(value: int32): int16 = + int16(max(min(int32(high(int16)), value), int32(low(int16)))) + +# used for combining sounds func mix(a, b: Sample): Sample = - var - left = int32(a[0]) + int32(b[0]) - right = int32(a[1]) + int32(b[1]) - left = max(min(int32(high(int16)), left), int32(low(int16))) - right = max(min(int32(high(int16)), right), int32(low(int16))) - (int16(left), int16(right)) + [ + clip(int32(a[0]) + int32(b[0])), + clip(int32(a[1]) + int32(b[1])), + ] proc updateSoundBuffer(mixer: var Mixer) = # mix for i in 0 ..< mixer.buffers[mixer.currentBuffer].len: - var currentSample = (0'i16, 0'i16) + var currentSample = [0'i16, 0'i16] mixer.lock.withLock(): for track in mixer.tracks.mvalues: var stoppedSounds: seq[uint64]
--- a/src/semicongine/core/audiotypes.nim Fri May 12 00:34:32 2023 +0700 +++ b/src/semicongine/core/audiotypes.nim Sat May 13 19:31:48 2023 +0700 @@ -9,7 +9,7 @@ type Level* = 0'f .. 1'f - Sample* = (int16, int16) + Sample* = array[2, int16] SoundData* = seq[Sample] Sound* = ref SoundData @@ -24,7 +24,7 @@ for i in 0 ..< int(float(rate) * len): let t = dt * float(i) let value = int16(sine(t) * float(high(int16))) - result.add (value, value) + result.add [value, value] proc newSound*(data: SoundData): Sound = result = new Sound
--- a/src/semicongine/resources/audio.nim Fri May 12 00:34:32 2023 +0700 +++ b/src/semicongine/resources/audio.nim Sat May 13 19:31:48 2023 +0700 @@ -1,7 +1,68 @@ import std/streams +import std/endians +import std/math import ../core/audiotypes +type + Encoding {.size: sizeof(uint32).} = enum + # Unspecified = 0 + # Uint8Ulaw = 1 + # Int8 = 2 + Int16 = 3 + # Int24 = 4 + # Int32 = 5 + # Float32 = 6 + # Float64 = 7 + + AuHeader = object + magicNumber: uint32 + dataOffset: uint32 + dataSize: uint32 + encoding: Encoding + sampleRate: uint32 + channels: uint32 + +func changeEndian(value: int16): int16 = + + var bytes: array[2, uint8] = cast[array[2, uint8]](value) + swap(bytes[0], bytes[1]) + result = cast[int16](bytes) + +proc readSample(stream: Stream, encoding: Encoding, channels: int): Sample = + result[0] = stream.readint16() + swapEndian16(addr result[0], addr result[0]) + + if channels == 2: + result[1] = stream.readint16() + swapEndian16(addr result[1], addr result[1]) + else: + result[1] = result[0] + + + # https://en.wikipedia.org/wiki/Au_file_format +# Returns sound data and samplerate proc readAU*(stream: Stream): Sound = - result + var header: AuHeader + + for name, value in fieldPairs(header): + var bytes: array[4, uint8] + stream.read(bytes) + swap(bytes[0], bytes[3]) + swap(bytes[1], bytes[2]) + value = cast[typeof(value)](bytes) + + assert header.magicNumber == 0x2e736e64 + if header.sampleRate != AUDIO_SAMPLE_RATE: + raise newException(Exception, "Only support sample rate of 48000 Hz but got " & $header.sampleRate & " Hz, please resample (e.g. ffmpeg -i {infile} -ar 48000 {outfile})") + if not (header.channels in [1'u32, 2'u32]): + raise newException(Exception, "Only support mono and stereo audio at the moment (1 or 2 channels), but found " & $header.channels) + + var annotation: string + stream.read(annotation) + + result = new Sound + stream.setPosition(int(header.dataOffset)) + while not stream.atEnd(): + result[].add stream.readSample(header.encoding, int(header.channels))