diff --git a/font/ter-u24n-test.data b/font/ter-u24n-test.data new file mode 100644 index 0000000..5d93177 Binary files /dev/null and b/font/ter-u24n-test.data differ diff --git a/font/ter-u24n.data b/font/ter-u24n.data new file mode 100644 index 0000000..c999451 Binary files /dev/null and b/font/ter-u24n.data differ diff --git a/font/ter-u24n.data.h b/font/ter-u24n.data.h new file mode 100644 index 0000000..8470564 --- /dev/null +++ b/font/ter-u24n.data.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_font_ter_u24n_data_start __asm("_binary_font_ter_u24n_data_start"); +extern uint32_t _binary_font_ter_u24n_data_end __asm("_binary_font_ter_u24n_data_end"); +extern uint32_t _binary_font_ter_u24n_data_size __asm("_binary_font_ter_u24n_data_size"); + +#ifdef __cplusplus +} +#endif diff --git a/font/ter-u32n-test.data b/font/ter-u32n-test.data new file mode 100644 index 0000000..2cd561d Binary files /dev/null and b/font/ter-u32n-test.data differ diff --git a/font/ter-u32n.data b/font/ter-u32n.data new file mode 100644 index 0000000..a85d9e4 Binary files /dev/null and b/font/ter-u32n.data differ diff --git a/font/ter-u32n.data.h b/font/ter-u32n.data.h new file mode 100644 index 0000000..6fa6e5f --- /dev/null +++ b/font/ter-u32n.data.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_font_ter_u32n_data_start __asm("_binary_font_ter_u32n_data_start"); +extern uint32_t _binary_font_ter_u32n_data_end __asm("_binary_font_ter_u32n_data_end"); +extern uint32_t _binary_font_ter_u32n_data_size __asm("_binary_font_ter_u32n_data_size"); + +#ifdef __cplusplus +} +#endif diff --git a/pcm/dk.adpcm b/pcm/dk.adpcm new file mode 100644 index 0000000..9cc95d0 Binary files /dev/null and b/pcm/dk.adpcm differ diff --git a/pcm/dk.adpcm.h b/pcm/dk.adpcm.h new file mode 100644 index 0000000..95a1f5b --- /dev/null +++ b/pcm/dk.adpcm.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_pcm_dk_adpcm_start __asm("_binary_pcm_dk_adpcm_start"); +extern uint32_t _binary_pcm_dk_adpcm_end __asm("_binary_pcm_dk_adpcm_end"); +extern uint32_t _binary_pcm_dk_adpcm_size __asm("_binary_pcm_dk_adpcm_size"); + +#ifdef __cplusplus +} +#endif diff --git a/pcm/dk.pcm b/pcm/dk.pcm new file mode 100644 index 0000000..34caff3 Binary files /dev/null and b/pcm/dk.pcm differ diff --git a/src/font.cpp b/src/font.cpp new file mode 100644 index 0000000..003954e --- /dev/null +++ b/src/font.cpp @@ -0,0 +1,112 @@ +#include "holly/isp_tsp.hpp" + +#include "texture.hpp" +#include "ta_parameter.hpp" +#include "font.hpp" + +#include "math/float_types.hpp" + +namespace font { + +const font fonts[] = { + [font::ter_u24n] = { + .texture_size = tsp_instruction_word::texture_u_size::from_int(256) + | tsp_instruction_word::texture_v_size::from_int(128), + .texture_offset = texture::offset::ter_u24n, + .texture_width = 256, + .texture_height = 128, + .hori_advance = 12, + .width = 12, + .height = 24, + .row_stride = 21, + }, + [font::ter_u32n] = { + .texture_size = tsp_instruction_word::texture_u_size::from_int(256) + | tsp_instruction_word::texture_v_size::from_int(256), + .texture_offset = texture::offset::ter_u32n, + .texture_width = 256, + .texture_height = 256, + .hori_advance = 16, + .width = 16, + .height = 32, + .row_stride = 16, + } +}; + +void draw_glyph_global(ta_parameter_writer& writer, const font& face) +{ + global_polygon_textured(writer, + para_control::list_type::punch_through, + face.texture_offset, + face.texture_size | tsp_instruction_word::dst_alpha_instr::inverse_src_alpha, + texture_control_word::pixel_format::_4bpp_palette); +} + +static inline vec2 transform_glyph_texture(const font& face, const vec2& t, int char_code) +{ + int row = char_code / face.row_stride; + int col = char_code % face.row_stride; + + return { + (float)(col * face.width + t.x * face.width) / (float)(face.texture_width), + (float)(row * face.height + t.y * face.height) / (float)(face.texture_height), + }; +} + +static inline vec3 transform_glyph_position(const font& face, const vec2& p, float x, float y, float z) +{ + return { + p.x * face.width + x, + p.y * face.height + y, + z + }; +} + +void draw_glyph(ta_parameter_writer& writer, + const font& face, + int c, + float x, float y, float z, + int base_color) +{ + static const vec2 vtx[] = { + { 0, 0 }, + { 1, 0 }, + { 1, 1 }, + { 0, 1 }, + }; + + vec3 ap = transform_glyph_position(face, vtx[0], x, y, z); + vec3 bp = transform_glyph_position(face, vtx[1], x, y, z); + vec3 cp = transform_glyph_position(face, vtx[2], x, y, z); + vec3 dp = transform_glyph_position(face, vtx[3], x, y, z); + + vec2 at = transform_glyph_texture(face, vtx[0], c); + vec2 bt = transform_glyph_texture(face, vtx[1], c); + vec2 ct = transform_glyph_texture(face, vtx[2], c); + vec2 dt = transform_glyph_texture(face, vtx[3], c); + + quad_type_3(writer, + ap, at, + bp, bt, + cp, ct, + dp, dt, + base_color); +} + +void draw_string(ta_parameter_writer& writer, + const font& face, + const char * s, + float x, float y, float z, + int base_color) +{ + const uint8_t * u8 = (const uint8_t *)s; + int len = 0; + while (*u8) { + len += 1; + int c = *u8++; + draw_glyph(writer, face, c - 32, x, y, z, base_color); + x += face.hori_advance; + } +} + +} diff --git a/src/font.hpp b/src/font.hpp new file mode 100644 index 0000000..ecfca89 --- /dev/null +++ b/src/font.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "holly/ta_parameter.hpp" + +namespace font { + + struct font { + uint32_t texture_size; + uint32_t texture_offset; + int16_t texture_width; + int16_t texture_height; + int8_t hori_advance; + int8_t width; + int8_t height; + int8_t row_stride; + + enum font_type { + ter_u24n, + ter_u32n, + }; + }; + + extern const font fonts[]; + + void draw_glyph_global(ta_parameter_writer& writer, const font& face); + + void draw_glyph(ta_parameter_writer& writer, + const font& face, + int c, + float x, float y, float z, + int base_color); + + void draw_string(ta_parameter_writer& writer, + const font& face, + const char * s, + float x, float y, float z, + int base_color); +} diff --git a/src/graphics.cpp b/src/graphics.cpp index 923697f..f216281 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -145,7 +145,10 @@ void graphics_event(ta_multiwriter& multi) multi.op.offset = 0; multi.pt.offset = 0; - graphics_cursor(multi); + if (scene::current_scene == &scene::scenes[scene::id::tracker]) { + graphics_cursor(multi); + } + assert(scene::current_scene->transfer != nullptr); scene::current_scene->transfer(multi); while (ta_in_use); diff --git a/src/graphics_primitive.cpp b/src/graphics_primitive.cpp index ad5889a..36845fe 100644 --- a/src/graphics_primitive.cpp +++ b/src/graphics_primitive.cpp @@ -9,7 +9,7 @@ struct vertex { vec2 t; }; -const vertex quad_vertices[] = { +static const vertex quad_vertices[] = { { { 0, 0 }, {0, 0} }, { { 1, 0 }, {1, 0} }, { { 1, 1 }, {1, 1} }, diff --git a/src/main.cpp b/src/main.cpp index 582c1e2..6f37842 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "sound.hpp" #include "scene/scene.hpp" #include "scene/logo/sound.hpp" +#include "scene/emulator/sound.hpp" #include "cursor.hpp" #include "input.hpp" @@ -42,13 +43,21 @@ void vbr600() graphics_interrupt(istnrm); } else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x360) { // AICA wait(); aica_sound.common.mcire = (1 << 6); // interrupt timer A - wait(); aica_sound.common.tactl_tima = - aica::tactl_tima::TACTL(0) // increment once every sample - | aica::tactl_tima::TIMA(0xfffd) // interrupt after 3 counts - ; - //scene::logo::sound::interrupt(); - interpreter::interrupt(); + if (scene::current_scene == &scene::scenes[scene::id::tracker]) { + wait(); aica_sound.common.tactl_tima + = aica::tactl_tima::TACTL(0) // increment once every sample + | aica::tactl_tima::TIMA(0xfffd) // interrupt after 3 counts + ; + } else { + wait(); aica_sound.common.tactl_tima + = aica::tactl_tima::TACTL(0) // increment once every sample + | aica::tactl_tima::TIMA(0xffff) // interrupt after 1 counts + ; + } + + assert(scene::current_scene->interrupt != nullptr); + scene::current_scene->interrupt(); } else { serial::string("vbr600\n"); interrupt_exception(); @@ -98,7 +107,7 @@ void main() //bool emulator = detect_emulator(); //printf("emulator %d\n", emulator); graphics_init(); - scene::scene_init(); + scene::scene_init(scene::id::tracker); input::state_init(); cursor::init(); @@ -127,5 +136,7 @@ void main() input::state_update(send_buf, recv_buf); graphics_event(multi); + + scene::transition(); } } diff --git a/src/scene/emulator/scene.cpp b/src/scene/emulator/scene.cpp new file mode 100644 index 0000000..0b6a0a6 --- /dev/null +++ b/src/scene/emulator/scene.cpp @@ -0,0 +1,119 @@ +#include "holly/background.hpp" +#include "holly/holly.hpp" + +#include "scene/emulator/scene.hpp" + +#include "holly/ta_bits.hpp" +#include "holly/isp_tsp.hpp" +#include "ta_parameter.hpp" + +#include "framebuffer.hpp" +#include "font.hpp" +#include "scene/emulator/sound.hpp" + +namespace scene::emulator { + const struct scene::scene scene = { + .ta_alloc = ta_alloc_ctrl::pt_opb::_32x4byte + | ta_alloc_ctrl::tm_opb::no_list + | ta_alloc_ctrl::t_opb::no_list + | ta_alloc_ctrl::om_opb::no_list + | ta_alloc_ctrl::o_opb::_32x4byte, + .opb_size = { + .opaque = 32 * 4, + .opaque_modifier = 0, + .translucent = 0, + .translucent_modifier = 0, + .punch_through = 32 * 4 + }, + .transfer = transfer, + .interrupt = sound::interrupt, + .init = init, + .done = done + }; + + static float intensity = 0.0; + + void draw_title(ta_parameter_writer& writer, int color) + { + const font::font& face = font::fonts[font::font::ter_u32n]; + draw_glyph_global(writer, face); + + int h_center = framebuffer.px_width / 2 - (30 * face.width) / 2; + draw_string(writer, face, "Counterfeit Dreamcast Detected", h_center, 35, 0.1, color << 16); + } + + void draw_paragraph(ta_parameter_writer& writer, int color) + { + const char * paragraph[] = { + "Your counterfeit Dreamcast failed a CORE", + "rasterization test.", + "", + "Dreamcast emulator behavior is highly divergent", + "from a genuine Sega Dreamcast. Some emulator", + "authors deliberately choose to forgo accuracy,", + "and instead are developing a distinct and", + "unrelated fantasy-platform.", + "", + "This program only supports genuine Sega", + "Dreamcasts. Other fantasy-platforms and emulators", + "are not supported." + }; + const int paragraph_length = (sizeof (paragraph)) / (sizeof (paragraph[0])); + + const font::font& face = font::fonts[font::font::ter_u24n]; + draw_glyph_global(writer, face); + + float x = 26; + float y = 80; + + int base_color = (color << 16) | (color << 8) | (color << 0); + + for (int i = 0; i < paragraph_length; i++) { + const char * s = paragraph[i]; + draw_string(writer, face, s, x, y, 0.1, base_color); + y += face.height; + } + } + + void transfer(ta_multiwriter& multi) + { + using namespace font; + + if (intensity < 1.0) + intensity += 0.005; + + int color = (int)(255.0 * intensity); + if (color > 255) + color = 255; + + draw_title(multi.pt, color); + draw_paragraph(multi.pt, color); + + global_polygon_untextured(multi.op, + para_control::list_type::opaque, + tsp_instruction_word::dst_alpha_instr::zero); + + quad_type_0(multi.op, + {0, 0, 0.1}, + {0, 0, 0.1}, + {0, 0, 0.1}, + {0, 0, 0.1}, + 0x0); + } + + void init() + { + intensity = 0; + + background_parameter2(texture_memory_alloc.background[1].start, + 0); + holly.VO_BORDER_COL = 0; + + ::scene::emulator::sound::init(); + } + + int done() + { + return -1; + } +} diff --git a/src/scene/emulator/scene.hpp b/src/scene/emulator/scene.hpp new file mode 100644 index 0000000..93ad91a --- /dev/null +++ b/src/scene/emulator/scene.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "ta_multiwriter.hpp" +#include "scene/scene.hpp" + +namespace scene::emulator { + + extern const struct scene::scene scene; + + void transfer(ta_multiwriter& multi); + + void init(); + + int done(); +} diff --git a/src/scene/emulator/sound.cpp b/src/scene/emulator/sound.cpp new file mode 100644 index 0000000..7db21d7 --- /dev/null +++ b/src/scene/emulator/sound.cpp @@ -0,0 +1,82 @@ +#include "aica/aica.hpp" +#include "../../sound.hpp" +#include "scene/logo/sound.hpp" +#include "pcm/dk.adpcm.h" + +#include "printf/printf.h" + +namespace scene::emulator::sound { + + const static void * start = reinterpret_cast(&_binary_pcm_dk_adpcm_start); + const static int size = reinterpret_cast(&_binary_pcm_dk_adpcm_size); + const static int sample_count = size * 2; + const static int loop_length = 65528; + const static int segment_count = sample_count / loop_length; + const static int last_loop = (sample_count % loop_length) & (~0b11); + + void init() + { + printf("init\n"); + ::sound::transfer(start, size); + + wait(); aica_sound.common.afsel_mslc_mobuf + = aica::afsel_mslc_mobuf::AFSEL(0) + | aica::afsel_mslc_mobuf::MSLC(0); + + wait(); aica_sound.channel[0].LPCTL(1); + wait(); aica_sound.channel[0].PCMS(2); // adpcm + wait(); aica_sound.channel[0].LSA(0); + wait(); aica_sound.channel[0].LEA(loop_length); + wait(); aica_sound.channel[0].D2R(0x0); + wait(); aica_sound.channel[0].D1R(0x0); + wait(); aica_sound.channel[0].RR(0x1f); + wait(); aica_sound.channel[0].AR(0x1f); + + wait(); aica_sound.channel[0].OCT(-1); + wait(); aica_sound.channel[0].FNS(0); + wait(); aica_sound.channel[0].DISDL(0xf); + wait(); aica_sound.channel[0].DIPAN(0x0); + + wait(); aica_sound.channel[0].KYONB(0); + wait(); aica_sound.channel[0].KYONEX(1); + } + + void interrupt() + { + static int segment = 0; + static bool last = false; + + wait(); + int lp_sgc_eg = aica_sound.common.lp_sgc_eg; + + if (aica::lp_sgc_eg::SGC(lp_sgc_eg) == 3) { // release + if (segment != 0) + return; + printf("start\n"); + wait(); aica_sound.channel[0].SA(0); + wait(); aica_sound.channel[0].KYONB(1); + wait(); aica_sound.channel[0].KYONEX(1); + return; + } + + if (aica::lp_sgc_eg::LP(lp_sgc_eg)) { + segment += 1; + if (segment >= segment_count) { + if (last || last_loop == 0) { + wait(); aica_sound.channel[0].KYONB(0); + wait(); aica_sound.channel[0].KYONEX(1); + return; + } else { + printf("last loop\n", segment); + last = true; + wait(); aica_sound.channel[0].LEA(last_loop); + } + } + + printf("loop %d\n", segment); + int sa = 0 + (loop_length / 2) * segment; + wait(); aica_sound.channel[0].SA(sa); + } + } + +} diff --git a/src/scene/emulator/sound.hpp b/src/scene/emulator/sound.hpp new file mode 100644 index 0000000..61c090d --- /dev/null +++ b/src/scene/emulator/sound.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace scene::emulator::sound { + + void init(); + + void interrupt(); +} diff --git a/src/scene/logo/scene.cpp b/src/scene/logo/scene.cpp index 31d722e..620f831 100644 --- a/src/scene/logo/scene.cpp +++ b/src/scene/logo/scene.cpp @@ -1,3 +1,6 @@ +#include "holly/background.hpp" +#include "holly/holly.hpp" + #include "math/float_types.hpp" #include "math/transform.hpp" @@ -144,7 +147,9 @@ namespace scene::logo { .punch_through = 0 }, .transfer = transfer, - .init = init + .interrupt = sound::interrupt, + .init = init, + .done = done }; static int tick = 0; @@ -257,6 +262,21 @@ namespace scene::logo { void init() { + background_parameter2(texture_memory_alloc.background[1].start, + 0xc0bebc); + holly.VO_BORDER_COL = 0xc0bebc; + ::scene::logo::sound::init(); } + + int done() + { + if (tick >= (20.000 * 60)) { + int scene_id = ::scene::id::tracker; + printf("scene transition to tracker %d\n", scene_id); + return scene_id; + } + + return -1; + } } diff --git a/src/scene/logo/scene.hpp b/src/scene/logo/scene.hpp index 6b2d2d9..46720d9 100644 --- a/src/scene/logo/scene.hpp +++ b/src/scene/logo/scene.hpp @@ -10,5 +10,7 @@ namespace scene::logo { void init(); + int done(); + extern const struct scene::scene scene; } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 12f3b06..2e90e38 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -3,17 +3,20 @@ #include "scene/scene.hpp" #include "scene/tracker/scene.hpp" #include "scene/logo/scene.hpp" - -static const scene::scene scenes[] = { - scene::tracker::scene, - scene::logo::scene, -}; +#include "scene/emulator/scene.hpp" namespace scene { - const scene * current_scene = &scenes[0]; + const scene scenes[] = { + [id::tracker] = tracker::scene, + [id::logo] = logo::scene, + [id::emulator] = emulator::scene, + }; - void scene_init() + const scene * current_scene = nullptr; + + void scene_init(int scene_id) { + current_scene = &scenes[scene_id]; graphics_scene_init(¤t_scene->opb_size); printf("scene init\n"); @@ -22,4 +25,13 @@ namespace scene { current_scene->init(); } } + + void transition() + { + assert(current_scene->done != nullptr); + int scene_id = current_scene->done(); + if (scene_id >= 0) { + scene_init(scene_id); + } + } } diff --git a/src/scene/scene.hpp b/src/scene/scene.hpp index c265b71..56be6de 100644 --- a/src/scene/scene.hpp +++ b/src/scene/scene.hpp @@ -4,15 +4,28 @@ #include "ta_multiwriter.hpp" namespace scene { + namespace id { + enum scene_type { + tracker, + logo, + emulator + }; + } struct scene { const uint32_t ta_alloc; const struct opb_size opb_size; void (* const transfer)(ta_multiwriter& multi); + void (* const interrupt)(); void (* const init)(); + int (* const done)(); }; + extern const scene scenes[]; + extern const scene * current_scene; - void scene_init(); + void scene_init(int scene_id); + + void transition(); } diff --git a/src/scene/tracker/scene.cpp b/src/scene/tracker/scene.cpp index 0935314..b5377a5 100644 --- a/src/scene/tracker/scene.cpp +++ b/src/scene/tracker/scene.cpp @@ -1,3 +1,5 @@ +#include "holly/background.hpp" +#include "holly/holly.hpp" #include "holly/ta_bits.hpp" #include "ta_parameter.hpp" @@ -149,11 +151,17 @@ namespace scene::tracker { .punch_through = 32 * 4 }, .transfer = transfer, + .interrupt = interpreter::interrupt, .init = init, + .done = done, }; void init() { + background_parameter2(texture_memory_alloc.background[1].start, + 0x110012); + holly.VO_BORDER_COL = 0x110012; + float y = 8 + ((glyph::vert_advance + 5) * 2) + 8; top.freeze(5, y); playlist::next(); @@ -225,4 +233,9 @@ namespace scene::tracker { notes::draw(multi, 5, y); } + + int done() + { + return -1; + } } diff --git a/src/scene/tracker/scene.hpp b/src/scene/tracker/scene.hpp index 3ed25fd..cb54e88 100644 --- a/src/scene/tracker/scene.hpp +++ b/src/scene/tracker/scene.hpp @@ -10,5 +10,7 @@ namespace scene::tracker { void init(); + int done(); + extern const struct scene::scene scene; } diff --git a/src/texture.cpp b/src/texture.cpp index 26a686c..3c3ed91 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -13,6 +13,8 @@ #include "model/32bitlogo/colors.data.h" #include "font/icons.data.h" #include "cover/cover1.data.h" +#include "font/ter-u24n.data.h" +#include "font/ter-u32n.data.h" namespace texture { @@ -32,6 +34,16 @@ namespace texture { .size = reinterpret_cast(&_binary_font_icons_data_size), .offset = offset::icons, }, + { + .start = reinterpret_cast(&_binary_font_ter_u24n_data_start), + .size = reinterpret_cast(&_binary_font_ter_u24n_data_size), + .offset = offset::ter_u24n, + }, + { + .start = reinterpret_cast(&_binary_font_ter_u32n_data_start), + .size = reinterpret_cast(&_binary_font_ter_u32n_data_size), + .offset = offset::ter_u32n, + }, { .start = reinterpret_cast(&_binary_cover_cover1_data_start), .size = reinterpret_cast(&_binary_cover_cover1_data_size), diff --git a/src/texture.hpp b/src/texture.hpp index 6814cb9..7a73807 100644 --- a/src/texture.hpp +++ b/src/texture.hpp @@ -8,10 +8,12 @@ namespace texture { }; namespace offset { - constexpr int tandy1k = 0; // 16384 - constexpr int logo = tandy1k + 16384; // 128 * 3 - constexpr int icons = logo + (128 * 3); // 2048 - constexpr int cover1 = icons + 2048; + constexpr int tandy1k = 0 ; // 16384 + constexpr int logo = tandy1k + 16384; // 384 + constexpr int icons = logo + 384; // 2048 + constexpr int ter_u24n = icons + 2048; // 16384 + constexpr int ter_u32n = ter_u24n + 16384; // 32768 + constexpr int cover1 = ter_u32n + 32768; // 32768 }; extern struct texture textures[]; diff --git a/xm_player.mk b/xm_player.mk index 7249869..c899c67 100644 --- a/xm_player.mk +++ b/xm_player.mk @@ -8,10 +8,13 @@ TEXTURE_OBJ = \ font/icons.data.o \ model/32bitlogo/colors.data.o \ cover/cover1.data.o \ - reference_render.data.o + reference_render.data.o \ + font/ter-u24n.data.o \ + font/ter-u32n.data.o PCM_OBJ = \ - pcm/start3.adpcm.o + pcm/start3.adpcm.o \ + pcm/dk.adpcm.o XM_PLAYER_OBJ = \ $(LIB)/holly/core.o \ @@ -25,6 +28,7 @@ XM_PLAYER_OBJ = \ $(LIB)/printf/printf.o \ $(LIB)/printf/unparse.o \ $(LIB)/printf/parse.o \ + src/font.o \ src/icons.o \ src/cursor.o \ src/detect_emulator.o \ @@ -38,6 +42,8 @@ XM_PLAYER_OBJ = \ src/playlist.o \ src/scene/logo/scene.o \ src/scene/logo/sound.o \ + src/scene/emulator/scene.o \ + src/scene/emulator/sound.o \ src/scene/scene.o \ src/scene/tracker/channel_status.o \ src/scene/tracker/cover.o \