Continue music

This commit is contained in:
Miloslav Číž 2020-04-16 16:59:06 +02:00
parent 443adbe950
commit 2a58188ee0
3 changed files with 101 additions and 25 deletions

95
main.c
View File

@ -101,6 +101,14 @@ static inline void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex);
*/ */
void SFG_playSound(uint8_t soundIndex, uint8_t volume); void SFG_playSound(uint8_t soundIndex, uint8_t volume);
/**
Informs the frontend whether music should get enabled/disabled. Playing music
is optional and the frontend can ignore it. If a frontend wants to implement
music, it can use the one provided in sounds.h or use its own.
*/
void SFG_enableMusic(uint8_t enable);
/* ========================================================================= */ /* ========================================================================= */
/** /**
@ -285,6 +293,9 @@ struct
uint8_t selectedMenuItem; uint8_t selectedMenuItem;
uint8_t selectedLevel; ///< Level to play selected in the main menu. uint8_t selectedLevel; ///< Level to play selected in the main menu.
uint8_t antiSpam; ///< Prevents log message spamming. uint8_t antiSpam; ///< Prevents log message spamming.
uint8_t soundSettings; /**< Sound settings: LSB says whether SFX is on,
second LSB says whether music is on. */
} SFG_game; } SFG_game;
/** /**
@ -442,8 +453,11 @@ uint8_t SFG_random()
return SFG_game.currentRandom; return SFG_game.currentRandom;
} }
void SFG_playSoundSafe(uint8_t soundIndex, uint8_t volume) void SFG_playGameSound(uint8_t soundIndex, uint8_t volume)
{ {
if (!(SFG_game.soundSettings & 0x01))
return;
uint8_t mask = 0x01 << soundIndex; uint8_t mask = 0x01 << soundIndex;
if (!(SFG_game.soundsPlayedThisFrame & mask)) if (!(SFG_game.soundsPlayedThisFrame & mask))
@ -1418,6 +1432,9 @@ void SFG_init()
SFG_game.antiSpam = 0; SFG_game.antiSpam = 0;
SFG_game.soundSettings = 0xff;
SFG_enableMusic(1);
SFG_LOG("computing average texture colors") SFG_LOG("computing average texture colors")
for (uint8_t i = 0; i < SFG_WALL_TEXTURE_COUNT; ++i) for (uint8_t i = 0; i < SFG_WALL_TEXTURE_COUNT; ++i)
@ -1693,10 +1710,10 @@ void SFG_monsterChangeHealth(SFG_MonsterRecord *monster, int8_t healthAdd)
SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]),
SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]))); SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1])));
SFG_playSoundSafe(5,volume); SFG_playGameSound(5,volume);
if (monster->health == 0) if (monster->health == 0)
SFG_playSoundSafe(2,volume); SFG_playGameSound(2,volume);
} }
} }
@ -1748,7 +1765,7 @@ void SFG_createExplosion(RCL_Unit x, RCL_Unit y, RCL_Unit z)
{ {
SFG_ProjectileRecord explosion; SFG_ProjectileRecord explosion;
SFG_playSound(2,SFG_distantSoundVolume(x,y,z)); SFG_playGameSound(2,SFG_distantSoundVolume(x,y,z));
explosion.type = SFG_PROJECTILE_EXPLOSION; explosion.type = SFG_PROJECTILE_EXPLOSION;
@ -1926,7 +1943,7 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
} }
if (projectile == SFG_PROJECTILE_BULLET) if (projectile == SFG_PROJECTILE_BULLET)
SFG_playSoundSafe(0, SFG_playGameSound(0,
SFG_distantSoundVolume( SFG_distantSoundVolume(
SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]),
SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]),
@ -2014,7 +2031,7 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
SFG_playerChangeHealth( SFG_playerChangeHealth(
-1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_MELEE)); -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_MELEE));
SFG_playSoundSafe(3,255); SFG_playGameSound(3,255);
} }
else // SFG_MONSTER_ATTACK_EXPLODE else // SFG_MONSTER_ATTACK_EXPLODE
{ {
@ -2085,7 +2102,7 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
if ((coordAdd[0] != 0 || coordAdd[1] != 0) && SFG_random() < if ((coordAdd[0] != 0 || coordAdd[1] != 0) && SFG_random() <
SFG_MONSTER_SOUND_PROBABILITY) SFG_MONSTER_SOUND_PROBABILITY)
SFG_playSoundSafe(5, SFG_playGameSound(5,
SFG_distantSoundVolume( SFG_distantSoundVolume(
SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]),
SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]),
@ -2309,7 +2326,7 @@ void SFG_updateLevel()
else if (p->type == SFG_PROJECTILE_BULLET) else if (p->type == SFG_PROJECTILE_BULLET)
SFG_createDust(p->position[0],p->position[1],p->position[2]); SFG_createDust(p->position[0],p->position[1],p->position[2]);
else if (p->type == SFG_PROJECTILE_PLASMA) else if (p->type == SFG_PROJECTILE_PLASMA)
SFG_playSoundSafe(4,SFG_distantSoundVolume(pos[0],pos[1],pos[2])); SFG_playGameSound(4,SFG_distantSoundVolume(pos[0],pos[1],pos[2]));
// remove the projectile // remove the projectile
@ -2360,7 +2377,7 @@ void SFG_updateLevel()
) ? SFG_DOOR_UP_DOWN_MASK : 0x00; ) ? SFG_DOOR_UP_DOWN_MASK : 0x00;
if (upDownState != newUpDownState) if (upDownState != newUpDownState)
SFG_playSoundSafe(1,255); SFG_playGameSound(1,255);
door->state = (door->state & ~SFG_DOOR_UP_DOWN_MASK) | newUpDownState; door->state = (door->state & ~SFG_DOOR_UP_DOWN_MASK) | newUpDownState;
@ -2567,7 +2584,7 @@ void SFG_gameStepPlaying()
} }
if (sound != 255) if (sound != 255)
SFG_playSoundSafe(sound,255); SFG_playGameSound(sound,255);
if (ammo != SFG_AMMO_NONE) if (ammo != SFG_AMMO_NONE)
SFG_player.ammo[ammo] -= projectileCount; SFG_player.ammo[ammo] -= projectileCount;
@ -2970,7 +2987,7 @@ void SFG_gameStepPlaying()
SFG_removeItem(i); SFG_removeItem(i);
SFG_player.lastItemTakenFrame = SFG_game.frame; SFG_player.lastItemTakenFrame = SFG_game.frame;
i--; i--;
SFG_playSoundSafe(3,255); SFG_playGameSound(3,255);
#endif #endif
} }
else if ( else if (
@ -3011,7 +3028,7 @@ void SFG_gameStepPlaying()
SFG_player.justTeleported = 1; SFG_player.justTeleported = 1;
SFG_playSoundSafe(4,255); SFG_playGameSound(4,255);
break; break;
} }
@ -3104,12 +3121,12 @@ void SFG_gameStepMenu()
(SFG_game.selectedMenuItem < menuItems - 1)) (SFG_game.selectedMenuItem < menuItems - 1))
{ {
SFG_game.selectedMenuItem++; SFG_game.selectedMenuItem++;
SFG_playSoundSafe(3,64); SFG_playGameSound(3,64);
} }
else if (SFG_keyRegisters(SFG_KEY_UP) && (SFG_game.selectedMenuItem > 0)) else if (SFG_keyRegisters(SFG_KEY_UP) && (SFG_game.selectedMenuItem > 0))
{ {
SFG_game.selectedMenuItem--; SFG_game.selectedMenuItem--;
SFG_playSoundSafe(3,64); SFG_playGameSound(3,64);
} }
else if (SFG_keyJustPressed(SFG_KEY_A)) else if (SFG_keyJustPressed(SFG_KEY_A))
{ {
@ -3135,6 +3152,23 @@ void SFG_gameStepMenu()
SFG_setGameState(SFG_GAME_STATE_MAP); SFG_setGameState(SFG_GAME_STATE_MAP);
break; break;
case SFG_MENU_ITEM_SOUND:
SFG_LOG("sound changed");
SFG_game.soundSettings++;
SFG_playGameSound(3,64);
if ((SFG_game.soundSettings & 0x02) !=
((SFG_game.soundSettings - 1) & 0x02))
{
if (SFG_game.soundSettings & 0x02)
SFG_enableMusic(1);
else
SFG_enableMusic(0);
}
break;
default: default:
break; break;
} }
@ -3145,12 +3179,12 @@ void SFG_gameStepMenu()
(SFG_game.selectedLevel < SFG_NUMBER_OF_LEVELS - 1)) (SFG_game.selectedLevel < SFG_NUMBER_OF_LEVELS - 1))
{ {
SFG_game.selectedLevel++; SFG_game.selectedLevel++;
SFG_playSoundSafe(3,64); SFG_playGameSound(3,64);
} }
else if (SFG_keyRegisters(SFG_KEY_LEFT) && SFG_game.selectedLevel > 0) else if (SFG_keyRegisters(SFG_KEY_LEFT) && SFG_game.selectedLevel > 0)
{ {
SFG_game.selectedLevel--; SFG_game.selectedLevel--;
SFG_playSoundSafe(3,64); SFG_playGameSound(3,64);
} }
} }
} }
@ -3625,12 +3659,29 @@ void SFG_drawMenu()
SFG_drawText(text,drawX,y,SFG_FONT_SIZE_MEDIUM,textColor,0,0); SFG_drawText(text,drawX,y,SFG_FONT_SIZE_MEDIUM,textColor,0,0);
if (item == SFG_MENU_ITEM_PLAY && if ((item == SFG_MENU_ITEM_PLAY || item == SFG_MENU_ITEM_SOUND) &&
(((i != SFG_game.selectedMenuItem) || ((i != SFG_game.selectedMenuItem) ||
(SFG_game.frame / SFG_BLINK_PERIOD_FRAMES) % 2))) ((SFG_game.frame / SFG_BLINK_PERIOD_FRAMES) % 2)))
SFG_drawNumber((SFG_game.selectedLevel + 1), {
drawX + SFG_characterSize(SFG_FONT_SIZE_MEDIUM) * (textLen + 1), //uint8_t blink = (SFG_game.frame / SFG_BLINK_PERIOD_FRAMES) % 2;
y,SFG_FONT_SIZE_MEDIUM,93);
uint32_t x =
drawX + SFG_characterSize(SFG_FONT_SIZE_MEDIUM) * (textLen + 1);
uint8_t c = 93;
if (item == SFG_MENU_ITEM_PLAY)
SFG_drawNumber((SFG_game.selectedLevel + 1),x,y,SFG_FONT_SIZE_MEDIUM,c);
else
{
char settingText[3] = " ";
settingText[0] = (SFG_game.soundSettings & 0x01) ? 'S' : ' ';
settingText[1] = (SFG_game.soundSettings & 0x02) ? 'M' : ' ';
SFG_drawText(settingText,x,y,SFG_FONT_SIZE_MEDIUM,c,0,0);
}
}
y += SFG_characterSize(SFG_FONT_SIZE_MEDIUM) + SFG_FONT_SIZE_MEDIUM; y += SFG_characterSize(SFG_FONT_SIZE_MEDIUM) + SFG_FONT_SIZE_MEDIUM;
i++; i++;

View File

@ -188,16 +188,26 @@ static inline uint8_t addSamples(uint8_t sample1, uint8_t sample2)
return mixed; return mixed;
} }
uint8_t musicOn = 1;
void audioFillCallback(void *userdata, uint8_t *s, int l) void audioFillCallback(void *userdata, uint8_t *s, int l)
{ {
for (int i = 0; i < l; ++i) for (int i = 0; i < l; ++i)
{ {
s[i] = addSamples(audioBuff[audioPos],SFG_getNextMusicSample()); s[i] = musicOn ?
addSamples(audioBuff[audioPos],SFG_getNextMusicSample()) :
audioBuff[audioPos];
audioBuff[audioPos] = 127; audioBuff[audioPos] = 127;
audioPos = (audioPos < SFG_SFX_SAMPLE_COUNT - 1) ? (audioPos + 1) : 0; audioPos = (audioPos < SFG_SFX_SAMPLE_COUNT - 1) ? (audioPos + 1) : 0;
} }
} }
void SFG_enableMusic(uint8_t enable)
{
musicOn = enable;
}
void SFG_playSound(uint8_t soundIndex, uint8_t volume) void SFG_playSound(uint8_t soundIndex, uint8_t volume)
{ {
uint8_t volumeStep = volume / 16; uint8_t volumeStep = volume / 16;

View File

@ -10,6 +10,9 @@
by Miloslav Ciz (drummyfish), 2019 by Miloslav Ciz (drummyfish), 2019
Music is based on bytebeat (procedural waveforms generated by short bitwise
operation formulas).
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is plus a waiver of all other intellectual property. The goal of this work is
be and remain completely in the public domain forever, available for any use be and remain completely in the public domain forever, available for any use
@ -34,6 +37,7 @@
struct struct
{ // all should be initialized to 0 { // all should be initialized to 0
// TODO: leave only those needed here
uint8_t track; uint8_t track;
uint32_t t; uint32_t t;
uint32_t t2; uint32_t t2;
@ -42,13 +46,17 @@ struct
uint32_t n7t; uint32_t n7t;
} SFG_MusicState; } SFG_MusicState;
/**
Gets the next 8bit 8KHz music sample for the bytebeat soundtrack. This
function is to be used by the frontend that plays music.
*/
uint8_t SFG_getNextMusicSample() uint8_t SFG_getNextMusicSample()
{ {
if (SFG_MusicState.t >= SFG_TRACK_SAMPLES) if (SFG_MusicState.t >= SFG_TRACK_SAMPLES)
{ {
SFG_MusicState.track++; SFG_MusicState.track++;
if (SFG_MusicState.track >= 3) if (SFG_MusicState.track >= 4)
SFG_MusicState.track = 0; SFG_MusicState.track = 0;
SFG_MusicState.t = 0; SFG_MusicState.t = 0;
@ -64,7 +72,7 @@ uint8_t SFG_getNextMusicSample()
#define t2 SFG_MusicState.t2 #define t2 SFG_MusicState.t2
#define n3t SFG_MusicState.n3t #define n3t SFG_MusicState.n3t
switch (SFG_MusicState.track) switch (SFG_MusicState.track) // individual music tracks
{ {
case 0: case 0:
{ {
@ -82,6 +90,13 @@ uint8_t SFG_getNextMusicSample()
} }
case 2: case 2:
{
result =
~((((t >> (t >> 2)) | (t >> (t >> 5))) & 0x12) << 1) | (t >> 11);
break;
}
case 3:
{ {
result = result =
((((t >> (t >> 2)) + (t >> (t >> 7)))) & 0x3f | (t >> 5) | (t >> 11)) ((((t >> (t >> 2)) + (t >> (t >> 7)))) & 0x3f | (t >> 5) | (t >> 11))