Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
334 lines
9.5 KiB
C
334 lines
9.5 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// VGM format sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
#include "msxgl.h"
|
|
#include "psg.h"
|
|
#include "wyz/wyz_player2.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
#define PLAYER_Y 4
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x02\x03\x04\x05"
|
|
|
|
// VGM music entry
|
|
struct MusicEntry
|
|
{
|
|
const c8* Name;
|
|
u16 Song;
|
|
u16 Inst;
|
|
u16 FX;
|
|
u16 Freq;
|
|
};
|
|
|
|
// Player button entry
|
|
struct ButtonEntry
|
|
{
|
|
u8 Char;
|
|
callback Func;
|
|
};
|
|
|
|
// Button callbacks
|
|
void ButtonPlay();
|
|
void ButtonPause();
|
|
void ButtonStop();
|
|
void ButtonPrev();
|
|
void ButtonNext();
|
|
void ButtonLoop();
|
|
|
|
// Music
|
|
extern u16 WYZ_songs;
|
|
extern u16 WYZ_instruments;
|
|
extern u16 WYZ_FXs;
|
|
extern u16 WYZ_notes;
|
|
extern u16 RA_PSG_Song;
|
|
extern u16 RA_PSG_Inst;
|
|
extern u16 RA_PSG_FX;
|
|
extern u16 RA_PSG_Freq;
|
|
extern u16 jinj_med_Song;
|
|
extern u16 jinj_med_Inst;
|
|
extern u16 jinj_med_FX;
|
|
extern u16 jinj_med_Freq;
|
|
extern u16 gothic_Song;
|
|
extern u16 gothic_Inst;
|
|
extern u16 gothic_FX;
|
|
extern u16 gothic_Freq;
|
|
extern u16 shampoo_Song;
|
|
extern u16 shampoo_Inst;
|
|
extern u16 shampoo_FX;
|
|
extern u16 shampoo_Freq;
|
|
extern u16 quezesto_Song;
|
|
extern u16 quezesto_Inst;
|
|
extern u16 quezesto_FX;
|
|
extern u16 quezesto_Freq;
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Fonts
|
|
#include "font/font_mgl_sample8.h"
|
|
|
|
// Animation characters
|
|
const u8 g_ChrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
// Music list
|
|
const struct MusicEntry g_MusicEntry[] =
|
|
{
|
|
{ "Jinj Med ", (u16)&jinj_med_Song, (u16)&jinj_med_Inst, (u16)&jinj_med_FX, (u16)&jinj_med_Freq },
|
|
{ "RA_PSG ", (u16)&RA_PSG_Song, (u16)&RA_PSG_Inst, (u16)&RA_PSG_FX, (u16)&RA_PSG_Freq },
|
|
{ "Nayade ", (u16)&WYZ_songs, (u16)&WYZ_instruments, (u16)&WYZ_FXs, (u16)&WYZ_notes },
|
|
{ "Gothic ", (u16)&gothic_Song, (u16)&gothic_Inst, (u16)&gothic_FX, (u16)&gothic_Freq },
|
|
{ "Shampoo ", (u16)&shampoo_Song, (u16)&shampoo_Inst, (u16)&shampoo_FX, (u16)&shampoo_Freq },
|
|
{ "Quezesto ", (u16)&quezesto_Song, (u16)&quezesto_Inst, (u16)&quezesto_FX, (u16)&quezesto_Freq },
|
|
};
|
|
|
|
// Player button list
|
|
const struct ButtonEntry g_ButtonEntry[] =
|
|
{
|
|
{ 0x80, ButtonPlay },
|
|
{ 0xB8, ButtonPause },
|
|
{ 0xB9, ButtonStop },
|
|
{ 0xBB, ButtonPrev },
|
|
{ 0xBA, ButtonNext },
|
|
{ 0xBE, ButtonLoop },
|
|
};
|
|
|
|
// Color shade
|
|
const u8 g_ColorBlink[4] = { COLOR_LIGHT_RED, COLOR_MEDIUM_RED, COLOR_DARK_RED, COLOR_MEDIUM_RED };
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
u8 g_CurrentMusic = 0;
|
|
u8 g_CurrentButton;
|
|
bool g_Freq50Hz = FALSE;
|
|
bool g_DoLoop = TRUE;
|
|
|
|
|
|
//=============================================================================
|
|
// HELPER FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void SetMusic(u8 idx)
|
|
{
|
|
g_CurrentMusic = idx;
|
|
const struct MusicEntry* entry = &g_MusicEntry[idx];
|
|
|
|
WYZ_Initialize(entry->Song, entry->Inst, entry->FX, entry->Freq);
|
|
// WYZ_PlaySong(0, g_DoLoop);
|
|
WYZ_Play(0);
|
|
|
|
Print_SetPosition(0, 2);
|
|
Print_DrawFormat("%i/%i %s", 1 + idx, numberof(g_MusicEntry), entry->Name);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void ButtonPlay()
|
|
{
|
|
// WYZ_Resume();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void ButtonPause()
|
|
{
|
|
// WYZ_Pause();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void ButtonStop()
|
|
{
|
|
WYZ_Stop();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void ButtonPrev()
|
|
{
|
|
if (g_CurrentMusic > 0)
|
|
SetMusic(g_CurrentMusic - 1);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void ButtonNext()
|
|
{
|
|
if (g_CurrentMusic < numberof(g_MusicEntry) - 1)
|
|
SetMusic(g_CurrentMusic + 1);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void ButtonLoop()
|
|
{
|
|
g_DoLoop = 1 - g_DoLoop;
|
|
// WYZ_SetLoop(g_DoLoop);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void SetCursor(u8 id)
|
|
{
|
|
g_CurrentButton = id;
|
|
VDP_SetSpriteSM1(0, 8 + 16*g_CurrentButton, ((PLAYER_Y+1)*8)-1, g_ButtonEntry[g_CurrentButton].Char, COLOR_LIGHT_RED);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// MAIN LOOP
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
void main()
|
|
{
|
|
// Initialize screen
|
|
VDP_SetMode(VDP_MODE_SCREEN1);
|
|
VDP_SetColor2(COLOR_BLACK, COLOR_WHITE);
|
|
VDP_ClearVRAM();
|
|
VDP_EnableVBlank(TRUE);
|
|
|
|
// Initialize font
|
|
Print_SetTextFont(g_Font_MGL_Sample8, 1); // Initialize font
|
|
Print_DrawText(MSX_GL " WYZ2 SAMPLE");
|
|
Print_DrawLineH(0, 1, 32);
|
|
|
|
// Decode VGM header
|
|
SetMusic(0);
|
|
Print_DrawBox(0, PLAYER_Y, numberof(g_ButtonEntry) * 2 + 1, 3);
|
|
for (u8 i = 0; i < numberof(g_ButtonEntry); ++i)
|
|
{
|
|
Print_SetPosition(1 + 2 * i, PLAYER_Y+1);
|
|
Print_DrawChar(g_ButtonEntry[i].Char);
|
|
}
|
|
|
|
Print_SetPosition(0, PLAYER_Y+3);
|
|
Print_DrawText(" Chan A\n");
|
|
Print_DrawText(" Chan B\n");
|
|
Print_DrawText(" Chan C\n\n");
|
|
|
|
Print_SetPosition(0, 11);
|
|
Print_DrawText("Load:\n");
|
|
Print_DrawText("Playing:\n");
|
|
Print_DrawText("Effect:\n");
|
|
Print_DrawText("SFX:\n");
|
|
Print_DrawText("Loop:\n");
|
|
Print_DrawText("Ended:");
|
|
|
|
g_Freq50Hz = Sys_Is50Hz() ? 1 : 0;
|
|
|
|
Print_SetPosition(0, 18);
|
|
Print_DrawFormat("Freq: %s", (g_Freq50Hz) ? "50Hz" : "60Hz");
|
|
|
|
Print_SetPosition(20, 18);
|
|
Print_DrawFormat("BIOS: %s", Sys_Is50Hz() ? "50Hz" : "60Hz");
|
|
|
|
// Footer
|
|
Print_DrawLineH(0, 22, 32);
|
|
Print_SetPosition(0, 23);
|
|
Print_DrawText("\x8D:Button \x83:Action \x82:Freq Home:FX");
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Sprite
|
|
|
|
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_8 + VDP_SPRITE_SCALE_1);
|
|
VDP_LoadSpritePattern(g_Font_MGL_Sample8 + 4, 0, g_Font_MGL_Sample8[3] - g_Font_MGL_Sample8[2]);
|
|
|
|
SetCursor(4);
|
|
|
|
u8 prevRow8 = 0xFF;
|
|
u8 count = 0;
|
|
while (1)
|
|
{
|
|
Halt();
|
|
count++;
|
|
if (g_Freq50Hz || (count % 6 != 0))
|
|
{
|
|
WYZ_Decode();
|
|
#if (!WYZ_USE_DIRECT_ACCESS)
|
|
PSG_Apply();
|
|
#endif
|
|
}
|
|
|
|
VDP_SetSpriteColorSM1(0, g_ColorBlink[(count >> 2) & 0x03]);
|
|
|
|
// Print_SetPosition(8, 11); Print_DrawChar((g_WYZ_State & (1 << 0)) ? 0xC : 0xB);
|
|
// Print_SetPosition(8, 12); Print_DrawChar((g_WYZ_State & (1 << 1)) ? 0xC : 0xB);
|
|
// Print_SetPosition(8, 13); Print_DrawChar((g_WYZ_State & (1 << 2)) ? 0xC : 0xB);
|
|
// Print_SetPosition(8, 14); Print_DrawChar((g_WYZ_State & (1 << 3)) ? 0xC : 0xB);
|
|
// Print_SetPosition(8, 15); Print_DrawChar((g_WYZ_State & (1 << 4)) ? 0xC : 0xB);
|
|
// Print_SetPosition(8, 16); Print_DrawChar((g_WYZ_State & (1 << 7)) ? 0xC : 0xB);
|
|
|
|
Print_SetPosition(31, 0);
|
|
u8 chr = count & 0x03;
|
|
Print_DrawChar(g_ChrAnim[chr]);
|
|
|
|
// VU metter
|
|
u8* ayReg = (u8*)AYREGS + PSG_REG_AMP_A;
|
|
u8 y = PLAYER_Y+3;
|
|
loop (i, 3)
|
|
{
|
|
Print_SetPosition(8, y++);
|
|
|
|
if (*ayReg < 8)
|
|
{
|
|
u8 l = *ayReg & 0x07;
|
|
Print_DrawChar((l == 0) ? ' ' : 0xA0 + l);
|
|
Print_DrawChar(' ');
|
|
}
|
|
else // if (*ayReg >= 8)
|
|
{
|
|
Print_DrawChar(0xA0);
|
|
u8 h = *ayReg - 8;
|
|
Print_DrawChar((h == 0) ? ' ' : 0xA0 + h);
|
|
}
|
|
|
|
ayReg++;
|
|
}
|
|
|
|
// Handle input
|
|
u8 row8 = Keyboard_Read(8);
|
|
|
|
// Change button
|
|
if (IS_KEY_PRESSED(row8, KEY_RIGHT) && !IS_KEY_PRESSED(prevRow8, KEY_RIGHT))
|
|
{
|
|
SetCursor((g_CurrentButton < numberof(g_ButtonEntry) - 1) ? g_CurrentButton + 1 : 0);
|
|
}
|
|
else if (IS_KEY_PRESSED(row8, KEY_LEFT) && !IS_KEY_PRESSED(prevRow8, KEY_LEFT))
|
|
{
|
|
SetCursor((g_CurrentButton > 0) ? g_CurrentButton - 1 : numberof(g_ButtonEntry) - 1);
|
|
}
|
|
// Activate button
|
|
if (IS_KEY_PRESSED(row8, KEY_SPACE) && !IS_KEY_PRESSED(prevRow8, KEY_SPACE))
|
|
{
|
|
g_ButtonEntry[g_CurrentButton].Func();
|
|
}
|
|
// Change frequency
|
|
if ((IS_KEY_PRESSED(row8, KEY_UP) && !IS_KEY_PRESSED(prevRow8, KEY_UP)) || (IS_KEY_PRESSED(row8, KEY_DOWN) && !IS_KEY_PRESSED(prevRow8, KEY_DOWN)))
|
|
{
|
|
g_Freq50Hz = 1 - g_Freq50Hz;
|
|
Print_SetPosition(0, 18);
|
|
Print_DrawFormat("Freq: %s", (g_Freq50Hz) ? "50Hz" : "60Hz");
|
|
}
|
|
// Activate button
|
|
// if (IS_KEY_PRESSED(row8, KEY_HOME) && !IS_KEY_PRESSED(prevRow8, KEY_HOME))
|
|
// {
|
|
// WYZ_PlayFX(0);
|
|
// }
|
|
|
|
prevRow8 = row8;
|
|
}
|
|
} |