Mercurial > games > semicongine
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)) |