Compare commits
13 Commits
sound_tuni
...
another_wi
Author | SHA1 | Date | |
---|---|---|---|
ba4248ff24 | |||
2cc5a6a4f3 | |||
5c86d55458 | |||
b9e5813223 | |||
1b4a93d9e1 | |||
30d50dcc5e | |||
1607dc62dd | |||
78df7eee66 | |||
09fe302e63
|
|||
d28e62fdd3
|
|||
01d4fe3f85
|
|||
5de2761fde | |||
1f807cdb7c |
BIN
docs/IMG_4941.jpg
Normal file
BIN
docs/IMG_4941.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 603 KiB |
BIN
docs/IMG_4958.jpeg
Normal file
BIN
docs/IMG_4958.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 262 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
BIN
docs/sound-driver-2.png
Normal file
BIN
docs/sound-driver-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 183 KiB |
@ -7,7 +7,7 @@ MCU=msp430g2553
|
|||||||
CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
|
CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
|
||||||
|
|
||||||
# for debugging
|
# for debugging
|
||||||
CFLAGS+= -g3 -ggdb -gdwarf-2
|
#CFLAGS+= -g3 -ggdb -gdwarf-2
|
||||||
|
|
||||||
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
|
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
|
||||||
|
|
||||||
|
120
game-ctrl/game.c
120
game-ctrl/game.c
@ -1,3 +1,5 @@
|
|||||||
|
// #define STATE_DEBUGGING
|
||||||
|
|
||||||
#include "stddef.h"
|
#include "stddef.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
@ -12,35 +14,36 @@
|
|||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
|
||||||
|
|
||||||
#define GAME_CYCLE_TIME 50
|
#define GAME_CYCLE_TIME 10
|
||||||
#define GAMEOVER_DELAY 10
|
#define GAMEOVER_DELAY 10
|
||||||
#define MAX_LEVEL 20
|
#define MAX_LEVEL 100
|
||||||
|
|
||||||
|
|
||||||
static uint8_t delayFactor(uint8_t level) {
|
static uint16_t delayFactor(uint16_t level) {
|
||||||
return MAX_LEVEL + 1 - level;
|
return MAX_LEVEL + 1 - level;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
e_Phase_Game, e_Phase_GameOver
|
e_Start, e_NewStone, e_Down, e_DownDelay,
|
||||||
} phase_t;
|
e_ClearRowInit, e_ClearRowNext, e_ClearRowCheck, e_ClearRowFlash, e_ClearRowFlashDelay, e_ClearRowWipe,
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
e_Start, e_NewStone, e_Down, e_DownDelay, e_ClearRows,
|
|
||||||
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
|
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
|
||||||
} state_t;
|
} state_t;
|
||||||
|
|
||||||
void gameExec(void *handle) {
|
void gameExec(void *handle) {
|
||||||
static phase_t phase;
|
|
||||||
static state_t state = e_Start;
|
static state_t state = e_Start;
|
||||||
static uint8_t gameOverDelay;
|
static uint8_t gameOverDelay;
|
||||||
static uint8_t rowIndex;
|
static uint8_t rowIndex;
|
||||||
static uint8_t proceedDelay;
|
static uint16_t proceedDelay;
|
||||||
static uint8_t level;
|
static uint16_t level;
|
||||||
static uint16_t filledLines;
|
static uint16_t filledLines;
|
||||||
static uint16_t score;
|
static uint16_t score;
|
||||||
static bool newHighScoreAchieved;
|
static bool newHighScoreAchieved;
|
||||||
|
|
||||||
|
static uint8_t clearCheckCnt;
|
||||||
|
|
||||||
|
#ifdef STATE_DEBUGGING
|
||||||
|
displaySetValue(state);
|
||||||
|
#endif
|
||||||
// --- engine begin -------------------------------------------------------
|
// --- engine begin -------------------------------------------------------
|
||||||
switch (state) {
|
switch (state) {
|
||||||
// --- phase: game --------------------------------------------------------
|
// --- phase: game --------------------------------------------------------
|
||||||
@ -51,7 +54,6 @@ void gameExec(void *handle) {
|
|||||||
filledLines = 0;
|
filledLines = 0;
|
||||||
score = 0;
|
score = 0;
|
||||||
newHighScoreAchieved = false;
|
newHighScoreAchieved = false;
|
||||||
phase = e_Phase_Game;
|
|
||||||
state = e_NewStone;
|
state = e_NewStone;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -68,30 +70,77 @@ void gameExec(void *handle) {
|
|||||||
case e_DownDelay:
|
case e_DownDelay:
|
||||||
proceedDelay--;
|
proceedDelay--;
|
||||||
if (proceedDelay == 0) {
|
if (proceedDelay == 0) {
|
||||||
rowIndex = 0;
|
|
||||||
state = e_ClearRows;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case e_ClearRows:
|
|
||||||
state = e_Down;
|
state = e_Down;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case e_Down:
|
case e_Down:
|
||||||
if (! stoneMoveDown()) {
|
if (! stoneMoveDown()) {
|
||||||
soundCtrl(SOUND_LOCK);
|
soundCtrl(SOUND_LOCK);
|
||||||
state = e_NewStone;
|
stoneLock();
|
||||||
|
state = e_ClearRowInit;
|
||||||
} else {
|
} else {
|
||||||
proceedDelay = delayFactor(level);
|
proceedDelay = delayFactor(level);
|
||||||
state = e_DownDelay;
|
state = e_DownDelay;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// --- phase: clear rows --------------------------------------------------
|
||||||
|
case e_ClearRowInit:
|
||||||
|
clearCheckCnt = 0;
|
||||||
|
state = e_ClearRowCheck;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowNext:
|
||||||
|
if (clearCheckCnt >= CANVAS_HEIGHT) {
|
||||||
|
state = e_NewStone;
|
||||||
|
} else {
|
||||||
|
clearCheckCnt += 1;
|
||||||
|
state = e_ClearRowCheck;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowCheck:
|
||||||
|
if (canvasIsRowFilled(clearCheckCnt)) {
|
||||||
|
score += level;
|
||||||
|
if (score > eepromReadHighScore()) {
|
||||||
|
newHighScoreAchieved = true;
|
||||||
|
eepromWriteHighScore(score);
|
||||||
|
}
|
||||||
|
state = e_ClearRowFlash;
|
||||||
|
} else {
|
||||||
|
state = e_ClearRowNext;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowFlash:
|
||||||
|
canvasFillRow(clearCheckCnt, _flash);
|
||||||
|
state = e_ClearRowFlashDelay;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowFlashDelay:
|
||||||
|
state = e_ClearRowWipe;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowWipe:
|
||||||
|
canvasWipeRow(clearCheckCnt);
|
||||||
|
filledLines += 1;
|
||||||
|
|
||||||
|
if ((filledLines > 0) && ((filledLines % 10) == 0)) {
|
||||||
|
if (level < MAX_LEVEL) {
|
||||||
|
level += 1;
|
||||||
|
}
|
||||||
|
soundCtrl(SOUND_FANFARE);
|
||||||
|
} else {
|
||||||
|
soundCtrl(SOUND_PLING);
|
||||||
|
}
|
||||||
|
state = e_ClearRowNext;
|
||||||
|
break;
|
||||||
|
|
||||||
// --- phase: game over ---------------------------------------------------
|
// --- phase: game over ---------------------------------------------------
|
||||||
case e_GameOver:
|
case e_GameOver:
|
||||||
soundCtrl(SOUND_GAMEOVER);
|
soundCtrl(SOUND_GAMEOVER);
|
||||||
rowIndex = CANVAS_HEIGHT;
|
rowIndex = CANVAS_HEIGHT;
|
||||||
phase = e_Phase_GameOver;
|
|
||||||
state = e_GameOverFill;
|
state = e_GameOverFill;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -121,42 +170,15 @@ void gameExec(void *handle) {
|
|||||||
}
|
}
|
||||||
// --- engine end ---------------------------------------------------------
|
// --- engine end ---------------------------------------------------------
|
||||||
|
|
||||||
bool wipedLines = false;
|
|
||||||
canvasShow();
|
canvasShow();
|
||||||
if (phase == e_Phase_Game) {
|
|
||||||
for (uint8_t r = 0; r < CANVAS_HEIGHT; r++) {
|
|
||||||
if (canvasIsRowFilled(r)) {
|
|
||||||
score += level;
|
|
||||||
if (score > eepromReadHighScore()) {
|
|
||||||
newHighScoreAchieved = true;
|
|
||||||
eepromWriteHighScore(score);
|
|
||||||
}
|
|
||||||
displaySetValue(score);
|
|
||||||
canvasWipeRow(r);
|
|
||||||
canvasShow();
|
|
||||||
wipedLines = true;
|
|
||||||
filledLines += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wipedLines) {
|
|
||||||
soundCtrl(SOUND_PLING);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wipedLines && (filledLines > 0) && ((filledLines % 10) == 0)) {
|
|
||||||
if (level < MAX_LEVEL) {
|
|
||||||
level += 1;
|
|
||||||
}
|
|
||||||
soundCtrl(SOUND_FANFARE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef STATE_DEBUGGING
|
||||||
if (isGameActive()) {
|
if (isGameActive()) {
|
||||||
displaySetValue(score);
|
displaySetValue(score);
|
||||||
} else {
|
} else {
|
||||||
displaySetValue(eepromReadHighScore());
|
displaySetValue(eepromReadHighScore());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameInit() {
|
void gameInit() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "shapes.h"
|
#include "shapes.h"
|
||||||
#include "myrand.h"
|
#include "myrand.h"
|
||||||
@ -19,6 +20,7 @@ typedef struct {
|
|||||||
orientation_t orientation;
|
orientation_t orientation;
|
||||||
uint8_t x; // column
|
uint8_t x; // column
|
||||||
uint8_t y; // row
|
uint8_t y; // row
|
||||||
|
bool locked;
|
||||||
} stone_t;
|
} stone_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -363,6 +365,11 @@ void stoneCreate() {
|
|||||||
stone.orientation = e_0;
|
stone.orientation = e_0;
|
||||||
stone.x = 4;
|
stone.x = 4;
|
||||||
stone.y = 0;
|
stone.y = 0;
|
||||||
|
stone.locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stoneLock() {
|
||||||
|
stone.locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t stoneIsValid() {
|
uint8_t stoneIsValid() {
|
||||||
@ -376,6 +383,12 @@ static uint8_t move(direction_t direction) {
|
|||||||
if (motions[stone.shape].nullRotation && (direction == e_RotateLeft || direction == e_RotateRight)) {
|
if (motions[stone.shape].nullRotation && (direction == e_RotateLeft || direction == e_RotateRight)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the stone is already locked, do nothing
|
||||||
|
if (stone.locked) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check whether the pixels to move to are free
|
// check whether the pixels to move to are free
|
||||||
if (canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[0].x,
|
if (canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[0].x,
|
||||||
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[0].y) &&
|
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[0].y) &&
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
void shapesInit();
|
void shapesInit();
|
||||||
void stoneCreate();
|
void stoneCreate();
|
||||||
|
void stoneLock();
|
||||||
uint8_t stoneIsValid();
|
uint8_t stoneIsValid();
|
||||||
uint8_t stoneDraw();
|
uint8_t stoneDraw();
|
||||||
uint8_t stoneMoveDown();
|
uint8_t stoneMoveDown();
|
||||||
|
10
readme.md
10
readme.md
@ -2,6 +2,14 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Update Amplifier (separate input circuitry per PSG, it appears, that a silent PSG has a DC level on its output which is summarized to the AC output of the working PSG, so two input circuits with individual couping capacitor):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Update of the power switch of the amplifier (at appears, that the small transistor couldn't deliver enough current):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
This Tetris implementation consists of a hardware and a software (running on that hardware).
|
This Tetris implementation consists of a hardware and a software (running on that hardware).
|
||||||
|
|
||||||
The hardware utilizes four MSP430 microcontrollers for 1.) the game play, 2.) the play ground canvas, 3.) the score display and 4.) the sound effects.
|
The hardware utilizes four MSP430 microcontrollers for 1.) the game play, 2.) the play ground canvas, 3.) the score display and 4.) the sound effects.
|
||||||
@ -54,7 +62,7 @@ An amplifier following the proposal of the AY-3-8913 datasheet is implemented us
|
|||||||
The clock generator proposed by the AY-3-8913 does not work reliably, so an alternative design from "The Art of Electronics" has been used.
|
The clock generator proposed by the AY-3-8913 does not work reliably, so an alternative design from "The Art of Electronics" has been used.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "colors.h"
|
#include "colors.h"
|
||||||
|
|
||||||
#define DIMM_FACTOR 3
|
#define DIMM_FACTOR 5
|
||||||
.section ".rodata","a"
|
.section ".rodata","a"
|
||||||
;; color definitions according to
|
;; color definitions according to
|
||||||
;; https://learn.sparkfun.com/tutorials/lilypad-protosnap-plus-activity-guide/3-custom-color-mixing
|
;; https://learn.sparkfun.com/tutorials/lilypad-protosnap-plus-activity-guide/3-custom-color-mixing
|
||||||
@ -35,4 +35,8 @@ white:
|
|||||||
.byte 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
||||||
red:
|
red:
|
||||||
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
||||||
|
flash:
|
||||||
|
.byte 0xff, 0xff, 0xff, 0
|
||||||
|
;; .byte 0x00, 0x00, 0x00, 0
|
||||||
|
;; .byte 0x80>>3, 0x00>>3, 0xff>>3, 0
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#define _yellow 0x0b
|
#define _yellow 0x0b
|
||||||
#define _white 0x0c
|
#define _white 0x0c
|
||||||
#define _red 0x0d
|
#define _red 0x0d
|
||||||
|
#define _flash 0x0e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,41 +9,17 @@ const t_tone plingVoice1[] = {
|
|||||||
{ .octave = e_O_5, .note = e_Cis, .length = e_L_1_16, .legato = false, .staccato = false },
|
{ .octave = e_O_5, .note = e_Cis, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
{ .octave = e_O_5, .note = e_D, .length = e_L_1_16, .legato = false, .staccato = false },
|
{ .octave = e_O_5, .note = e_D, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
{ .octave = e_O_5, .note = e_Dis, .length = e_L_1_16, .legato = false, .staccato = false },
|
{ .octave = e_O_5, .note = e_Dis, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
|
{ .octave = e_O_5, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
|
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_StopMark,.legato = false, .staccato = false },
|
{ .octave = e_O_Null, .note = e_Null, .length = e_L_StopMark,.legato = false, .staccato = false },
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false },
|
{ .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false },
|
||||||
};
|
};
|
||||||
const t_tone plingVoice2[] = {
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_5, .note = e_Gis, .length = e_L_1_4, .legato = false, .staccato = false },
|
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_HoldMark,.legato = false, .staccato = false },
|
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false },
|
|
||||||
};
|
|
||||||
const t_tone plingVoice3[] = {
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_16, .legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_5, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
|
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_HoldMark,.legato = false, .staccato = false },
|
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false },
|
|
||||||
};
|
|
||||||
|
|
||||||
t_melodies pling = {
|
t_melodies pling = {
|
||||||
.melodies = { { .amplitude = 12, .tones = plingVoice1 }, { .amplitude = 12, .tones = plingVoice2 }, { .amplitude = 12, .tones = plingVoice3 } },
|
.melodies = { { .amplitude = 12, .tones = plingVoice1 } },
|
||||||
.numOfMelodies = 3,
|
.numOfMelodies = 1,
|
||||||
.pace = 200,
|
.pace = 200,
|
||||||
.chip = 1
|
.chip = 1
|
||||||
};
|
};
|
||||||
|
@ -8,15 +8,15 @@ void muteInit() {
|
|||||||
P1DIR |= BIT6;
|
P1DIR |= BIT6;
|
||||||
|
|
||||||
// initially, mute
|
// initially, mute
|
||||||
P1OUT |= BIT6;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mute() {
|
|
||||||
P1OUT |= BIT6;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unMute() {
|
|
||||||
P1OUT &= ~BIT6;
|
P1OUT &= ~BIT6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mute() {
|
||||||
|
P1OUT &= ~BIT6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unMute() {
|
||||||
|
P1OUT |= BIT6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,9 +96,11 @@ void sequencerExec(void *handle) {
|
|||||||
melody->state = e_PlayTone;
|
melody->state = e_PlayTone;
|
||||||
break;
|
break;
|
||||||
case e_Hold:
|
case e_Hold:
|
||||||
|
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
|
||||||
break;
|
break;
|
||||||
case e_Terminate:
|
case e_Terminate:
|
||||||
schDel(melodies->taskId);
|
schDel(melodies->taskId);
|
||||||
|
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
|
||||||
slots &= ~(melodies->slotMask);
|
slots &= ~(melodies->slotMask);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user