[WIP] Audio shader almost working
This commit is contained in:
parent
e077c4e036
commit
fbd3dd52c7
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue