diff --git a/src/graphics.cpp b/src/graphics.cpp index 213d03d..d517364 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -561,13 +561,116 @@ void transfer_middle_line(ta_parameter_writer& writer, float x, float y) 0x202020); } +static inline int round_up_div(int n, int m) +{ + int div = n / m; + int rem = n % m; + if (rem == 0) + return div; + return div + 1; +} + +static inline int round_up(int n, int m) +{ + int rem = n % m; + if (rem == 0) + return n; + return n + m - rem; +} + +void transfer_rectangle(ta_parameter_writer& writer, + float x, float y, float z, + float width, float height, + uint32_t base_color) +{ + quad_type_0(writer, + {x + 0, y + 0, z}, + {x + width, y + 0, z}, + {x + width, y + height, z}, + {x + 0, y + height, z}, + base_color); +} + +void transfer_channel_status(ta_parameter_writer& writer, int x, int y) +{ + using namespace interpreter; + + const int channel_status_height = 50; + + int max_channels_per_row = framebuffer.px_width / 40; + int rows = round_up_div(state.xm.number_of_channels, max_channels_per_row); + assert(rows > 0); + int number_of_channels = round_up(state.xm.number_of_channels, rows); + int channels_per_row = number_of_channels / rows; + int width_per_col = (framebuffer.px_width - 3) / channels_per_row; + int offset = (framebuffer.px_width - (width_per_col * channels_per_row)) / 2; + + int inner_width = width_per_col - 3; + + int height_per_row = channel_status_height / rows; + int vert_center = height_per_row / 2 - glyph_vert_advance / 2; + + int ch = 0; + for (int row = 0; row < rows; row++) { + int xi = x + offset - 2; + + global_polygon_untextured(writer, + para_control::list_type::opaque, + tsp_instruction_word::dst_alpha_instr::zero); + + transfer_horizontal_border(writer, xi, y, width_per_col * channels_per_row); + + for (int col = 0; col < channels_per_row; col++) { + + global_polygon_untextured(writer, + para_control::list_type::opaque, + tsp_instruction_word::dst_alpha_instr::zero); + + transfer_vertical_border(writer, xi, y, height_per_row); + + int keyon = 128 * (state.channel[ch].keyon - 224) / 16; + if (keyon < 0) keyon = 0; + uint32_t base_color = (keyon << 16) | (keyon << 8) | (keyon << 0); + transfer_rectangle(writer, + xi, y, 1.0 / 10000.0, + width_per_col, height_per_row, + base_color); + + if (ch < state.xm.number_of_channels) { + global_polygon_textured(writer, + para_control::list_type::opaque); + + int hori_center = inner_width / 2 - (glyph_hori_advance * (ch >= 10)) / 2; + transfer_integer(writer, ch, xi + hori_center, y + vert_center, + 0, 0, + 0xa7a7a7); + } + + xi += width_per_col; + ch += 1; + } + + global_polygon_untextured(writer, + para_control::list_type::opaque, + tsp_instruction_word::dst_alpha_instr::zero); + + transfer_vertical_border(writer, xi, y, height_per_row); + + y += height_per_row; + } + + int xi = x + offset - 2; + transfer_horizontal_border(writer, xi, y, width_per_col * channels_per_row); +} + void transfer_scene(ta_parameter_writer& writer) { const int x = 3; - const int y = 48; + const int y = 100; { // punch-through - global_polygon_textured(writer); + global_polygon_textured(writer, + para_control::list_type::punch_through); transfer_lines(writer, x, y); @@ -593,6 +696,8 @@ void transfer_scene(ta_parameter_writer& writer) transfer_borders(writer, x, y); + transfer_channel_status(writer, 0, 0); + writer.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); } diff --git a/src/interpreter.cpp b/src/interpreter.cpp index b20916c..a7c4022 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -113,7 +113,7 @@ void _play_note(int ch, const xm_pattern_format_t * pf) wait(); aica_sound.channel[ch].PLFOS(0); } - state.channel[ch].keyon = 1; + state.channel[ch].keyon = 255; wait(); aica_sound.channel[ch].KYONB(0); } @@ -227,9 +227,9 @@ void interrupt() break; } */ - if (state.channel[ch].keyon != 0) { + if (state.channel[ch].keyon == 255) { wait(); aica_sound.channel[ch].KYONB(1); - state.channel[ch].keyon = 0; + state.channel[ch].keyon -= 1; } } wait(); aica_sound.channel[0].KYONEX(1); @@ -237,6 +237,12 @@ void interrupt() if ((state.interrupt_clock % state.tick_rate) != 0) { return; } + for (int ch = 0; ch < 64; ch++) { + int keyon = state.channel[ch].keyon; + if (keyon != 255 && keyon != 0) { + state.channel[ch].keyon -= 1; + } + } int tick = state.tick % state.ticks_per_line; bool note_tick = tick == 0; diff --git a/src/ta_parameter.hpp b/src/ta_parameter.hpp index c71b965..a91d454 100644 --- a/src/ta_parameter.hpp +++ b/src/ta_parameter.hpp @@ -1,12 +1,12 @@ -void global_polygon_textured(ta_parameter_writer& writer) +void global_polygon_textured(ta_parameter_writer& writer, uint32_t list_type) { const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume - | para_control::list_type::punch_through + | list_type | obj_control::col_type::packed_color | obj_control::texture ; - const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater_or_equal | isp_tsp_instruction_word::culling_mode::no_culling; const uint32_t tsp_instruction_word = tsp_instruction_word::texture_shading_instruction::modulate @@ -39,7 +39,7 @@ void global_polygon_untextured(ta_parameter_writer& writer, uint32_t list_type, | obj_control::col_type::packed_color ; - const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater_or_equal | isp_tsp_instruction_word::culling_mode::no_culling; const uint32_t tsp_instruction_word = tsp_instruction_word::texture_shading_instruction::modulate