Skip to content

Commit dfd3957

Browse files
committed
Add support for 24 and 32 bit .wav's
Apparently those .wav's are always format_code 3? The conversion is SLOW on long files (like songs). It requires going through every byte to do the conversion. So if performance is important, GDScript is just not fast enough for this.
1 parent 2fd9821 commit dfd3957

1 file changed

Lines changed: 53 additions & 7 deletions

File tree

GDScriptAudioImport.gd

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ func loadfile(filepath):
5656
return AudioStreamSample.new()
5757

5858
var bytes = file.get_buffer(file.get_len())
59-
6059
# if File is wav
6160
if filepath.ends_with(".wav"):
62-
6361
var newstream = AudioStreamSample.new()
6462

6563
#---------------------------
6664
#parrrrseeeeee!!! :D
67-
65+
66+
var bits_per_sample = 0
67+
6868
for i in range(0, 100):
6969
var those4bytes = str(char(bytes[i])+char(bytes[i+1])+char(bytes[i+2])+char(bytes[i+3]))
7070

@@ -90,6 +90,9 @@ func loadfile(filepath):
9090
if format_code == 0: format_name = "8_BITS"
9191
elif format_code == 1: format_name = "16_BITS"
9292
elif format_code == 2: format_name = "IMA_ADPCM"
93+
else:
94+
format_name = "UNKNOWN (trying to interpret as 16_BITS)"
95+
format_code = 1
9396
print ("Format: " + str(format_code) + " " + format_name)
9497
#assign format to our AudioStreamSample
9598
newstream.format = format_code
@@ -114,20 +117,25 @@ func loadfile(filepath):
114117
var bits_sample_channel = bytes[fsc0+12] + (bytes[fsc0+13] << 8)
115118
print ("BitsPerSample * Channel / 8: " + str(bits_sample_channel))
116119

117-
#aaaand bits per sample/bitrate [Bytes 14-15] - TODO: Handle different bitrates
118-
var bits_per_sample = bytes[fsc0+14] + (bytes[fsc0+15] << 8)
120+
#aaaand bits per sample/bitrate [Bytes 14-15]
121+
bits_per_sample = bytes[fsc0+14] + (bytes[fsc0+15] << 8)
119122
print ("Bits per sample: " + str(bits_per_sample))
120123

121-
122124
if those4bytes == "data":
125+
assert(bits_per_sample != 0)
126+
123127
var audio_data_size = bytes[i+4] + (bytes[i+5] << 8) + (bytes[i+6] << 16) + (bytes[i+7] << 24)
124128
print ("Audio data/stream size is " + str(audio_data_size) + " bytes")
125129

126130
var data_entry_point = (i+8)
127131
print ("Audio data starts at byte " + str(data_entry_point))
128132

129-
newstream.data = bytes.subarray(data_entry_point, data_entry_point+audio_data_size-1)
133+
var data = bytes.subarray(data_entry_point, data_entry_point+audio_data_size-1)
130134

135+
if bits_per_sample in [24, 32]:
136+
newstream.data = convert_to_16bit(data, bits_per_sample)
137+
else:
138+
newstream.data = data
131139
# end of parsing
132140
#---------------------------
133141

@@ -155,6 +163,44 @@ func loadfile(filepath):
155163
print ("ERROR: Wrong filetype or format")
156164
file.close()
157165

166+
# Converts .wav data from 24 or 32 bits to 16
167+
#
168+
# These conversions are SLOW in GDScript
169+
# on my one test song, 32 -> 16 was around 3x slower than 24 -> 16
170+
#
171+
# I couldn't get threads to help very much
172+
# They made the 24bit case about 2x faster in my test file
173+
# And the 32bit case abour 50% slower
174+
# I don't wanna risk it always being slower on other files
175+
# And really, the solution would be to handle it in a low-level language
176+
func convert_to_16bit(data: PoolByteArray, from: int) -> PoolByteArray:
177+
print("converting to 16-bit from %d" % from)
178+
var time = OS.get_ticks_msec()
179+
# 24 bit .wav's are typically stored as integers
180+
# so we just grab the 2 most significant bytes and ignore the other
181+
if from == 24:
182+
var j = 0
183+
for i in range(0, data.size(), 3):
184+
data[j] = data[i+1]
185+
data[j+1] = data[i+2]
186+
j += 2
187+
data.resize(data.size() * 2 / 3)
188+
# 32 bit .wav's are typically stored as floating point numbers
189+
# so we need to grab all 4 bytes and interpret them as a float first
190+
if from == 32:
191+
var spb := StreamPeerBuffer.new()
192+
var single_float: float
193+
var value: int
194+
for i in range(0, data.size(), 4):
195+
spb.data_array = data.subarray(i, i+3)
196+
single_float = spb.get_float()
197+
value = single_float * 32768
198+
data[i/2] = value
199+
data[i/2+1] = value >> 8
200+
data.resize(data.size() / 2)
201+
print("Took %f seconds for slow conversion" % ((OS.get_ticks_msec() - time) / 1000.0))
202+
return data
203+
158204

159205
# ---------- REFERENCE ---------------
160206
# note: typical values doesn't always match

0 commit comments

Comments
 (0)