[WIP] Audio shader almost working

This commit is contained in:
Luke Hubmayer-Werner 2024-07-12 01:56:05 +09:30
parent e077c4e036
commit fbd3dd52c7
4 changed files with 27 additions and 26 deletions

View File

@ -189,7 +189,7 @@ const TEX_WIDTH := 2048
const FILTER_PAD := 3
func samples_to_texture():
var num_samples := INST_NUM + SFX_NUM
var header_length := num_samples * 6
var header_length := num_samples * 8
# Create header and unwrapped payload separately first
var header_buffer := StreamPeerBuffer.new()
@ -201,15 +201,16 @@ func samples_to_texture():
var nonlooping: bool = loop_begin >= loop_end
if nonlooping:
loop_begin = loop_end
loop_end += 1
header_buffer.put_u16(header_length + (payload_buffer.get_position()/2) + FILTER_PAD) # sample_start
header_buffer.put_u16(sample.loop_end + FILTER_PAD) # sample_length
header_buffer.put_u16(sample.loop_begin + FILTER_PAD) # sample_loop_begin
loop_end += 3
header_buffer.put_32(header_length + (payload_buffer.get_position()/2) + FILTER_PAD) # sample_start
header_buffer.put_u16(loop_end + FILTER_PAD) # sample_length
header_buffer.put_u16(loop_begin + FILTER_PAD) # sample_loop_begin
header_buffer.put_u16(sample.mix_rate) # sample_mixrate
header_buffer.put_u8(0) # TODO: attack
header_buffer.put_u8(0) # TODO: decay
header_buffer.put_u8(0) # TODO: sustain
header_buffer.put_u8(0) # TODO: release
header_buffer.put_u16(0) # TODO: unk
for i in FILTER_PAD: # Prepend 3 frames of silence
payload_buffer.put_16(0)
payload_buffer.put_data(sample.data) # Copy entire S16LE audio data
@ -251,7 +252,7 @@ func samples_to_texture():
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, Texture.FLAG_FILTER)
self.samples_tex.create_from_image(samples_img, 0) #Texture.FLAG_FILTER)
var player := AudioStreamPlayer.new() # Make one for each channel, later

View File

@ -98,7 +98,7 @@ vec4 test_writeback(sampler2D tex, vec2 uv) {
// With the 258 texel header, which uses 3 texels of margin, 255 would be subtracted from the above payload,
// leaving 261121 texels for the sample data.
const float HEADER_LENGTH_TEXELS = 6.0;
const float HEADER_LENGTH_TEXELS = 8.0;
uniform sampler2D instrument_samples;
uniform vec2 instrument_samples_size = vec2(2048.0, 128.0);
uniform float instrument_row_padding = 3.0; // In case we want to go to cubic filtering
@ -115,15 +115,21 @@ vec2 get_inst_texel(vec2 xy) {
return texture(instrument_samples, xy/instrument_samples_size).xw;
}
float get_inst_texel_int16(float s) {
float x = mod(s, instrument_row_payload) + instrument_row_padding;
float y = trunc(s / instrument_row_payload);
return unpack_int16(texture(instrument_samples, (vec2(x, y) + 0.5)/instrument_samples_size).xw);
}
float get_instrument_sample(float instrument_index, float pitch_scale, float t, float t_end) {
// t_end is for ADSR purposes
float header_offset = instrument_index * HEADER_LENGTH_TEXELS;
float sample_start = unpack_uint16(get_inst_texel(vec2(header_offset, 0.0))); // The true start, after the prepended 3 frames of silence
float sample_length = unpack_uint16(get_inst_texel(vec2(header_offset + 1.0, 0.0))); // 3 frames after the true end, because of how we loop
float sample_loop_begin = unpack_uint16(get_inst_texel(vec2(header_offset + 2.0, 0.0))); // 3 frames after the true loop point
float sample_mixrate = unpack_uint16(get_inst_texel(vec2(header_offset + 3.0, 0.0)));
vec2 attack_decay = get_inst_texel(vec2(header_offset + 4.0, 0.0));
vec2 sustain_release = get_inst_texel(vec2(header_offset + 5.0, 0.0));
float sample_start = float(unpack_int32(vec4(get_inst_texel(vec2(header_offset, 0.0)), get_inst_texel(vec2(header_offset + 1.0, 0.0))))); // The true start, after the prepended 3 frames of silence
float sample_length = unpack_uint16(get_inst_texel(vec2(header_offset + 2.0, 0.0))); // 3 frames after the true end, because of how we loop
float sample_loop_begin = unpack_uint16(get_inst_texel(vec2(header_offset + 3.0, 0.0))); // 3 frames after the true loop point
float sample_mixrate = unpack_uint16(get_inst_texel(vec2(header_offset + 4.0, 0.0)));
vec2 attack_decay = get_inst_texel(vec2(header_offset + 5.0, 0.0));
vec2 sustain_release = get_inst_texel(vec2(header_offset + 6.0, 0.0));
// Calculate the point we want to sample in linear space
float mixrate = sample_mixrate * pitch_scale;
float target_frame = t * mixrate;
@ -134,10 +140,11 @@ float get_instrument_sample(float instrument_index, float pitch_scale, float t,
target_frame -= overshoot_loops*loop_length;
// Now we need to identify the sampling point since our frames are spread across multiple rows for GPU reasons
// We only sample from texel 4 onwards on a given row - texel 0 is the header, texels 1,2,3 are lead-in for filtering
// Note that y should be integral, but x should be continuous, as that's what applies the filtering!
target_frame += sample_start;
vec2 sample_xy = vec2(instrument_row_padding + mod(target_frame, instrument_row_payload), trunc(target_frame/instrument_row_payload));
return rescale_int16(unpack_int16(get_inst_texel(sample_xy)));
float a = get_inst_texel_int16(floor(target_frame));
float b = get_inst_texel_int16(ceil(target_frame));
float mix_amount = fract(target_frame);
return rescale_int16(mix(a, b, mix_amount));
}
const int NUM_CHANNELS = 8;
@ -196,13 +203,7 @@ vec4 render_song(int smp) {
}
}
// Convert the stereo float audio to S16LE
// return vec4(pack_float_to_int16(downmixed_stereo.x), pack_float_to_int16(downmixed_stereo.y));
// return vec4(pack_float_to_int16(downmixed_stereo.x), pack_float_to_int16(mod(t, 2.0) - 1.0));
vec2 isuv = vec2(mod(float(smp), instrument_samples_size.x), trunc(float(smp)/instrument_samples_size.x))/instrument_samples_size;
// float ins = rescale_int16(unpack_int16(texture(instrument_samples, isuv).xw));
// return vec4(pack_float_to_int16(ins), pack_float_to_int16(mod(t, 2.0) - 1.0));
return vec4(texture(instrument_samples, isuv).xw, pack_float_to_int16(mod(t, 2.0) - 1.0));
// return vec4(pack_float_to_int16((t/10.0) - 1.0), pack_float_to_int16(mod(t, 2.0) - 1.0));
return vec4(pack_float_to_int16(downmixed_stereo.x), pack_float_to_int16(downmixed_stereo.y));
}
void fragment() {

View File

@ -138,9 +138,9 @@ func test_rendering() -> void:
var midi_events_bytes3 := StreamPeerBuffer.new()
var midi_events_bytes4 := StreamPeerBuffer.new()
for i in 2048:
var t = i * 10.0
var t = i * 3.0
midi_events_bytes.put_32(t*32000) # t_start
midi_events_bytes2.put_32((t+3.0)*32000) # t_end
midi_events_bytes2.put_32((t+2.75)*32000) # t_end
midi_events_bytes3.put_u8((i%35)) # instrument
midi_events_bytes3.put_u8(71) # pitch_idx
# midi_events_bytes.put_float((35 + (i%40))) # pitch_idx

View File

@ -13,7 +13,6 @@ shader_param/instrument_row_payload = 2042.0
shader_param/reference_note = 71.0
shader_param/output_mixrate = 32000.0
shader_param/midi_events_size = Vector2( 2048, 16 )
shader_param/t_scale = 524.0
[node name="audio_system" type="Node2D"]
script = ExtResource( 1 )