2021-03-21 18:35:04 +00:00
|
|
|
#pragma option -zCSHARED_ -k-
|
2021-02-28 18:10:51 +00:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "platform.h"
|
|
|
|
#include "x86real.h"
|
|
|
|
#include "pc98.h"
|
|
|
|
#include "planar.h"
|
2021-03-07 12:07:29 +00:00
|
|
|
#include "decomp.hpp"
|
2021-02-28 18:10:51 +00:00
|
|
|
#include "master.hpp"
|
|
|
|
#include "libs/kaja/kaja.h"
|
|
|
|
#include "th05/music/piano.h"
|
2021-04-17 18:08:30 +00:00
|
|
|
#include "th05/sprites/piano_l.hpp"
|
2021-02-28 18:10:51 +00:00
|
|
|
|
|
|
|
/// Coordinates
|
|
|
|
/// -----------
|
|
|
|
|
|
|
|
static const screen_x_t PIANO_LEFT = 384;
|
|
|
|
static const vram_y_t PIANO_TOP = 64;
|
|
|
|
static const pixel_t PIANO_H = 15;
|
|
|
|
static const pixel_t PIANO_KEY_W = 4;
|
|
|
|
static const pixel_t PIANO_BLACK_H = 9;
|
|
|
|
static const pixel_t PIANO_BLACK_PRESSED_H = 8;
|
|
|
|
static const pixel_t PIANO_PADDING_BOTTOM = 3;
|
|
|
|
static const pixel_t PIANO_H_PADDED = (PIANO_H + PIANO_PADDING_BOTTOM);
|
|
|
|
|
|
|
|
static const int PIANO_OCTAVES = 8;
|
|
|
|
static const pixel_t PIANO_OCTAVE_W = (7 * PIANO_KEY_W);
|
|
|
|
|
|
|
|
static const vram_x_t PIANO_VRAM_LEFT = (PIANO_LEFT / BYTE_DOTS);
|
|
|
|
static const vram_byte_amount_t PIANO_VRAM_W = (
|
|
|
|
(PIANO_OCTAVES * PIANO_OCTAVE_W) / BYTE_DOTS
|
|
|
|
);
|
|
|
|
|
|
|
|
static const pixel_t PIANO_LABEL_DIST_X = 32;
|
|
|
|
static const pixel_t PIANO_LABEL_DIST_Y = 4;
|
|
|
|
|
|
|
|
static inline screen_x_t label_left(int col) {
|
|
|
|
return (PIANO_LEFT - PIANO_LABEL_DIST_X + (col * PIANO_LABEL_FONT_W));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline screen_x_t label_top(int row) {
|
|
|
|
return (PIANO_TOP + PIANO_LABEL_DIST_Y + (row * PIANO_H_PADDED));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline vram_y_t part_top(int part_id) {
|
|
|
|
return (PIANO_TOP + (part_id * PIANO_H_PADDED));
|
|
|
|
}
|
|
|
|
/// -----------
|
|
|
|
|
|
|
|
// Sprite data
|
|
|
|
extern const dots8_t PIANO_KEYS_BLACK[PIANO_VRAM_W];
|
|
|
|
|
|
|
|
/// Note data
|
|
|
|
/// ---------
|
|
|
|
|
|
|
|
// Actually a single `OPEN_WORK far *`.
|
|
|
|
extern uint16_t pmd_workadr[2];
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char fm[5];
|
|
|
|
char unused[3]; // SSG?
|
|
|
|
} piano_notes_t;
|
|
|
|
|
|
|
|
extern piano_notes_t piano_notes_cur;
|
|
|
|
extern piano_notes_t piano_notes_prev;
|
|
|
|
/// ---------
|
|
|
|
|
|
|
|
/// Redundant garbage
|
|
|
|
/// -----------------
|
|
|
|
|
|
|
|
#undef grcg_setmode
|
|
|
|
#undef grcg_off
|
|
|
|
|
|
|
|
#define grcg_setmode(mode) __asm { \
|
|
|
|
mov al, mode; \
|
|
|
|
out 0x7C, al; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define grcg_off() __asm { \
|
|
|
|
db 0x32, 0xC0; /* XOR AL, AL (alternate encoding) */ \
|
|
|
|
out 0x7C, al; \
|
|
|
|
}
|
|
|
|
|
|
|
|
void near grcg_setcolor_direct_seg1_raw();
|
|
|
|
#define grcg_setcolor(col) { \
|
|
|
|
_AH = col; \
|
|
|
|
grcg_setcolor_direct_seg1_raw(); \
|
|
|
|
}
|
|
|
|
/// -----------------
|
|
|
|
|
2021-02-27 14:49:28 +00:00
|
|
|
/// Helper functions
|
|
|
|
/// ----------------
|
|
|
|
|
|
|
|
// Additionally takes:
|
|
|
|
// • `void far *vram_at_x0_and_top_of_part<es:di>`
|
|
|
|
// • `int fm_part_id` in SI
|
|
|
|
// • `void __seg *original_data_ds` in FS
|
|
|
|
// Draws a piano with the currently pressed note retrieved from [qq]. In
|
|
|
|
// addition to SI, the part is also indicated through the VRAM offset in
|
|
|
|
// ES:DI.
|
|
|
|
void __fastcall near piano_fm_part_put_raw(
|
|
|
|
int16_t ax_unused, int16_t dx_unused, QQ near *near *qq
|
|
|
|
);
|
2021-02-28 18:10:51 +00:00
|
|
|
#define piano_fm_part_put(part_id, qq) \
|
|
|
|
_DI = vram_offset_shift(0, part_top(part_id)); \
|
|
|
|
__asm { mov si, part_id; } \
|
|
|
|
piano_fm_part_put_raw(_AX, _DX, qq);
|
2021-02-27 14:49:28 +00:00
|
|
|
|
|
|
|
// Returns the currently played note from [qq] as a KAJA onkai value, or
|
|
|
|
// ONKAI_REST if none is played.
|
|
|
|
char __fastcall near piano_current_note_from(
|
|
|
|
int16_t ax_unused, int16_t dx_unused, QQ near *near *qq
|
2021-02-28 18:10:51 +00:00
|
|
|
);
|
2021-02-27 14:49:28 +00:00
|
|
|
|
|
|
|
// Additionally takes:
|
|
|
|
// • `void far *vram_at_x0_and_top_of_part<es:di>`
|
|
|
|
// Draws a blank piano, for the part is indicated through the VRAM offset in
|
|
|
|
// ES:DI.
|
|
|
|
void near piano_part_keys_put_raw();
|
2021-02-28 18:10:51 +00:00
|
|
|
inline void piano_part_keys_put(int part_id) {
|
|
|
|
_DI = vram_offset_shift(0, part_top(part_id));
|
|
|
|
piano_part_keys_put_raw();
|
|
|
|
}
|
2021-02-27 14:49:28 +00:00
|
|
|
|
|
|
|
// Additionally takes:
|
|
|
|
// • `void far *vram_at_x0_and_top_of_part<es:di>`
|
|
|
|
// Draws the key given in [onkai] as pressed. The part is indicated through
|
|
|
|
// the VRAM offset in ES:DI.
|
|
|
|
void __fastcall near piano_pressed_key_put(char onkai);
|
|
|
|
|
|
|
|
// Additionally takes:
|
|
|
|
// • `void far *vram_at_x0_and_top_of_part<es:di>`
|
|
|
|
// Blits a piano label character to the top-left VRAM position indicated in
|
|
|
|
// ES:DI. Assumes that the GRCG is active.
|
|
|
|
void __fastcall near piano_label_put_raw(piano_label_t label_char);
|
2021-02-28 18:10:51 +00:00
|
|
|
inline void piano_label_putc(int col, int row, piano_label_t chr) {
|
|
|
|
_AL = chr;
|
|
|
|
_DI = vram_offset_muldiv(label_left(col), label_top(row));
|
|
|
|
piano_label_put_raw(static_cast<piano_label_t>(_AL));
|
|
|
|
}
|
|
|
|
#define piano_label_puts(row, chr1, chr2, chr3) \
|
|
|
|
piano_label_putc(0, row, pl_##chr1); \
|
|
|
|
piano_label_putc(1, row, pl_##chr2); \
|
|
|
|
piano_label_putc(2, row, pl_##chr3);
|
2021-02-27 14:49:28 +00:00
|
|
|
/// ----------------
|
2021-02-28 18:10:51 +00:00
|
|
|
|
|
|
|
void piano_setup_and_put_initial(void)
|
|
|
|
{
|
|
|
|
grcg_setmode(GC_RMW);
|
|
|
|
_ES = SEG_PLANE_B;
|
|
|
|
// Thanks, Turbo C++, for indicating that SI actually didn't need to be
|
|
|
|
// saved in this function!
|
|
|
|
_SI = _SI;
|
|
|
|
|
|
|
|
piano_part_keys_put(0);
|
|
|
|
piano_part_keys_put(1);
|
|
|
|
piano_part_keys_put(2);
|
|
|
|
piano_part_keys_put(3);
|
|
|
|
piano_part_keys_put(4);
|
|
|
|
piano_part_keys_put(5);
|
|
|
|
|
|
|
|
grcg_setcolor(GC_RI);
|
|
|
|
piano_label_puts(0, F, M, 1);
|
|
|
|
piano_label_puts(1, F, M, 2);
|
|
|
|
piano_label_puts(2, F, M, 3);
|
|
|
|
piano_label_puts(3, F, M, 4);
|
|
|
|
piano_label_puts(4, F, M, 5);
|
|
|
|
piano_label_puts(5, S, S, G);
|
|
|
|
grcg_off();
|
|
|
|
|
|
|
|
__asm { push ds; }
|
|
|
|
_AH = PMD_GET_WORKAREA_ADDRESS;
|
|
|
|
geninterrupt(PMD);
|
|
|
|
_AX = _DS;
|
|
|
|
__asm { pop ds; }
|
|
|
|
|
|
|
|
// pmd_workadr = reinterpret_cast<OPEN_WORK far *>(MK_FP(_DX, _AX));
|
|
|
|
pmd_workadr[0] = _DX;
|
|
|
|
pmd_workadr[1] = _AX;
|
|
|
|
}
|
|
|
|
|
|
|
|
void piano_render(void)
|
|
|
|
{
|
|
|
|
__asm { push ds; }
|
|
|
|
__asm { push ds; }
|
|
|
|
__emit__(0x0F, 0xA1); // POP FS
|
|
|
|
|
|
|
|
grcg_setmode(GC_RMW);
|
|
|
|
_ES = SEG_PLANE_B;
|
|
|
|
|
|
|
|
piano_part_keys_put(5);
|
|
|
|
|
|
|
|
__asm { lds bx, dword ptr pmd_workadr; } // BX = FMPart[0]
|
|
|
|
|
|
|
|
#define _BX reinterpret_cast<QQ near *near *>(_BX)
|
|
|
|
|
|
|
|
piano_fm_part_put(0, _BX); _BX++; // BX = FMPart[1]
|
|
|
|
piano_fm_part_put(1, _BX); _BX++; // BX = FMPart[2]
|
|
|
|
piano_fm_part_put(2, _BX); _BX++; // BX = FMPart[3]
|
|
|
|
piano_fm_part_put(3, _BX); _BX++; // BX = FMPart[4]
|
|
|
|
piano_fm_part_put(4, _BX);
|
|
|
|
|
|
|
|
grcg_setcolor(GC_RI);
|
|
|
|
_DI = vram_offset_shift(0, part_top(5));
|
|
|
|
_BX += 2; // BX = SSGPart[0]
|
|
|
|
piano_pressed_key_put(piano_current_note_from(_AX, _DX, _BX));
|
|
|
|
_BX++; // BX = SSGPart[1]
|
|
|
|
piano_pressed_key_put(piano_current_note_from(_AX, _DX, _BX));
|
|
|
|
|
|
|
|
#undef _BX
|
|
|
|
|
|
|
|
grcg_off();
|
|
|
|
|
|
|
|
__asm { pop ds; }
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|