Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 24 and 32 bit .wav's #13

Merged
merged 1 commit into from
May 19, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 53 additions & 7 deletions GDScriptAudioImport.gd
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ func loadfile(filepath):
return AudioStreamSample.new()

var bytes = file.get_buffer(file.get_len())

# if File is wav
if filepath.ends_with(".wav"):

var newstream = AudioStreamSample.new()

#---------------------------
#parrrrseeeeee!!! :D


var bits_per_sample = 0

for i in range(0, 100):
var those4bytes = str(char(bytes[i])+char(bytes[i+1])+char(bytes[i+2])+char(bytes[i+3]))

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

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


if those4bytes == "data":
assert(bits_per_sample != 0)

var audio_data_size = bytes[i+4] + (bytes[i+5] << 8) + (bytes[i+6] << 16) + (bytes[i+7] << 24)
print ("Audio data/stream size is " + str(audio_data_size) + " bytes")

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

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

if bits_per_sample in [24, 32]:
newstream.data = convert_to_16bit(data, bits_per_sample)
else:
newstream.data = data
# end of parsing
#---------------------------

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

# Converts .wav data from 24 or 32 bits to 16
#
# These conversions are SLOW in GDScript
# on my one test song, 32 -> 16 was around 3x slower than 24 -> 16
#
# I couldn't get threads to help very much
# They made the 24bit case about 2x faster in my test file
# And the 32bit case abour 50% slower
# I don't wanna risk it always being slower on other files
# And really, the solution would be to handle it in a low-level language
func convert_to_16bit(data: PoolByteArray, from: int) -> PoolByteArray:
print("converting to 16-bit from %d" % from)
var time = OS.get_ticks_msec()
# 24 bit .wav's are typically stored as integers
# so we just grab the 2 most significant bytes and ignore the other
if from == 24:
var j = 0
for i in range(0, data.size(), 3):
data[j] = data[i+1]
data[j+1] = data[i+2]
j += 2
data.resize(data.size() * 2 / 3)
# 32 bit .wav's are typically stored as floating point numbers
# so we need to grab all 4 bytes and interpret them as a float first
if from == 32:
var spb := StreamPeerBuffer.new()
var single_float: float
var value: int
for i in range(0, data.size(), 4):
spb.data_array = data.subarray(i, i+3)
single_float = spb.get_float()
value = single_float * 32768
data[i/2] = value
data[i/2+1] = value >> 8
data.resize(data.size() / 2)
print("Took %f seconds for slow conversion" % ((OS.get_ticks_msec() - time) / 1000.0))
return data


# ---------- REFERENCE ---------------
# note: typical values doesn't always match
Expand Down