ChocolateBird/scripts/loaders/SoundLoader.gd

343 lines
22 KiB
GDScript3
Raw Permalink Normal View History

2023-07-25 14:21:10 +09:30
extends Node
signal audio_samples_loaded
signal audio_inst_sample_loaded(id)
signal audio_sfx_sample_loaded(id)
var has_loaded_audio_samples := false
2023-07-25 16:33:45 +09:30
const BGM_NUM := 70
const INST_NUM := 35
const SFX_NUM := 8
const PREPEND_MS := 20 # Prepend 20ms of silence to each sample for preplay purposes
const PLAY_START := PREPEND_MS / 1000.0
const BYTES_PER_SAMPLE := 2 # 16bit samples
const ATTACK_TIME_SMPS := PoolIntArray([131072, 81920, 49152, 32768, 20480, 12288, 8192, 5120, 3072, 2048, 1280, 768, 512, 320, 192, 2])
const ATTACK_TIME_SMPS_ENTRIES := 16
const SPC_DECAY_CURVE := PoolIntArray([2047, 2039, 2031, 2023, 2015, 2007, 1999, 1991, 1983, 1975, 1967, 1959, 1951, 1943, 1935, 1927, 1919, 1911, 1903, 1895, 1887, 1879, 1871, 1863, 1855, 1847, 1839, 1831, 1823, 1815, 1807, 1799, 1791, 1784, 1777, 1770, 1763, 1756, 1749, 1742, 1735, 1728, 1721, 1714, 1707, 1700, 1693, 1686, 1679, 1672, 1665, 1658, 1651, 1644, 1637, 1630, 1623, 1616, 1609, 1602, 1595, 1588, 1581, 1574, 1567, 1560, 1553, 1546, 1539, 1532, 1526, 1520, 1514, 1508, 1502, 1496, 1490, 1484, 1478, 1472, 1466, 1460, 1454, 1448, 1442, 1436, 1430, 1424, 1418, 1412, 1406, 1400, 1394, 1388, 1382, 1376, 1370, 1364, 1358, 1352, 1346, 1340, 1334, 1328, 1322, 1316, 1310, 1304, 1298, 1292, 1286, 1280, 1275, 1270, 1265, 1260, 1255, 1250, 1245, 1240, 1235, 1230, 1225, 1220, 1215, 1210, 1205, 1200, 1195, 1190, 1185, 1180, 1175, 1170, 1165, 1160, 1155, 1150, 1145, 1140, 1135, 1130, 1125, 1120, 1115, 1110, 1105, 1100, 1095, 1090, 1085, 1080, 1075, 1070, 1065, 1060, 1055, 1050, 1045, 1040, 1035, 1030, 1025, 1020, 1016, 1012, 1008, 1004, 1000, 996, 992, 988, 984, 980, 976, 972, 968, 964, 960, 956, 952, 948, 944, 940, 936, 932, 928, 924, 920, 916, 912, 908, 904, 900, 896, 892, 888, 884, 880, 876, 872, 868, 864, 860, 856, 852, 848, 844, 840, 836, 832, 828, 824, 820, 816, 812, 808, 804, 800, 796, 792, 788, 784, 780, 776, 772, 768, 765, 762, 759, 756, 753, 750, 747, 744, 741, 738, 735, 732, 729, 726, 723, 720, 717, 714, 711, 708, 705, 702, 699, 696, 693, 690, 687, 684, 681, 678, 675, 672, 669, 666, 663, 660, 657, 654, 651, 648, 645, 642, 639, 636, 633, 630, 627, 624, 621, 618, 615, 612, 609, 606, 603, 600, 597, 594, 591, 588, 585, 582, 579, 576, 573, 570, 567, 564, 561, 558, 555, 552, 549, 546, 543, 540, 537, 534, 531, 528, 525, 522, 519, 516, 513, 510, 508, 506, 504, 502, 500, 498, 496, 494, 492, 490, 488, 486, 484, 482, 480, 478, 476, 474, 472, 470, 468, 466, 464, 462, 460, 458, 456, 454, 452, 450, 448, 446, 444, 442, 440, 438, 436, 434, 432, 430, 428, 426, 424, 422, 420, 418, 416, 414, 412, 410, 408, 406, 404, 402, 400, 398, 396, 394, 392, 390, 388, 386, 384, 382, 380, 378, 376, 374, 372, 370, 368, 366, 364, 362, 360, 358, 356, 354, 352, 350, 348, 346, 344, 342, 340, 338, 336, 334, 332, 330, 328, 326, 324, 322, 320, 318, 316, 314, 312, 310, 308, 306, 304, 302, 300, 298, 296, 294, 292, 290, 288, 286, 284, 282, 280, 278, 276, 274, 272, 270, 268, 266, 264, 262, 260, 258, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0])
const SPC_DECAY_CURVE_ENTRIES := len(SPC_DECAY_CURVE) #697
# const SPC_DECAY_CURVE := PoolIntArray([1024, 1020, 1016, 1012, 1008, 1004, 1000, 996, 992, 988, 984, 980, 976, 972, 968, 964, 960, 956, 952, 948, 944, 940, 936, 932, 928, 924, 920, 916, 912, 908, 904, 900, 896, 892, 888, 884, 880, 876, 872, 868, 864, 860, 856, 852, 848, 844, 840, 836, 832, 828, 824, 820, 816, 812, 808, 804, 800, 796, 792, 788, 784, 780, 776, 772, 768, 765, 762, 759, 756, 753, 750, 747, 744, 741, 738, 735, 732, 729, 726, 723, 720, 717, 714, 711, 708, 705, 702, 699, 696, 693, 690, 687, 684, 681, 678, 675, 672, 669, 666, 663, 660, 657, 654, 651, 648, 645, 642, 639, 636, 633, 630, 627, 624, 621, 618, 615, 612, 609, 606, 603, 600, 597, 594, 591, 588, 585, 582, 579, 576, 573, 570, 567, 564, 561, 558, 555, 552, 549, 546, 543, 540, 537, 534, 531, 528, 525, 522, 519, 516, 513, 510, 508, 506, 504, 502, 500, 498, 496, 494, 492, 490, 488, 486, 484, 482, 480, 478, 476, 474, 472, 470, 468, 466, 464, 462, 460, 458, 456, 454, 452, 450, 448, 446, 444, 442, 440, 438, 436, 434, 432, 430, 428, 426, 424, 422, 420, 418, 416, 414, 412, 410, 408, 406, 404, 402, 400, 398, 396, 394, 392, 390, 388, 386, 384, 382, 380, 378, 376, 374, 372, 370, 368, 366, 364, 362, 360, 358, 356, 354, 352, 350, 348, 346, 344, 342, 340, 338, 336, 334, 332, 330, 328, 326, 324, 322, 320, 318, 316, 314, 312, 310, 308, 306, 304, 302, 300, 298, 296, 294, 292, 290, 288, 286, 284, 282, 280, 278, 276, 274, 272, 270, 268, 266, 264, 262, 260, 258, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0])
# const SPC_DECAY_CURVE_ENTRIES := 535 # len(SPC_DECAY_CURVE) # Includes trailing zero
# Treat 0 as infinite
const SPC_PERIOD_TABLE := PoolIntArray([0, 2048, 1536, 1280, 1024, 768, 640, 512, 384, 320, 256, 192, 160, 128, 96, 80, 64, 48, 40, 32, 24, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 1])
const SPC_PERIOD_TABLE_LEN := len(SPC_PERIOD_TABLE) # 32
# This is the number of samples (@32kHz) between each action step for ADSR
# Attack Rate = SPC_PERIOD_TABLE[A*2+1]
# Decay Rate = SPC_PERIOD_TABLE[D*2+16]
# Sustain decay Rate = SPC_PERIOD_TABLE[SR]
#
# Since Attack is linear, we can just calculate the total duration and lerp it.
# Decay and Sustain decay are both exponential and will lookup SPC_DECAY_CURVE.
# Attack increases by 0x20==32 per period, or 0x400==1024 at the highest value of 15, and the Attack phase ends when envelope > 0x7FF==2047
# const ATTACK_PERIODS := PoolIntArray([64*2048, 64*1280, 64*768, 64*512, 64*320, 64*192, 64*128, 64*80, 64*48, 64*32, 64*20, 64*12, 64*8, 64*5, 64*3, 2*1])
# const DECAY_PERIODS := PoolIntArray([64, 40, 24, 16, 10, 6, 4, 2])
2024-07-27 17:19:32 +09:30
static func get_adsr_decay_total_periods(adsr_sustain_level: int) -> int:
# Set decay_total_periods based on sustain_level
var target_env = adsr_sustain_level << 8 # SL is 3bit, and is compared to top 3 bits of 11bit envelope to determine when decay ends
for i in SPC_DECAY_CURVE_ENTRIES:
if SPC_DECAY_CURVE[i] <= target_env:
return i
return SPC_DECAY_CURVE_ENTRIES
static func generate_all_adsr_decay_total_periods() -> PoolIntArray:
var output = PoolIntArray()
for i in 8:
output.append(get_adsr_decay_total_periods(i))
return output
onready var all_adsr_decay_total_periods := generate_all_adsr_decay_total_periods()
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!! Testing a workaround for a Godot 3.x AudioStreamSample playback: !!!
# !!! Copy the looped samples one or more times to avoid the break in interpolation at buffer end. !!!
# !!! Adding a few ms to the loops removes harshness. !!!
const HACK_EXTEND_LOOP_SAMPLE_EXTRA_MS := 2 # !!!
func HACK_EXTEND_LOOP_SAMPLE(audio: AudioStreamSample) -> AudioStreamSample: # !!!
2024-07-10 22:13:58 +09:30
var output: AudioStreamSample = audio.duplicate(true) # !!!
# Prepend silence # !!!
var silent_samples := (audio.mix_rate * PREPEND_MS) / 1000 # !!!
var silence := PoolByteArray() # !!!
silence.resize(silent_samples * 2) # 16bit samples in 8bit array # !!!
silence.fill(0) # !!!
output.data = silence + output.data # !!!
output.loop_begin += silent_samples # !!!
output.loop_end += silent_samples # !!!
# Append looped samples # !!!
if output.loop_begin >= output.loop_end: # !!!
return output # !!!
var looped_samples = audio.data.subarray(audio.loop_begin * BYTES_PER_SAMPLE, -1) # !!!
var loop_len = len(looped_samples) # !!!
var target_len = (audio.mix_rate * HACK_EXTEND_LOOP_SAMPLE_EXTRA_MS / 1000) * BYTES_PER_SAMPLE # !!!
while loop_len < target_len: # Keep doubling in length until it's long enough # !!!
looped_samples += looped_samples # !!!
loop_len = len(looped_samples) # !!!
2024-07-10 22:13:58 +09:30
output.data += looped_samples # !!!
return output # !!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2023-07-25 16:33:45 +09:30
var bgm_tracks = []
var instrument_samples = []
var instrument_samples_HACK_EXTENDED_LOOPS = []
2023-07-25 16:33:45 +09:30
var sfx_samples = []
var audio_renderer_viewport: Viewport
var audio_renderer: Node
func read_rom_address(buffer: StreamPeerBuffer) -> int:
2023-07-25 16:33:45 +09:30
# Read a 3-byte little-endian address and wrap the bank to ROM space
return buffer.get_u16() + ((buffer.get_u8() & 0x3F) << 16)
2023-07-25 16:33:45 +09:30
2023-07-25 14:21:10 +09:30
const MAX_15B = 1 << 15
const MAX_16B = 1 << 16
func unsigned16_to_signed(unsigned):
return (unsigned + MAX_15B) % MAX_16B - MAX_15B
func get_reference_pitch_samplerate(tuning1: int, tuning2: int = 0) -> int:
# This is non-trivial and subject to change
2023-09-23 16:04:51 +09:30
var pitch_scale = tuning1/255.0 + tuning2/65535.0
if tuning1 < 0x80:
pitch_scale += 1.0
return int(pitch_scale * 36000)
# return (unsigned16_to_signed(pitch) + 0x8000) * 32000/4096
2023-07-25 14:21:10 +09:30
func process_sample(mantissa: int, exponent: int) -> int:
# For filter arithmetic the samples need to be in signed form.
# Sign-extend
if mantissa >= 8:
mantissa |= 0xFFF0
2023-07-25 16:33:45 +09:30
if exponent > 12:
exponent = 12
2023-07-25 14:21:10 +09:30
var unsigned = (mantissa << exponent) & 0xFFFF
return unsigned16_to_signed(unsigned)
func clamp_short(i: int) -> int:
if i < -0x8000:
return -0x8000
if i > 0x7FFF:
return 0x7FFF
return i
2023-07-25 14:21:10 +09:30
func make_sample(buffer: StreamPeerBuffer, size: int, sample_rate: int) -> AudioStreamSample:
2023-07-25 14:21:10 +09:30
var audio := AudioStreamSample.new()
audio.mix_rate = sample_rate
audio.stereo = false
audio.set_format(AudioStreamSample.FORMAT_16_BITS)
if (size % 9) != 0:
print_debug('Oh no! An instrument sample has an invalid size of %d! at $%06X' % [size, buffer.get_position()-2])
2023-07-25 14:21:10 +09:30
return audio
var num_packets := size/9
2023-07-25 14:21:10 +09:30
2024-07-10 22:13:58 +09:30
var samples = PoolIntArray([0, 0]) # Start with two zero samples for filter purposes, strip them from the actual output later
var i := 2
for pkt in num_packets:
2023-08-23 19:38:59 +09:30
# Decode a single 9byte BRR packet
var header_byte := buffer.get_u8()
2023-08-23 19:38:59 +09:30
var exponent := header_byte >> 4
var filter := (header_byte >> 2) & 0x03
2024-07-10 22:13:58 +09:30
# var loop := bool(header_byte & 0x02)
2023-08-23 19:38:59 +09:30
var end := bool(header_byte & 0x01)
for sample in 8:
var b := buffer.get_u8()
2023-08-23 19:38:59 +09:30
samples.append(process_sample(b >> 4, exponent))
samples.append(process_sample(b & 0x0F, exponent))
# Apply filter
var l := len(samples)
2023-07-25 14:21:10 +09:30
match filter:
1:
2023-08-23 19:38:59 +09:30
for j in range(l-16, l):
samples[j] = clamp_short(samples[j] + (samples[j-1]*15)/16)
2023-07-25 14:21:10 +09:30
2:
2023-08-23 19:38:59 +09:30
for j in range(l-16, l):
samples[j] = clamp_short(samples[j] + (samples[j-1]*61)/32 - (samples[j-2]*15)/16)
2023-07-25 14:21:10 +09:30
3:
2023-08-23 19:38:59 +09:30
for j in range(l-16, l):
samples[j] = clamp_short(samples[j] + (samples[j-1]*115)/64 - (samples[j-2]*13)/16)
2023-07-25 14:21:10 +09:30
if end:
# print('End flag on packet')
2023-07-25 14:21:10 +09:30
break
2024-07-10 22:13:58 +09:30
# Remove first two zero samples
samples.remove(0)
samples.remove(0)
# Pack 16bit samples to 8bit array
2024-07-10 22:13:58 +09:30
var out_buff = StreamPeerBuffer.new()
for sample in samples:
out_buff.put_16(sample)
audio.data = out_buff.data_array
2023-07-25 14:21:10 +09:30
return audio
func get_inst_sample_data(snes_data: Dictionary, buffer: StreamPeerBuffer, id: int) -> AudioStreamSample:
var sample_rate := get_reference_pitch_samplerate(snes_data.bgm_instrument_samplerates[id] & 0xFF)
var loop_start_packet: int = snes_data.bgm_instrument_loop_starts[id]/9 # Note that Instrument $1F Steel Guitar has a length of $088B but a loop point of $088D which is 243.22... packets. Luckily it doesn't matter.
buffer.seek(snes_data.bgm_instrument_brr_pointers[id] & 0x3FFFFF)
var size := buffer.get_u16()
var num_samples := (size/9)*16
var audio := make_sample(buffer, size, sample_rate)
audio.loop_mode = AudioStreamSample.LOOP_FORWARD
2024-07-10 22:13:58 +09:30
audio.loop_begin = (loop_start_packet * 16) # Each 9byte packet is 16 samples
audio.loop_end = num_samples
# print_debug('Loaded instrument #%02X with lookup offset $%06X, BRR data offset $%06X, length $%04X (%f packets, %d samples) and loop point %d samples' % [id, lookup_offset, brr_offset, size, size/9.0, num_samples, audio.loop_begin])
return audio
2023-07-25 14:21:10 +09:30
2024-07-05 20:59:54 +09:30
# const SFX_BRR_START := 0x041E3F + 2 # First two bytes are the length of the block, 0x010E = 270 bytes = 16 BRR packets = 480 samples
func load_sfx_samples_data(snes_data: Dictionary, buffer: StreamPeerBuffer):
2023-07-25 18:37:55 +09:30
var brr_spc_addrs = []
var brr_spc_loop_addrs = []
for two_of_u16 in snes_data.sfx_brr_pointers:
brr_spc_addrs.append(two_of_u16[0])
brr_spc_loop_addrs.append(two_of_u16[1])
var brr_spc_start = Common.SNES_PSX_addresses.sfx_brr_data.SNES - brr_spc_addrs[0] # Refactor this later - SFX samples start at $4800 in ARAM, right after the SFX tracks
2023-07-25 18:37:55 +09:30
for i in SFX_NUM:
buffer.seek(brr_spc_addrs[i] + brr_spc_start)
# print('Loading sfx sample #%X with BRR data offset $%06X' % [i, buffer.get_position()])
var sample_rate := get_reference_pitch_samplerate(snes_data.sfx_samplerates[i] & 0xFF)
var audio := make_sample(buffer, 900, sample_rate)
var loop_start_packet: int = brr_spc_loop_addrs[i] - brr_spc_addrs[i]
audio.loop_mode = AudioStreamSample.LOOP_FORWARD
audio.loop_begin = (loop_start_packet/9) * 16 # Each 9byte packet is 16 samples
audio.loop_end = (len(audio.data)/2)
sfx_samples.append(audio) # Use 900 as a limit, it won't be hit, parser stops after End packet anyway
emit_signal('audio_sfx_sample_loaded', i)
# print('size of %d samples' % sfx_samples[i].data.size())
2023-07-25 14:21:10 +09:30
# Called when the node enters the scene tree for the first time.
func load_samples(snes_data: Dictionary, buffer: StreamPeerBuffer):
load_sfx_samples_data(snes_data, buffer)
# For some reason, this is a bit slow currently under certain editor conditions. Might optimize later.
2023-07-25 14:21:10 +09:30
for i in INST_NUM:
2024-07-10 22:13:58 +09:30
var samp := get_inst_sample_data(snes_data, buffer, i)
instrument_samples.append(samp)
# Workaround for Godot 3.x quirk where looping samples are interpolated as if they go to nothing instead of looping
2024-07-10 22:13:58 +09:30
instrument_samples_HACK_EXTENDED_LOOPS.append(HACK_EXTEND_LOOP_SAMPLE(samp))
# print('Instrument %02X has mix_rate %d Hz and %d samples'%[i, samp.mix_rate, len(samp.data)/2])
emit_signal('audio_inst_sample_loaded', i)
2024-07-10 22:13:58 +09:30
# samp.save_to_wav('output/instrument%02d(%dHz)(loop from %d to %d of %d).wav' % [i, samp.mix_rate, samp.loop_begin, samp.loop_end, len(samp.data)/2])
# We start the texture with a bunch of same-size headers
# int32 sample_start // The true start, after the prepended 3 frames of silence
# uint16 sample_length // 3 frames after the true end, because of how we loop
# uint16 sample_loop_begin // 3 frames after the true loop point
# uint16 mixrate
var samples_tex: ImageTexture
const TEX_WIDTH := 2048
const FILTER_PAD := 32
func samples_to_texture():
var num_samples := SFX_NUM + INST_NUM
var header_length := (num_samples * 5) + TEX_WIDTH # Use first row for the ADSR tables
2024-07-10 22:13:58 +09:30
# Create header and unwrapped payload separately first
var header_buffer := StreamPeerBuffer.new()
var payload_buffer := StreamPeerBuffer.new()
# Fill first row with ADSR table
for i in ATTACK_TIME_SMPS: # 32 u16 texels
header_buffer.put_u32(i)
for i in SPC_PERIOD_TABLE: # 32 u16 texels
header_buffer.put_u16(i)
for i in SPC_DECAY_CURVE: # 697 u16 texels
header_buffer.put_u16(i)
var remaining_first_row_texels := TEX_WIDTH - (header_buffer.get_position()/2)
for i in remaining_first_row_texels:
header_buffer.put_u16(0)
# Do instrument headers and data in parallel
for sample in sfx_samples + instrument_samples:
2024-07-10 22:13:58 +09:30
var sample_data_start: int = header_length + (payload_buffer.get_position()/2) + FILTER_PAD # After the prepended silence, in texels (2bytes)
var loop_begin: int = sample.loop_begin
var loop_length: int = sample.loop_end - loop_begin
var nonlooping: bool = loop_length <= 0
2024-07-14 23:34:23 +09:30
# print('Processing sample, nonlooping=%s'%nonlooping)
2024-07-10 22:13:58 +09:30
for i in FILTER_PAD: # Prepend frames of silence
payload_buffer.put_16(0)
payload_buffer.put_data(sample.data) # Copy entire S16LE audio data
if nonlooping:
# Append trailing silence for filter safety
for i in FILTER_PAD*5:
payload_buffer.put_16(0)
# Make it loop the trailing silence
loop_begin += FILTER_PAD
loop_length = 1
else:
# Append copies of the loop for filter safety
# var loop_data = sample.data.subarray(sample.loop_begin*2, -1)
# for i in ceil((FILTER_PAD*4)/loop_length):
# payload_buffer.put_data(loop_data)
# Copy frame by frame in case the loop is shorter than padding frames
for i in FILTER_PAD*4:
var pos := payload_buffer.get_position()
payload_buffer.seek(pos - loop_length*2)
var frame := payload_buffer.get_16()
payload_buffer.seek(pos)
payload_buffer.put_16(frame)
header_buffer.put_32(sample_data_start)
header_buffer.put_u16(loop_begin + FILTER_PAD)
header_buffer.put_u16(loop_length)
header_buffer.put_u16(sample.mix_rate)
# Combine the unwrapped arrays
var data := header_buffer.data_array + payload_buffer.data_array
var datasamp := AudioStreamSample.new()
datasamp.data = data
datasamp.mix_rate = 32000
datasamp.format = AudioStreamSample.FORMAT_16_BITS
# datasamp.save_to_wav('output/texture_inst_data.wav')
var needed_rows := (len(data)/2)/float(TEX_WIDTH)
var rows := int(pow(2, ceil(log(needed_rows) / log(2))))
if rows > TEX_WIDTH:
print_debug('Sound Sample Texture rows have exceeded width: %d > %d'%[rows, TEX_WIDTH])
# Now that the full texture size is known, pad our existing data with zeroes until the end
var final_data_size_bytes = rows * TEX_WIDTH * 2
if final_data_size_bytes > len(data):
var end_padding := PoolByteArray()
end_padding.resize(final_data_size_bytes - len(data))
end_padding.fill(0)
data = data + end_padding
# data is complete, turn it into an ImageTexture for the shader to use
var samples_img = Image.new()
samples_img.create_from_data(TEX_WIDTH, rows, false, Image.FORMAT_LA8, data)
self.samples_tex = ImageTexture.new()
self.samples_tex.create_from_image(samples_img, 0) #Texture.FLAG_FILTER)
2023-07-25 14:21:10 +09:30
2023-07-25 16:33:45 +09:30
2023-07-25 14:21:10 +09:30
var player := AudioStreamPlayer.new() # Make one for each channel, later
2024-07-05 20:59:54 +09:30
func play_sample(id: int, pitch_scale: float = 1.0):
2023-08-23 19:38:59 +09:30
print('Playing inst sample #%02X' % id)
2024-07-05 20:59:54 +09:30
player.pitch_scale = pitch_scale
2024-07-10 22:13:58 +09:30
player.stream = instrument_samples_HACK_EXTENDED_LOOPS[id]
2024-07-05 20:59:54 +09:30
player.play(PLAY_START/pitch_scale)
2023-07-25 14:21:10 +09:30
func play_sfx(id: int):
2023-08-23 19:38:59 +09:30
print('Playing sfx sample #%02X' % id)
2024-07-05 20:59:54 +09:30
player.pitch_scale = 1.0
2023-07-25 14:21:10 +09:30
player.stream = sfx_samples[id]
player.play(PLAY_START)
2023-07-25 14:21:10 +09:30
func parse_rom(snes_data: Dictionary, buffer: StreamPeerBuffer):
load_samples(snes_data, buffer)
#load_bgms(buffer)
has_loaded_audio_samples = true
emit_signal('audio_samples_loaded')
2023-07-25 16:33:45 +09:30
2023-07-25 14:21:10 +09:30
func _ready() -> void:
self.player.name = 'player' # Easier to see in the debugger
add_child(self.player)
audio_renderer_viewport = Viewport.new()
audio_renderer_viewport.name = 'audio_renderer_viewport'
audio_renderer_viewport.size_override_stretch = true
audio_renderer_viewport.transparent_bg = true
audio_renderer_viewport.handle_input_locally = false
audio_renderer_viewport.hdr = false
audio_renderer_viewport.render_target_update_mode = Viewport.UPDATE_ALWAYS
# add_child(self.audio_renderer_viewport)
audio_renderer = preload('res://scripts/audio_renderer.gd').new()
audio_renderer.name = 'audio_renderer'
audio_renderer_viewport.add_child(audio_renderer)
get_parent().call_deferred('add_child', audio_renderer_viewport)