comparison src/semicongine/resources/audio.nim @ 681:f20965f1d7fa

add: loading *.au audio files
author Sam <sam@basx.dev>
date Sat, 13 May 2023 19:31:48 +0700
parents 28e704ca739b
children ddfc54036e00
comparison
equal deleted inserted replaced
680:d3e62cd055d1 681:f20965f1d7fa
1 import std/streams 1 import std/streams
2 import std/endians
3 import std/math
2 4
3 import ../core/audiotypes 5 import ../core/audiotypes
4 6
7 type
8 Encoding {.size: sizeof(uint32).} = enum
9 # Unspecified = 0
10 # Uint8Ulaw = 1
11 # Int8 = 2
12 Int16 = 3
13 # Int24 = 4
14 # Int32 = 5
15 # Float32 = 6
16 # Float64 = 7
17
18 AuHeader = object
19 magicNumber: uint32
20 dataOffset: uint32
21 dataSize: uint32
22 encoding: Encoding
23 sampleRate: uint32
24 channels: uint32
25
26 func changeEndian(value: int16): int16 =
27
28 var bytes: array[2, uint8] = cast[array[2, uint8]](value)
29 swap(bytes[0], bytes[1])
30 result = cast[int16](bytes)
31
32 proc readSample(stream: Stream, encoding: Encoding, channels: int): Sample =
33 result[0] = stream.readint16()
34 swapEndian16(addr result[0], addr result[0])
35
36 if channels == 2:
37 result[1] = stream.readint16()
38 swapEndian16(addr result[1], addr result[1])
39 else:
40 result[1] = result[0]
41
42
43
5 # https://en.wikipedia.org/wiki/Au_file_format 44 # https://en.wikipedia.org/wiki/Au_file_format
45 # Returns sound data and samplerate
6 proc readAU*(stream: Stream): Sound = 46 proc readAU*(stream: Stream): Sound =
7 result 47 var header: AuHeader
48
49 for name, value in fieldPairs(header):
50 var bytes: array[4, uint8]
51 stream.read(bytes)
52 swap(bytes[0], bytes[3])
53 swap(bytes[1], bytes[2])
54 value = cast[typeof(value)](bytes)
55
56 assert header.magicNumber == 0x2e736e64
57 if header.sampleRate != AUDIO_SAMPLE_RATE:
58 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})")
59 if not (header.channels in [1'u32, 2'u32]):
60 raise newException(Exception, "Only support mono and stereo audio at the moment (1 or 2 channels), but found " & $header.channels)
61
62 var annotation: string
63 stream.read(annotation)
64
65 result = new Sound
66 stream.setPosition(int(header.dataOffset))
67 while not stream.atEnd():
68 result[].add stream.readSample(header.encoding, int(header.channels))