118 Commits

Author SHA1 Message Date
68816a06fa not working :-( 2024-04-24 14:22:59 +02:00
1d915baf77 docs 2024-04-23 15:38:11 +02:00
08b96a6617 photo 2024-04-23 15:34:15 +02:00
ff95034605 level and speed up stuff 2024-04-23 12:45:39 +02:00
ac4801c7cf docs update 2024-04-22 15:51:05 +02:00
a4cb8129c5 update 2024-04-22 15:48:49 +02:00
f5fa1e5e22 single schematics pages 2024-04-22 15:46:30 +02:00
1d96cee661 Merge branch 'main' of gitea.hottis.de:wn/tetris 2024-04-22 15:34:41 +02:00
7a560959c1 readme 2024-04-22 15:34:29 +02:00
8d8a818cf9 updates schematics 2024-04-19 22:51:39 +02:00
b400431607 add highscore display 2024-04-19 11:38:32 +02:00
7933aa46ae new schematics 2024-04-18 15:16:58 +02:00
076c0f3f1a start in muted state 2024-04-18 13:48:36 +02:00
b49665512f dead code dropped 2024-04-18 13:31:28 +02:00
36d3b2f735 sound works 2024-04-17 15:30:45 +02:00
d68dae167d pragmas 2024-04-16 10:19:08 +02:00
3412197cae pragmas 2024-04-16 10:16:56 +02:00
8dc0569407 pragmas 2024-04-16 10:16:13 +02:00
ac6ca860cb pragmas 2024-04-16 10:14:03 +02:00
2711f5fb4b some sounds 2024-04-15 17:10:33 +02:00
9674bc8ef5 fix 2024-04-15 17:04:27 +02:00
c0ee849cec fix 2024-04-15 17:03:16 +02:00
78c906ef26 fix 2024-04-15 17:02:09 +02:00
0c4533bfac fix 2024-04-15 17:00:59 +02:00
3eed2e30eb cmd in sound 2024-04-15 16:59:50 +02:00
3cebb5d351 fix 2024-04-15 16:47:05 +02:00
a29525ac9e fix 2024-04-15 16:46:24 +02:00
83e6227581 fix 2024-04-15 16:45:31 +02:00
010c493b90 more sound effects 2024-04-15 16:42:33 +02:00
2404910870 add getSeconds, sound controller, mute/unmute switches 2024-04-15 16:23:51 +02:00
53e538b112 docs 2024-04-14 19:39:51 +02:00
1232d0b884 changes 2024-04-14 19:39:10 +02:00
a1d6422897 some sound tests 2024-04-14 14:59:37 +02:00
761de5a94d add mute switch 2024-04-10 14:37:20 +02:00
9a58eedcc4 melodies 2024-04-10 14:10:49 +02:00
2fb12f8af0 melodies 2024-04-10 14:10:42 +02:00
fef3f69f63 fixed 2024-04-10 14:00:12 +02:00
5b9194caae fix 2024-04-10 13:43:28 +02:00
2f8e2937c1 tusch and sequencer stop fix 2024-04-10 12:58:30 +02:00
3769b3eb05 second chip works, stop mark introduces 2024-04-09 18:37:53 +02:00
8f777c9ac4 76498 not working as expected 2024-04-09 18:14:31 +02:00
aeb7aeb7f2 start with other sound chip 2024-04-09 10:32:19 +02:00
20c01f2efa frequency table for 76489AN 2024-04-07 13:37:42 +02:00
40cb04bde5 fix wording 2024-03-29 18:08:37 +01:00
a1457e6a69 lengthCnt must be 16 Bit, one full tone for 160/4 has 375 2024-03-29 15:52:12 +01:00
0303bbdc3c corrects of tones 2024-03-29 15:11:38 +01:00
162bdaefee beat marks 2024-03-29 15:10:04 +01:00
b9fd0099a8 variable names 2024-03-29 14:22:02 +01:00
d09f8d240f Merge branch 'main' of gitea.hottis.de:wn/tetris 2024-03-29 14:13:10 +01:00
ed6da383de docs 2024-03-29 14:13:05 +01:00
9328e22425 pace calculation works 2024-03-29 14:11:36 +01:00
48b9fc7578 some docs 2024-03-29 13:33:39 +01:00
d4d494ae7b sync marks work 2024-03-29 13:29:53 +01:00
1ebf85cb9d sync marks 2024-03-29 13:04:05 +01:00
5a8323bddb up to three melodies will be played by one sequencer instance 2024-03-29 12:41:44 +01:00
97dc6ede70 dreistimmig 2024-03-29 11:15:38 +01:00
a4563cd393 third melody 2024-03-29 00:39:21 +01:00
b435396d67 other melody 2024-03-29 00:28:15 +01:00
38ea1a7fdb register name 2024-03-28 17:05:35 +01:00
6632630303 register names 2024-03-28 17:03:56 +01:00
fdb524c8d4 separate SPI 2024-03-28 16:53:19 +01:00
2c3bccd147 fix wrong initial state 2024-03-28 16:53:08 +01:00
ee98ba12a3 spi separated 2024-03-28 16:48:29 +01:00
33242a09c1 docs 2024-03-28 16:25:16 +01:00
2097280f2b add docs 2024-03-28 16:07:50 +01:00
70b3b25a9d Merge branch 'main' of gitea.hottis.de:wn/tetris 2024-03-26 23:22:06 +01:00
5e1e9dfa92 sequencer init state 2024-03-26 23:21:24 +01:00
f397d0737b docs 2024-03-26 23:15:56 +01:00
1c2414463b sounds good 2024-03-26 23:13:59 +01:00
2e629f12aa sequencer states 2024-03-26 22:12:46 +01:00
9989a52c38 legato 2024-03-26 21:05:48 +01:00
73d2bbc730 tetris melody 2024-03-26 16:56:46 +01:00
5e2f120432 Tonleiter is running 2024-03-26 16:47:42 +01:00
152f171c66 sequencer 2024-03-26 15:58:45 +01:00
9ddb747f16 refactored 2024-03-26 15:05:39 +01:00
bd11d12620 psg and notes 2024-03-26 14:43:02 +01:00
e5c6669284 notes refactored 2024-03-26 13:30:42 +01:00
202e91bfb6 playsommething 2024-03-26 12:23:44 +01:00
48c83f0b2d scheduler added, tuned for 1ms 2024-03-26 10:44:23 +01:00
d8e34ec209 note definitions 2024-03-25 23:13:33 +01:00
5a491140c7 register numbering is octal! 2024-03-25 22:11:15 +01:00
aaf709b0c9 begin sound driver 2024-03-25 13:28:33 +01:00
32bb08696f score reset 2024-03-22 23:03:31 +01:00
85d243551e score counter 2024-03-22 22:49:43 +01:00
a32ef8fa5b prepare display 2024-03-22 18:38:30 +01:00
10a09e3ad3 game over 2024-03-22 12:00:23 +01:00
611c56b329 game over 2024-03-22 11:59:28 +01:00
5b1dfde819 updated schematics 2024-03-21 21:14:05 +01:00
1cc4785ddb refactor SPI handling and introduce SPI CS, forgotten files 2024-03-21 20:55:41 +01:00
9acd56b79b refactor SPI handling and introduce SPI CS 2024-03-21 20:55:26 +01:00
474fce2278 mini canvas 2024-03-21 19:30:40 +01:00
8597a9f736 schematics 2024-03-21 16:02:24 +01:00
da21fac130 motion definition 2024-03-21 15:40:16 +01:00
5f9fab5f2c more to the center 2024-03-21 15:28:36 +01:00
f524a08687 introduce next shape 2024-03-21 12:24:12 +01:00
5c03232855 wipe full lines 2024-03-21 11:58:42 +01:00
f69c5bc59e random is working 2024-03-21 11:34:20 +01:00
50486f6ec0 adc for random number generation not yet working 2024-03-20 21:56:19 +01:00
8c995f66ff J done 2024-03-20 21:00:22 +01:00
ebe958ac49 start of J 2024-03-20 17:35:31 +01:00
fadb80c362 L done 2024-03-20 17:05:13 +01:00
d1e13dc16a S done 2024-03-20 15:19:26 +01:00
90a9294da6 Z done 2024-03-20 14:48:25 +01:00
cfc06ddb2d placeholders for all stones 2024-03-20 13:54:57 +01:00
5e5c616bde T done 2024-03-20 13:48:06 +01:00
2ca1d2e4ad T, move right fixed 2024-03-19 22:18:42 +01:00
a28cdcf6af T, move left fixed 2024-03-19 21:19:34 +01:00
7f6d027d1a fix T, rotate left 2024-03-19 18:14:03 +01:00
97b1d19da8 T 2024-03-19 17:42:25 +01:00
8b2f18415d buttons 2024-03-19 16:46:52 +01:00
5615c80e8f all leds 2024-03-19 14:57:41 +01:00
a68f74559f refactoring 2024-03-18 20:50:10 +01:00
326d0f66b0 remove unused code 2024-03-18 13:01:23 +01:00
feed11f977 change 2024-03-18 12:54:23 +01:00
fd3df973ec code beautifying 2024-03-18 12:51:57 +01:00
58ae9a641a move displayTests to disabled folder 2024-03-18 12:18:18 +01:00
e0aae175b0 debug option in Makefile separated 2024-03-15 23:27:10 +01:00
7e4285f280 move down, left, right for T done 2024-03-15 14:23:19 +01:00
87 changed files with 3075 additions and 318 deletions

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
*.o
firmware.*
firmware.txt
firmware.elf
firmware.map

31
display-driver/Makefile Normal file
View File

@ -0,0 +1,31 @@
TOOLCHAIN_PREFIX=/opt/msp430-gcc
CC=$(TOOLCHAIN_PREFIX)/bin/msp430-elf-gcc
OBJDUMP=$(TOOLCHAIN_PREFIX)/bin/msp430-elf-objdump
ARTIFACT=firmware
MCU=msp430g2553
CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
# for debugging
#CFLAGS+= -g3 -ggdb -gdwarf-2
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
$(ARTIFACT).elf: main.o
$(CC) -o $@ $(LDFLAGS) $^
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt
.c.o:
$(CC) $(CFLAGS) -c $<
.PHONY: all
all: $(ARTIFACT).elf
.PHONY: clean
clean:
-rm -f *.o $(ARTIFACT).elf $(ARTIFACT).txt
.PHONY: upload
upload: $(ARTIFACT).elf
mspdebug rf2500 "prog $(ARTIFACT).elf"

Binary file not shown.

Binary file not shown.

131
display-driver/main.c Normal file
View File

@ -0,0 +1,131 @@
#include <msp430g2553.h>
#include <stdint.h>
#include <stdlib.h>
const uint8_t patterns[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00100111, // 7
0b01111111, // 8
0b01101111, // 9
};
volatile union {
uint16_t value;
uint8_t receiveBuffer[2];
} value;
static void delay() {
asm volatile (
"push r12\n"
"mov.w #1000, r12\n"
"loop:\n"
"dec.w r12\n"
"jnz loop\n"
"pop r12\n"
);
}
void __attribute__ ((interrupt (USCIAB0RX_VECTOR))) receive() {
static uint8_t octetNumber = 0;
if (UC0IFG & UCB0RXIFG) {
value.receiveBuffer[octetNumber] = UCB0RXBUF;
octetNumber++;
if (octetNumber > 1) {
octetNumber = 0;
}
}
}
// mask 0x0f: digit value
// mask 0x10: set dp
// mask 0x20: digit off
static void setDigit(uint16_t bit, uint8_t value) {
P1OUT |= (BIT0 | BIT1 | BIT2 | BIT3);
P2OUT = ((value & 0x20) ? 0 : patterns[value & 0x0f]) | ((value & 0x10) ? 0x80 : 0x00);
P1OUT &= ~bit;
}
int main() {
WDTCTL = WDTPW | WDTHOLD;
__disable_interrupt();
// highest possible system clock
DCOCTL = DCO0 | DCO1 | DCO2;
BCSCTL1 = XT2OFF | RSEL0 | RSEL1 | RSEL2 | RSEL3;
BCSCTL2 = 0;
BCSCTL3 = 0;
// SPI slave
// BIT4: UCB0STE
// BIT5: UCB0CLK
// BIT6: UCB0SOMI
// BIT7: UCB0SIMO
P1SEL |= BIT4 | BIT5 | BIT6 | BIT7;
P1SEL2 |= BIT4 | BIT5 | BIT6 | BIT7;
// most significant bit first, enable STE
UCB0CTL0 = UCCKPH | UCSYNC | UCMSB | UCMODE_2;
UCB0CTL1 = 0x00;
// enable RX interrupt
UC0IE |= UCB0RXIE;
// digit driver
P1DIR |= BIT0 | BIT1 | BIT2 | BIT3;
P1SEL &= ~(BIT0 | BIT1 | BIT2 | BIT3);
P1SEL2 &= ~(BIT0 | BIT1 | BIT2 | BIT3);
// segment driver
P2DIR = 0xff;
P2SEL = 0x00;
P2SEL2 = 0x00;
// all digits off
P1OUT |= (BIT0 | BIT1 | BIT2 | BIT3);
// all segments off
P2OUT &= ~(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7);
// reset value to 0
value.value = 0;
__enable_interrupt();
while (1) {
__disable_interrupt();
uint16_t shadowValue = value.value;
__enable_interrupt();
uint8_t digit0 = shadowValue % 10;
uint8_t digit1 = (shadowValue / 10) % 10;
uint8_t digit2 = (shadowValue / 100) % 10;
uint8_t digit3 = (shadowValue / 1000) % 10;
digit1 += (!((digit3 & 0x0f) | (digit2 & 0x0f) | (digit1 & 0x0f))) ? 0x20 : 0x00;
digit2 += (!((digit3 & 0x0f) | (digit2 & 0x0f))) ? 0x20 : 0x00;
digit3 += (!(digit3 & 0x0f)) ? 0x20 : 0x00;
setDigit(BIT0, digit0);
delay();
setDigit(BIT1, digit1);
delay();
setDigit(BIT2, digit2);
delay();
setDigit(BIT3, digit3);
delay();
}
}

BIN
docs/IMG_4936.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
docs/display-driver.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/game-ctrl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
docs/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/reset-ctrl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
docs/rgb-driver.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/schematics.pdf Executable file

Binary file not shown.

BIN
docs/sound-driver-1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
docs/sound-driver-2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/sound-driver-3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
docs/sound-driver-4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -7,11 +7,11 @@ MCU=msp430g2553
CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
# for debugging
# CFLAGS+= -g3 -ggdb -gdwarf-2
CFLAGS+= -g3 -ggdb -gdwarf-2
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
$(ARTIFACT).elf: main.o led.o time.o PontCoopScheduler.o displayDriver.o canvas.o shapes.o game.o buttons.o
$(ARTIFACT).elf: main.o spi.o scheduler.o canvas.o shapes.o game.o buttons.o myrand.o display.o sound.o eeprom.o
$(CC) -o $@ $(LDFLAGS) $^
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt

View File

@ -1,98 +1,114 @@
#include "stddef.h"
#include "stdint.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <msp430g2553.h>
#include "buttons.h"
#include "PontCoopScheduler.h"
#include "scheduler.h"
#include "shapes.h"
#include "canvas.h"
#include "led.h"
#include "sound.h"
// TEST CODE
uint16_t counter;
bool mutedFlag = true;
static uint8_t buttonsMoveLeftPressed() {
// -----------------------
// TEST CODE
//if (counter == 95) {
// ledGreenToggle();
// return 1;
//}
// -----------------------
return 0;
static uint8_t last = 0;
uint8_t current = (P2IN & BIT4);
uint8_t res = (current != 0) && (current != last);
last = current;
return res;
}
static uint8_t buttonsMoveRightPressed() {
// -----------------------
// TEST CODE
if (counter == 95) {
ledGreenToggle();
return 1;
}
// -----------------------
return 0;
static uint8_t last = 0;
uint8_t current = (P2IN & BIT0);
uint8_t res = (current != 0) && (current != last);
last = current;
return res;
}
static uint8_t buttonsRotateLeftPressed() {
return 0;
static uint8_t last = 0;
uint8_t current = (P2IN & BIT3);
uint8_t res = (current != 0) && (current != last);
last = current;
return res;
}
static uint8_t buttonsRotateRightPressed() {
// -----------------------
// TEST CODE
if (counter == 35) {
ledGreenToggle();
return 1;
}
// -----------------------
// -----------------------
// TEST CODE
if (counter == 45) {
ledGreenToggle();
return 1;
}
// -----------------------
return 0;
static uint8_t last = 0;
uint8_t current = (P2IN & BIT1);
uint8_t res = (current != 0) && (current != last);
last = current;
return res;
}
static uint8_t buttonsMoveDownPressed() {
return P2IN & BIT2;
}
void buttonsExec(void *handle) {
static uint32_t unmuteTimestamp;
uint32_t currentTimestamp = getSeconds();
if (! stoneIsValid()) {
// don't do anything, the stone has not been initialized
return;
}
// TEST CODE
counter++;
uint8_t buttonPressed = 0;
if (buttonsMoveLeftPressed()) {
stoneMoveLeft();
soundCtrl(SOUND_MOTION);
buttonPressed = 1;
}
if (buttonsMoveRightPressed()) {
stoneMoveRight();
soundCtrl(SOUND_MOTION);
buttonPressed = 1;
}
if (buttonsRotateLeftPressed()) {
stoneRotateLeft();
soundCtrl(SOUND_MOTION);
buttonPressed = 1;
}
if (buttonsRotateRightPressed()) {
stoneRotateRight();
soundCtrl(SOUND_MOTION);
buttonPressed = 1;
}
if (buttonsMoveDownPressed()) {
stoneMoveDown();
soundCtrl(SOUND_MOTION);
buttonPressed = 1;
}
if (buttonPressed == 1) {
canvasShow();
if (mutedFlag) {
soundCtrl(SOUND_UNMUTE);
mutedFlag = false;
}
unmuteTimestamp = currentTimestamp;
}
if ((! mutedFlag) && (unmuteTimestamp + MUTE_DELAY < currentTimestamp)) {
soundCtrl(SOUND_MUTE);
mutedFlag = true;
}
}
void buttonsInit() {
// TEST CODE
counter = 0;
P2DIR &= ~(BIT0|BIT1|BIT2|BIT3|BIT4);
schAdd(buttonsExec, NULL, 0, 100);
schAdd(buttonsExec, NULL, 0, 25);
}
bool isGameActive() {
return ! mutedFlag;
}

View File

@ -1,7 +1,10 @@
#ifndef _BUTTONS_H_
#define _BUTTONS_H_
#include <stdbool.h>
void buttonsInit();
bool isGameActive();
#endif // _BUTTONS_H_

View File

@ -1,39 +1,80 @@
#include <string.h>
#include <stdint.h>
#include <msp430g2553.h>
#include "canvas.h"
#include "displayDriver.h"
#include "spi.h"
static uint8_t canvasStorage[CANVAS_WIDTH * CANVAS_HEIGHT];
const canvas_t canvas = {
.height = CANVAS_HEIGHT,
.width = CANVAS_WIDTH,
.size = CANVAS_WIDTH * CANVAS_HEIGHT,
.canvas = canvasStorage
};
static uint8_t miniCanvasStorage[MINI_CANVAS_WIDTH * MINI_CANVAS_HEIGHT];
const canvas_t miniCanvas = {
.height = MINI_CANVAS_HEIGHT,
.width = MINI_CANVAS_WIDTH,
.canvas = miniCanvasStorage
};
void canvasShow() {
// wait for signal waiting for data
while (!(P1IN & BIT3));
spiSendBegin(e_SPI_CANVAS);
for (uint8_t i = 0; i < (CANVAS_WIDTH*CANVAS_HEIGHT); i++) {
if ((*((canvas.canvas)+i) & 0x80) != 0) {
*((canvas.canvas)+i) &= ~0x80;
spiSendOctet(i);
spiSendOctet(*((canvas.canvas)+i));
}
}
for (uint8_t i = 0; i < (MINI_CANVAS_WIDTH*MINI_CANVAS_HEIGHT); i++) {
if ((*((miniCanvas.canvas)+i) & 0x80) != 0) {
*((miniCanvas.canvas)+i) &= ~0x80;
spiSendOctet(i + (CANVAS_HEIGHT*CANVAS_WIDTH));
spiSendOctet(*((miniCanvas.canvas)+i));
}
}
spiSendOctet(0xfe);
spiSendEnd(e_SPI_CANVAS);
}
void canvasInit() {
// P1.3 is signal line
P1DIR &= ~BIT3;
canvasClear();
displayDriverTransferCanvas();
miniCanvasClear();
canvasShow();
}
void canvasClear() {
memset(canvas.canvas, 0x80, canvas.size);
memset(canvas.canvas, 0x80, CANVAS_WIDTH*CANVAS_HEIGHT);
}
void canvasSetAll(uint8_t color) {
memset(canvas.canvas, color + 0x80, canvas.size);
void miniCanvasClear() {
memset(miniCanvas.canvas, 0x80, MINI_CANVAS_WIDTH*MINI_CANVAS_HEIGHT);
}
void canvasShow() {
displayDriverTransferCanvas();
}
//void canvasSetAll(uint8_t color) {
// memset(canvas.canvas, color + 0x80, CANVAS_WIDTH*CANVAS_HEIGHT);
//}
void canvasSetPixel(uint8_t column, uint8_t row, uint8_t color) {
*((canvas.canvas) + (row * canvas.width + column)) = (color + 0x80);
}
void miniCanvasSetPixel(uint8_t column, uint8_t row, uint8_t color) {
*((miniCanvas.canvas) + (row * miniCanvas.width + column)) = (color + 0x80);
}
void canvasWipeRow(uint8_t row) {
memmove(((canvas.canvas)+canvas.width), canvas.canvas, canvas.width*row);
for (uint8_t i = 10; i < canvas.width*(row+1); i++) {
@ -42,6 +83,13 @@ void canvasWipeRow(uint8_t row) {
memset(canvas.canvas, 0x80, canvas.width);
}
void canvasFillRow(uint8_t row, uint8_t color) {
for (uint8_t c = 0; c < canvas.width; c++) {
canvasSetPixel(c, row, color);
}
}
uint8_t canvasIsRowFilled(uint8_t row) {
uint8_t res = 1;
for (uint8_t column = 0; column < canvas.width; column++) {

View File

@ -3,9 +3,10 @@
#include <stdint.h>
// Definition of CANVAS_WIDTH and CANVAS_HEIGHT
// imported from rgb-driver
#include "../rgb-driver/canvasSize.h"
#define CANVAS_WIDTH 10
#define CANVAS_HEIGHT 11
typedef struct {
const uint8_t width;
@ -16,13 +17,14 @@ typedef struct {
void canvasInit();
void canvasClear();
void canvasSetAll(uint8_t color);
void miniCanvasClear();
//void canvasSetAll(uint8_t color);
void canvasShow();
void canvasSetPixel(uint8_t column, uint8_t row, uint8_t color);
void miniCanvasSetPixel(uint8_t column, uint8_t row, uint8_t color);
uint8_t canvasIsPixelFree(uint8_t column, uint8_t row);
void canvasWipeRow(uint8_t row);
void canvasFillRow(uint8_t row, uint8_t color);
uint8_t canvasIsRowFilled(uint8_t row);
extern const canvas_t canvas;
#endif // _CANVAS_H_

View File

@ -1,6 +1,6 @@
#include "led.h"
#include <msp430g2553.h>
#include "PontCoopScheduler.h"
#include "scheduler.h"
#include <stdlib.h>

26
game-ctrl/display.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdint.h>
#include "display.h"
#include "spi.h"
void displayInit() {
}
void displaySetValue(uint16_t v) {
union {
uint16_t value;
uint8_t sendBuffer[2];
} value;
value.value = v;
spiSendBegin(e_SPI_DISPLAY);
spiSendOctet(value.sendBuffer[0]);
spiSendOctet(value.sendBuffer[1]);
spiSendEnd(e_SPI_DISPLAY);
}

13
game-ctrl/display.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _DISPLAY_H_
#define _DISPLAY_H_
#include <stdint.h>
void displayInit();
void displaySetValue(uint16_t v);
#endif // _DISPLAY_H_

View File

@ -1,57 +0,0 @@
#include "displayDriver.h"
#include "led.h"
#include "canvas.h"
#include <msp430g2553.h>
#include <stdlib.h>
#include <stdint.h>
inline static void spiSendOctet(uint8_t v) {
// wait for TX buffer empty
while (!(UC0IFG & UCB0TXIFG));
// load octet into TX buffer
UCB0TXBUF = v;
}
void displayDriverTransferCanvas() {
// wait for signal waiting for data
while ((P1IN & BIT3) == 0);
for (uint8_t i = 0; i < canvas.size; i++) {
if ((*((canvas.canvas)+i) & 0x80) != 0) {
*((canvas.canvas)+i) &= ~0x80;
spiSendOctet(i);
spiSendOctet(*((canvas.canvas)+i));
}
}
spiSendOctet(0xfe);
}
void displayDriverInit() {
// SPI in master mode
UCB0CTL0 = UCMST;
// SPI timing config
UCB0CTL1 = UCSSEL_3;
// Faster than 8 ends up in strange communication errors
// between the both MCUs.
// With 8 the transfer of a complete 110 pixel canvas takes
// about 720us.
UCB0BR0 = 8;
UCB0BR1 = 0;
// BIT5: UCB0CLK
// BIT6: UCB0SOMI
// BIT7: UCB0SIMO
P1SEL |= BIT5 | BIT6 | BIT7;
P1SEL2 |= BIT5 | BIT6 | BIT7;
P1DIR |= BIT5 | BIT7;
// P1.3 is signal line
P1DIR &= ~BIT3;
// enable SPI module
UCB0CTL1 &= ~UCSWRST;
}

View File

@ -1,9 +0,0 @@
#ifndef _DISPLAY_DRIVER_H_
#define _DISPLAY_DRIVER_H_
void displayDriverInit();
void displayDriverTransferCanvas();
#endif // _DISPLAY_DRIVER_H_

Binary file not shown.

75
game-ctrl/eeprom.c Normal file
View File

@ -0,0 +1,75 @@
#include <stdint.h>
#include "eeprom.h"
#include "spi.h"
#define MAGIC 0xaffe
#define HIGHSCORE_ADDR 0x00
#define DUMMY 0x00
#define CMD_READ 0b00000011
#define CMD_WRITE 0b00000010
#define CMD_WRDI 0b00000100
#define CMD_WREN 0b00000110
typedef union {
uint8_t buffer[4];
struct {
uint16_t magic;
uint16_t highScore;
} v;
} eepromBuf_t;
eepromBuf_t buf;
static void writeBuf() {
spiSendBegin(e_SPI_EEPROM);
spiSendOctet(CMD_WREN);
spiSendEnd(e_SPI_EEPROM);
spiSendBegin(e_SPI_EEPROM);
spiSendOctet(CMD_WRITE);
spiSendOctet(HIGHSCORE_ADDR);
spiSendOctet(buf.buffer[0]);
spiSendOctet(buf.buffer[1]);
spiSendOctet(buf.buffer[2]);
spiSendOctet(buf.buffer[3]);
spiSendEnd(e_SPI_EEPROM);
}
static void readBuf() {
spiSendBegin(e_SPI_EEPROM);
spiSendOctet(CMD_READ);
spiReceiveOctet();
spiSendOctet(HIGHSCORE_ADDR);
spiReceiveOctet();
spiSendOctet(DUMMY);
buf.buffer[0] = spiReceiveOctet();
spiSendOctet(DUMMY);
buf.buffer[1] = spiReceiveOctet();
spiSendOctet(DUMMY);
buf.buffer[2] = spiReceiveOctet();
spiSendOctet(DUMMY);
buf.buffer[3] = spiReceiveOctet();
spiSendEnd(e_SPI_EEPROM);
}
void eepromInit() {
readBuf();
if (buf.v.magic != MAGIC) {
buf.v.magic = MAGIC;
buf.v.highScore = 0;
writeBuf();
}
}
uint16_t eepromReadHighScore() {
return buf.v.highScore;
}
void eepromWriteHighScore(uint16_t v) {
buf.v.highScore = v;
writeBuf();
}

13
game-ctrl/eeprom.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _EEPROM_H_
#define _EEPROM_H_
#include <stdint.h>
void eepromInit();
uint16_t eepromReadHighScore();
void eepromWriteHighScore(uint16_t v);
#endif // _EEPROM_H_

2
game-ctrl/firmware.gdb Normal file
View File

@ -0,0 +1,2 @@
target remote localhost:2000
file firmware.elf

View File

@ -2,66 +2,164 @@
#include "stdint.h"
#include "game.h"
#include "PontCoopScheduler.h"
#include "scheduler.h"
#include "shapes.h"
#include "canvas.h"
#include "../rgb-driver/colors.h"
#include "display.h"
#include "sound.h"
#include "eeprom.h"
#include "buttons.h"
typedef enum { e_idle, e_start, e_newStone, e_down, e_gameOver, e_delay } state_t;
#define GAME_CYCLE_TIME 50
#define GAMEOVER_DELAY 10
#define MAX_LEVEL 20
static uint8_t delayFactor(uint8_t level) {
return MAX_LEVEL + 1 - level;
}
typedef enum {
e_Phase_Game, e_Phase_GameOver
} phase_t;
typedef enum {
e_Start, e_NewStone, e_Down, e_DownDelay, e_ClearRows,
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
} state_t;
void gameExec(void *handle) {
static state_t state = e_start;
static uint8_t delay;
static phase_t phase;
static state_t state = e_Start;
static uint8_t gameOverDelay;
static uint8_t rowIndex;
static uint8_t proceedDelay;
static uint8_t level;
static uint16_t filledLines;
static uint16_t score;
static bool newHighScoreAchieved;
// --- engine begin -------------------------------------------------------
switch (state) {
case e_idle:
break;
case e_start:
// --- phase: game --------------------------------------------------------
case e_Start:
canvasClear();
state = e_newStone;
soundCtrl(SOUND_START);
level = 1;
filledLines = 0;
score = 0;
newHighScoreAchieved = false;
phase = e_Phase_Game;
state = e_NewStone;
break;
case e_newStone:
case e_NewStone:
stoneCreate();
if (stoneDraw()) {
state = e_down;
proceedDelay = delayFactor(level);
state = e_DownDelay;
} else {
state = e_gameOver;
state = e_GameOver;
}
break;
case e_DownDelay:
proceedDelay--;
if (proceedDelay == 0) {
rowIndex = 0;
state = e_ClearRows;
}
break;
case e_ClearRows:
state = e_Down;
break;
case e_down:
case e_Down:
if (! stoneMoveDown()) {
state = e_newStone;
soundCtrl(SOUND_LOCK);
state = e_NewStone;
} else {
proceedDelay = delayFactor(level);
state = e_DownDelay;
}
break;
case e_gameOver:
for (uint8_t c = 0; c < canvas.width; c++) {
canvasSetPixel(c, 0, 0x0d);
canvasSetPixel(c, canvas.height-1, 0x0d);
}
for (uint8_t r = 0; r < canvas.height; r++) {
canvasSetPixel(0, r, 0x0d);
canvasSetPixel(canvas.width-1, r, 0x0d);
}
delay = 10;
state = e_delay;
// --- phase: game over ---------------------------------------------------
case e_GameOver:
soundCtrl(SOUND_GAMEOVER);
rowIndex = CANVAS_HEIGHT;
phase = e_Phase_GameOver;
state = e_GameOverFill;
break;
case e_delay:
delay--;
if (delay == 0) {
state = e_start;
case e_GameOverFill:
rowIndex--;
canvasFillRow(rowIndex, newHighScoreAchieved ? _green : _red);
if (rowIndex == 0) {
state = e_GameOverWipe;
}
break;
case e_GameOverWipe:
canvasWipeRow(rowIndex);
rowIndex++;
if (rowIndex == CANVAS_HEIGHT) {
gameOverDelay = GAMEOVER_DELAY;
state = e_GameOverDelay;
}
break;
case e_GameOverDelay:
gameOverDelay--;
if (gameOverDelay == 0) {
state = e_Start;
}
break;
}
// --- engine end ---------------------------------------------------------
bool wipedLines = false;
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);
}
if (isGameActive()) {
displaySetValue(score);
} else {
displaySetValue(eepromReadHighScore());
}
}
void gameInit() {
schAdd(gameExec, NULL, 0, 1000);
schAdd(gameExec, NULL, 0, GAME_CYCLE_TIME);
}

View File

@ -4,13 +4,15 @@
#include <stdbool.h>
#include "time.h"
#include "PontCoopScheduler.h"
#include "led.h"
#include "displayDriver.h"
#include "scheduler.h"
#include "canvas.h"
#include "game.h"
#include "buttons.h"
#include "shapes.h"
#include "myrand.h"
#include "spi.h"
#include "display.h"
#include "eeprom.h"
int main() {
@ -24,11 +26,12 @@ int main() {
BCSCTL2 = 0;
BCSCTL3 = 0;
timeInit();
schInit();
ledInit();
displayDriverInit();
spiInit();
eepromInit();
displayInit();
myRandInit();
canvasInit();
shapesInit();

26
game-ctrl/myrand.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdint.h>
#include <msp430g2553.h>
#include "myrand.h"
void myRandInit() {
ADC10CTL1 = INCH_10;
ADC10CTL0 = SREF_1 | ADC10SHT_1 | REFON | ADC10ON;
}
uint16_t myRandGet() {
uint16_t res = 0;
for (uint8_t i = 0; i < 16; i++) {
ADC10CTL0 |= ENC | ADC10SC;
while ((ADC10CTL1 & ADC10BUSY));
res <<= 1;
res |= ADC10MEM & 0x0001;
}
return res;
}

8
game-ctrl/myrand.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _MYRAND_H_
#define _MYRAND_H_
void myRandInit();
uint16_t myRandGet();
#endif // _MYRAND_H_

111
game-ctrl/scheduler.c Normal file
View File

@ -0,0 +1,111 @@
/*
* PontCoopScheduler.c
*
* Originally created on: 29.08.2016
* Author: wn
*/
#include <stdlib.h>
#include <msp430g2553.h>
#include "scheduler.h"
tTask tasks[MAX_NUM_OF_TASKS];
uint32_t seconds;
void schInit() {
TACCR0 = 32;
TACCTL0 = CCIE;
TACTL = MC_1 | ID_0 | TASSEL_1 | TACLR;
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
tasks[i].delay = 0;
tasks[i].period = 0;
tasks[i].run = 0;
tasks[i].exec = NULL;
tasks[i].handle = NULL;
}
seconds = 0;
}
void __attribute__ ((interrupt (TIMER0_A0_VECTOR))) schUpdate() {
static uint16_t milliSeconds = 0;
if (milliSeconds >= 1000) {
seconds += 1;
milliSeconds = 0;
}
milliSeconds += 1;
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
if (tasks[i].exec != NULL) {
if (tasks[i].delay == 0) {
tasks[i].delay = tasks[i].period;
tasks[i].run++;
} else {
tasks[i].delay--;
}
}
}
}
void schAdd(void (*exec)(void *), void *handle, uint32_t delay, uint32_t period) {
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
if (tasks[i].exec == NULL) {
tasks[i].delay = delay;
tasks[i].period = period;
if (delay == 0 && period == 0) {
tasks[i].run = 1;
} else {
tasks[i].run = 0;
}
tasks[i].exec = exec;
tasks[i].handle = handle;
break;
}
}
}
/*
void schDel(void (*exec)(void *), void *handle) {
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
if ((tasks[i].exec == exec) && (tasks[i].handle == handle)) {
tasks[i].exec = NULL;
break;
}
}
}
*/
void schExec() {
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
// synchronize access to tasks[].run
__disable_interrupt();
if (tasks[i].exec != NULL && tasks[i].run > 0) {
tasks[i].run--;
// synchronize access to tasks[].run
// reenable interrupts before actually executing task
__enable_interrupt();
tasks[i].exec(tasks[i].handle);
if (tasks[i].period == 0) {
tasks[i].exec = NULL;
}
} else {
// synchronize access to tasks[].run
// reenable interrupts in case task is not yet executable
__enable_interrupt();
}
}
}
uint32_t getSeconds() {
uint32_t s;
__disable_interrupt();
s = seconds;
__enable_interrupt();
return s;
}

View File

@ -31,6 +31,7 @@ void schDel(void (*exec)(void *), void *handle);
void schExec();
void schUpdate();
uint8_t schTaskCnt();
uint32_t getSeconds();
#endif /* PONTCOOPSCHEDULER_H_ */

View File

@ -1,7 +1,9 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include "shapes.h"
#include "myrand.h"
#include "canvas.h"
#include "../rgb-driver/colors.h"
@ -42,7 +44,7 @@ typedef struct {
motion_t motion[5][4];
} motionTable_t;
const motionTable_t motions[2] = { // 2 = number of implemented stones
const motionTable_t motions[7] = { // size = number of implemented stones
{ // I
.color = _cyan,
.nullRotation = 0,
@ -120,13 +122,223 @@ const motionTable_t motions[2] = { // 2 = number of implemented stones
},
{
// rotate right
{ .set = { {-2, 1}, {-1, 1}, { 1, 1}, { 1, 1} }, .reset = { { 0, 0}, { 0, 2}, { 0, 3}, { 0, 3} }, .offset = {-2, 1} }, // 0
{ .set = { { 1,-1}, { 1, 1}, { 1, 2}, { 1, 2} }, .reset = { { 0, 0}, { 2, 0}, { 3, 0}, { 3, 0} }, .offset = { 1,-1} }, // 90
{ .set = { {-2, 1}, {-1, 1}, { 1, 1}, { 1, 1} }, .reset = { { 0, 0}, { 0, 2}, { 0, 3}, { 0, 3} }, .offset = {-2, 1} }, // 180
{ .set = { { 1,-1}, { 1, 1}, { 1, 2}, { 1, 2} }, .reset = { { 0, 0}, { 2, 0}, { 3, 0}, { 3, 0} }, .offset = { 1,-1} }, // 270
{ .set = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .reset = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .offset = { 0, 0} }, // 0
{ .set = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .reset = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .offset = { 0, 0} }, // 90
{ .set = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .reset = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .offset = { 0, 0} }, // 180
{ .set = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .reset = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .offset = { 0, 0} }, // 270
},
}
}
},
{ // T
.color = _violet,
.nullRotation = 0,
.draw = { { 0, 0}, { 1, 0}, { 2, 0}, { 1, 1} },
.motion = {
{
// move down
{ .set = { { 0, 1}, { 2, 1}, { 1, 2}, { 1, 2} }, .reset = { { 0, 0}, { 1, 0}, { 2, 0}, { 2, 0} }, .offset = { 0, 1} }, // 0
{ .set = { { 0, 2}, { 1, 3}, { 1, 3}, { 1, 3} }, .reset = { { 1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 1} }, // 90
{ .set = { { 0, 2}, { 1, 2}, { 2, 2}, { 2, 2} }, .reset = { { 1, 0}, { 0, 1}, { 2, 1}, { 2, 1} }, .offset = { 0, 1} }, // 180
{ .set = { { 0, 3}, { 1, 2}, { 1, 2}, { 1, 2} }, .reset = { { 0, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0, 1} }, // 270
},
{
// move left
{ .set = { {-1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 1, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = {-1, 0} }, // 0
{ .set = { { 0, 0}, {-1, 1}, { 0, 2}, { 0, 2} }, .reset = { { 1, 0}, { 1, 1}, { 1, 2}, { 1, 2} }, .offset = {-1, 0} }, // 90
{ .set = { {-1, 1}, { 0, 0}, { 0, 0}, { 0, 0} }, .reset = { { 1, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1, 0} }, // 180
{ .set = { {-1, 0}, {-1, 1}, {-1, 2}, {-1, 2} }, .reset = { { 0, 0}, { 0, 2}, { 1, 1}, { 1, 1} }, .offset = {-1, 0} }, // 270
},
{
// move right
{ .set = { { 3, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 0, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 1, 0} }, // 0
{ .set = { { 2, 0}, { 2, 1}, { 2, 2}, { 2, 2} }, .reset = { { 0, 1}, { 1, 0}, { 1, 2}, { 1, 2} }, .offset = { 1, 0} }, // 90
{ .set = { { 3, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 0, 1}, { 1, 0}, { 1, 0} }, .offset = { 1, 0} }, // 180
{ .set = { { 1, 0}, { 1, 2}, { 2, 1}, { 2, 1} }, .reset = { { 0, 0}, { 0, 1}, { 0, 2}, { 0, 2} }, .offset = { 1, 0} }, // 270
},
{
// rotate left
{ .set = { { 1,-1}, { 1,-1}, { 1,-1}, { 1,-1} }, .reset = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .offset = { 1,-1} }, // 0
{ .set = { { 2, 1}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 1, 0}, { 1, 0}, { 1, 0}, { 1, 0} }, .offset = { 0, 1} }, // 90
{ .set = { { 1, 2}, { 1, 2}, { 1, 2}, { 1, 2} }, .reset = { { 2, 1}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = { 0, 0} }, // 180
{ .set = { {-1, 1}, {-1, 1}, {-1, 1}, {-1, 1} }, .reset = { { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} }, .offset = {-1, 0} }, // 270
},
{
// rotate right
{ .set = { { 1,-1}, { 1,-1}, { 1,-1}, { 1,-1} }, .reset = { { 2, 0}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 0,-1} }, // 0
{ .set = { { 2, 1}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 1, 2}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 0, 0} }, // 90
{ .set = { { 1, 2}, { 1, 2}, { 1, 2}, { 1, 2} }, .reset = { { 0, 1}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 1, 0} }, // 180
{ .set = { {-1, 1}, {-1, 1}, {-1, 1}, {-1, 1} }, .reset = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }, .offset = {-1, 1} }, // 270
},
}
},
{ // Z
.color = _red,
.nullRotation = 0,
.draw = { { 0, 0}, { 1, 0}, { 1, 1}, { 2, 1} },
.motion = {
{
// move down
{ .set = { { 0, 1}, { 1, 2}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 1, 0}, { 2, 1}, { 2, 1} }, .offset = { 0, 1} }, // 0
{ .set = { { 1, 2}, { 0, 3}, { 0, 3}, { 0, 3} }, .reset = { { 1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 1} }, // 90
{ .set = { { 0, 1}, { 1, 2}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 1, 0}, { 2, 1}, { 2, 1} }, .offset = { 0, 1} }, // 180
{ .set = { { 1, 2}, { 0, 3}, { 0, 3}, { 0, 3} }, .reset = { { 1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 1} }, // 270
},
{
// move left
{ .set = { {-1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 1, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1, 0} }, // 0
{ .set = { {-1, 1}, {-1, 2}, { 0, 0}, { 0, 0} }, .reset = { { 1, 0}, { 1, 1}, { 0, 2}, { 0, 2} }, .offset = {-1, 0} }, // 90
{ .set = { {-1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 1, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1, 0} }, // 180
{ .set = { {-1, 1}, {-1, 2}, { 0, 0}, { 0, 0} }, .reset = { { 1, 0}, { 1, 1}, { 0, 2}, { 0, 2} }, .offset = {-1, 0} }, // 270
},
{
// move right
{ .set = { { 3, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 1, 0} }, // 0
{ .set = { { 2, 0}, { 2, 1}, { 1, 2}, { 1, 2} }, .reset = { { 0, 1}, { 0, 2}, { 1, 0}, { 1, 0} }, .offset = { 1, 0} }, // 90
{ .set = { { 3, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 1, 0} }, // 180
{ .set = { { 2, 0}, { 2, 1}, { 1, 2}, { 1, 2} }, .reset = { { 0, 1}, { 0, 2}, { 1, 0}, { 1, 0} }, .offset = { 1, 0} }, // 270
},
{
// rotate left
{ .set = { { 1,-1}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 2, 1}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0,-1} }, // 0
{ .set = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 0, 2}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 0} }, // 90
{ .set = { { 1,-1}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 2, 1}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0,-1} }, // 180
{ .set = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 0, 2}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 0} }, // 270
},
{
// rotate right
{ .set = { { 1,-1}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 2, 1}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0,-1} }, // 0
{ .set = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 0, 2}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 0} }, // 90
{ .set = { { 1,-1}, { 0, 1}, { 0, 1}, { 0, 1} }, .reset = { { 2, 1}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0,-1} }, // 180
{ .set = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .reset = { { 0, 2}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 0} }, // 270
},
}
},
{ // S
.color = _green,
.nullRotation = 0,
.draw = { { 0, 1}, { 1, 1}, { 1, 0}, { 2, 0} },
.motion = {
{
// move down
{ .set = { { 0, 2}, { 1, 2}, { 2, 1}, { 2, 1} }, .reset = { { 0, 1}, { 1, 0}, { 2, 0}, { 2, 0} }, .offset = { 0, 1} }, // 0
{ .set = { { 0, 2}, { 1, 3}, { 1, 3}, { 1, 3} }, .reset = { { 0, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0, 1} }, // 90
{ .set = { { 0, 2}, { 1, 2}, { 2, 1}, { 2, 1} }, .reset = { { 0, 1}, { 1, 0}, { 2, 0}, { 2, 0} }, .offset = { 0, 1} }, // 180
{ .set = { { 0, 2}, { 1, 3}, { 1, 3}, { 1, 3} }, .reset = { { 0, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 0, 1} }, // 270
},
{
// move left
{ .set = { { 0, 0}, {-1, 1}, {-1, 1}, {-1, 1} }, .reset = { { 2, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = {-1, 0} }, // 0
{ .set = { {-1, 0}, {-1, 1}, { 0, 2}, { 0, 2} }, .reset = { { 0, 0}, { 1, 1}, { 1, 2}, { 1, 2} }, .offset = {-1, 0} }, // 90
{ .set = { { 0, 0}, {-1, 1}, {-1, 1}, {-1, 1} }, .reset = { { 2, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = {-1, 0} }, // 180
{ .set = { {-1, 0}, {-1, 1}, { 0, 2}, { 0, 2} }, .reset = { { 0, 0}, { 1, 1}, { 1, 2}, { 1, 2} }, .offset = {-1, 0} }, // 270
},
{
// move right
{ .set = { { 2, 1}, { 3, 0}, { 3, 0}, { 3, 0} }, .reset = { { 1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 1, 0} }, // 0
{ .set = { { 1, 0}, { 2, 1}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 0, 1}, { 1, 2}, { 1, 2} }, .offset = { 1, 0} }, // 90
{ .set = { { 2, 1}, { 3, 0}, { 3, 0}, { 3, 0} }, .reset = { { 1, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 1, 0} }, // 180
{ .set = { { 1, 0}, { 2, 1}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 0, 1}, { 1, 2}, { 1, 2} }, .offset = { 1, 0} }, // 270
},
{
// rotate left
{ .set = { { 0, 0}, { 0,-1}, { 0,-1}, { 0,-1} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 0,-1} }, // 0
{ .set = { { 1, 0}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 0, 0} }, // 90
{ .set = { { 0, 0}, { 0,-1}, { 0,-1}, { 0,-1} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 0,-1} }, // 180
{ .set = { { 1, 0}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 0, 0} }, // 270
},
{
// rotate right
{ .set = { { 0, 0}, { 0,-1}, { 0,-1}, { 0,-1} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 0,-1} }, // 0
{ .set = { { 1, 0}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 0, 0} }, // 90
{ .set = { { 0, 0}, { 0,-1}, { 0,-1}, { 0,-1} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 0,-1} }, // 180
{ .set = { { 1, 0}, { 2, 0}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 0, 0} }, // 270
},
}
},
{ // L
.color = _orange,
.nullRotation = 0,
.draw = { { 0, 0}, { 0, 1}, { 0, 2}, { 1, 2} },
.motion = {
{
// move down
{ .set = { { 0, 3}, { 1, 3}, { 1, 3}, { 1, 3} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 0, 1} }, // 0
{ .set = { { 1, 1}, { 2, 1}, { 0, 2}, { 0, 2} }, .reset = { { 0, 0}, { 1, 0}, { 2, 0}, { 2, 0} }, .offset = { 0, 1} }, // 90
{ .set = { { 0, 1}, { 1, 3}, { 1, 3}, { 1, 3} }, .reset = { { 0, 0}, { 1, 0}, { 1, 0}, { 1, 0} }, .offset = { 0, 1} }, // 180
{ .set = { { 0, 2}, { 1, 2}, { 2, 2}, { 2, 2} }, .reset = { { 2, 0}, { 0, 1}, { 1, 1}, { 1, 1} }, .offset = { 0, 1} }, // 270
},
{
// move left
{ .set = { {-1, 0}, {-1, 1}, {-1, 2}, {-1, 2} }, .reset = { { 0, 0}, { 0, 1}, { 1, 2}, { 0, 0} }, .offset = {-1, 0} }, // 0
{ .set = { {-1, 0}, {-1, 1}, {-1, 1}, {-1, 1} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = {-1, 0} }, // 90
{ .set = { { 0, 1}, { 0, 2}, {-1, 0}, {-1, 0} }, .reset = { { 1, 0}, { 1, 1}, { 1, 2}, { 1, 2} }, .offset = {-1, 0} }, // 180
{ .set = { {-1, 1}, { 1, 0}, { 1, 0}, { 1, 0} }, .reset = { { 2, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1, 0} }, // 270
},
{
// move right
{ .set = { { 1, 0}, { 1, 1}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 0, 1}, { 0, 2}, { 0, 2} }, .offset = { 1, 0} }, // 0
{ .set = { { 1, 1}, { 3, 0}, { 3, 0}, { 3, 0} }, .reset = { { 0, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 1, 0} }, // 90
{ .set = { { 2, 0}, { 2, 1}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 1, 1}, { 1, 2}, { 1, 2} }, .offset = { 1, 0} }, // 180
{ .set = { { 3, 0}, { 3, 1}, { 3, 1}, { 3, 1} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 1, 0} }, // 270
},
{
// rotate left
{ .set = { {-1, 2}, {-2, 2}, {-2, 2}, {-2, 2} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = {-2, 1} }, // 0
{ .set = { { 0,-1}, { 0,-2}, { 0,-2}, { 0,-2} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 0,-2} }, // 90
{ .set = { { 2, 0}, { 3, 0}, { 3, 0}, { 3, 0} }, .reset = { { 0, 0}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = { 1, 0} }, // 180
{ .set = { { 2, 2}, { 2, 3}, { 2, 3}, { 2, 3} }, .reset = { { 0, 1}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = { 1, 1} }, // 270
},
{
// rotate right
{ .set = { { 0, 3}, { 2, 2}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 0, 2} }, // 0
{ .set = { {-1, 0}, { 0, 2}, { 0, 2}, { 0, 2} }, .reset = { { 1, 0}, { 2, 0}, { 2, 0}, { 2, 0} }, .offset = {-1, 0} }, // 90
{ .set = { {-1, 0}, { 1,-1}, { 1,-1}, { 1,-1} }, .reset = { { 1, 1}, { 1, 2}, { 1, 2}, { 1, 2} }, .offset = {-1,-1} }, // 180
{ .set = { { 2,-1}, { 3, 1}, { 3, 1}, { 3, 1} }, .reset = { { 0, 1}, { 1, 1}, { 1, 1}, { 1, 1} }, .offset = { 2,-1} }, // 270
},
}
},
{ // J
.color = _blue,
.nullRotation = 0,
.draw = { { 0, 2}, { 1, 0}, { 1, 1}, { 1, 2} },
.motion = {
{
// move down
{ .set = { { 0, 3}, { 1, 3}, { 1, 3}, { 1, 3} }, .reset = { { 0, 2}, { 1, 0}, { 1, 0}, { 1, 0} }, .offset = { 0, 1} }, // 0
{ .set = { { 0, 2}, { 1, 2}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 1, 1}, { 2, 1}, { 2, 1} }, .offset = { 0, 1} }, // 90
{ .set = { { 0, 3}, { 1, 1}, { 1, 1}, { 1, 1} }, .reset = { { 0, 0}, { 1, 0}, { 1, 0}, { 1, 0} }, .offset = { 0, 1} }, // 180
{ .set = { { 0, 1}, { 1, 1}, { 2, 2}, { 2, 2} }, .reset = { { 0, 0}, { 1, 0}, { 2, 0}, { 2, 0} }, .offset = { 0, 1} }, // 270
},
{
// move left
{ .set = { { 0, 0}, { 0, 1}, {-1, 2}, {-1, 2} }, .reset = { { 1, 0}, { 1, 1}, { 1, 2}, { 1, 2} }, .offset = {-1, 0} }, // 0
{ .set = { {-1, 0}, {-1, 1}, {-1, 1}, {-1, 1} }, .reset = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1, 0} }, // 90
{ .set = { {-1, 0}, {-1, 1}, {-1, 2}, {-1, 2} }, .reset = { { 1, 0}, { 0, 1}, { 0, 2}, { 0, 2} }, .offset = {-1, 0} }, // 180
{ .set = { {-1, 0}, { 1, 1}, { 1, 1}, { 1, 1} }, .reset = { { 2, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1, 0} }, // 270
},
{
// move right
{ .set = { { 2, 0}, { 2, 1}, { 2, 2}, { 2, 2} }, .reset = { { 1, 0}, { 1, 1}, { 0, 2}, { 0, 2} }, .offset = { 1, 0} }, // 0
{ .set = { { 1, 0}, { 3, 1}, { 3, 1}, { 3, 1} }, .reset = { { 0, 0}, { 0, 1}, { 0, 1}, { 0, 1} }, .offset = { 1, 0} }, // 90
{ .set = { { 1, 1}, { 1, 2}, { 2, 0}, { 2, 0} }, .reset = { { 0, 0}, { 0, 1}, { 0, 2}, { 0, 2} }, .offset = { 1, 0} }, // 180
{ .set = { { 3, 0}, { 3, 1}, { 3, 1}, { 3, 1} }, .reset = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = { 1, 0} }, // 270
},
{
// rotate left
{ .set = { { 1, 3}, {-1, 2}, {-1, 2}, {-1, 2} }, .reset = { { 1, 0}, { 1, 1}, { 0, 0}, { 0, 0} }, .offset = {-1, 2} }, // 0
{ .set = { {-1, 1}, { 0,-1}, { 0,-1}, { 0,-1} }, .reset = { { 1, 1}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = {-1,-1} }, // 90
{ .set = { { 2, 0}, { 0,-1}, { 0,-1}, { 0,-1} }, .reset = { { 0, 1}, { 0, 2}, { 0, 2}, { 0, 2} }, .offset = { 0,-1} }, // 180
{ .set = { { 2, 2}, { 3, 0}, { 3, 0}, { 3, 0} }, .reset = { { 0, 0}, { 1, 0}, { 1, 0}, { 1, 0} }, .offset = { 2, 0} }, // 270
},
{
// rotate right
{ .set = { { 2, 2}, { 3, 2}, { 3, 2}, { 3, 2} }, .reset = { { 1, 0}, { 0, 2}, { 0, 2}, { 0, 2} }, .offset = { 1, 1} }, // 0
{ .set = { { 0, 2}, { 0, 3}, { 0, 3}, { 0, 3} }, .reset = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = { 0, 1} }, // 90
{ .set = { {-1, 0}, {-2, 0}, {-2, 0}, {-2, 0} }, .reset = { { 1, 0}, { 0, 2}, { 0, 2}, { 0, 2} }, .offset = {-2, 0} }, // 180
{ .set = { { 2,-1}, { 2,-2}, { 2,-2}, { 2,-2} }, .reset = { { 0, 0}, { 2, 1}, { 2, 1}, { 2, 1} }, .offset = { 1,-2} }, // 270
},
}
},
};
const orientation_t nextOrientation[5][4] = { // 5 = number of directions to move, 4 = number of orientation a stone can have
@ -138,20 +350,18 @@ const orientation_t nextOrientation[5][4] = { // 5 = number of directions to mov
};
stone_t stone;
shape_t nextShape;
void shapesInit() {
stone.shape = e_ShapeInvalid;
nextShape = e_Z;
}
void stoneCreate() {
static uint8_t cnt = 0;
stone.shape = ((shape_t[]){ e_I, e_O, e_T, e_Z, e_S, e_L, e_J })[cnt];
cnt++;
if (cnt > 1) {
cnt = 0;
}
stone.shape = nextShape;
nextShape = ((shape_t[]){ e_I, e_O, e_T, e_Z, e_S, e_L, e_J })[myRandGet() % e_ShapeInvalid];
stone.orientation = e_0;
stone.x = 5;
stone.x = 4;
stone.y = 0;
}
@ -161,39 +371,100 @@ uint8_t stoneIsValid() {
// all of them return 1 in case of success and 0 in case of error
static uint8_t move(direction_t direction) {
// if this is a rotation and the shape is marked with nullRotation (just the O), do nothing
// and return success
if (motions[stone.shape].nullRotation && (direction == e_RotateLeft || direction == e_RotateRight)) {
return 1;
}
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) &&
canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[1].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[1].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[2].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[2].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[3].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[3].y)) {
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[0].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[0].y, _off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[1].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[1].y, _off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[2].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[2].y, _off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[3].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[3].y, _off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[0].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[0].y, motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[1].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[1].y, motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[2].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[2].y, motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[3].x, stone.y + motions[stone.shape].motion[direction][stone.orientation].set[3].y, motions[stone.shape].color);
// check whether the pixels to move to are free
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) &&
canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[1].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[1].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[2].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[2].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[3].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[3].y)) {
// if so, reset the pixels the shape moves away from
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[0].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[0].y,
_off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[1].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[1].y,
_off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[2].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[2].y,
_off);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].reset[3].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].reset[3].y,
_off);
// and set the pixels the shape moves to to the shape's color
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[0].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[0].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[1].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[1].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[2].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[2].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[3].x,
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[3].y,
motions[stone.shape].color);
// set the new origin of the shape
stone.x += motions[stone.shape].motion[direction][stone.orientation].offset.x;
stone.y += motions[stone.shape].motion[direction][stone.orientation].offset.y;
stone.orientation = (nextOrientation[direction][stone.orientation] == e_Keep) ? stone.orientation : nextOrientation[direction][stone.orientation];
// set the new orientation of the shape, if required
stone.orientation = (nextOrientation[direction][stone.orientation] == e_Keep) ?
stone.orientation :
nextOrientation[direction][stone.orientation];
return 1;
}
return 0;
}
uint8_t stoneDraw() {
void nextStoneDraw() {
miniCanvasClear();
miniCanvasSetPixel(motions[nextShape].draw[0].x,
motions[nextShape].draw[0].y,
motions[nextShape].color);
miniCanvasSetPixel(motions[nextShape].draw[1].x,
motions[nextShape].draw[1].y,
motions[nextShape].color);
miniCanvasSetPixel(motions[nextShape].draw[2].x,
motions[nextShape].draw[2].y,
motions[nextShape].color);
miniCanvasSetPixel(motions[nextShape].draw[3].x,
motions[nextShape].draw[3].y,
motions[nextShape].color);
}
uint8_t stoneDraw() {
nextStoneDraw();
uint8_t res = 0;
if (canvasIsPixelFree(stone.x + motions[stone.shape].draw[0].x, stone.y + motions[stone.shape].draw[0].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].draw[1].x, stone.y + motions[stone.shape].draw[1].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].draw[2].x, stone.y + motions[stone.shape].draw[2].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].draw[3].x, stone.y + motions[stone.shape].draw[3].y)) {
canvasSetPixel(stone.x + motions[stone.shape].draw[0].x, stone.y + motions[stone.shape].draw[0].y, motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[1].x, stone.y + motions[stone.shape].draw[1].y, motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[2].x, stone.y + motions[stone.shape].draw[2].y, motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[3].x, stone.y + motions[stone.shape].draw[3].y, motions[stone.shape].color);
// check if the pixels the shape should be drawn at are free
if (canvasIsPixelFree(stone.x + motions[stone.shape].draw[0].x,
stone.y + motions[stone.shape].draw[0].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].draw[1].x,
stone.y + motions[stone.shape].draw[1].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].draw[2].x,
stone.y + motions[stone.shape].draw[2].y) &&
canvasIsPixelFree(stone.x + motions[stone.shape].draw[3].x,
stone.y + motions[stone.shape].draw[3].y)) {
// if so, draw the shape
canvasSetPixel(stone.x + motions[stone.shape].draw[0].x,
stone.y + motions[stone.shape].draw[0].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[1].x,
stone.y + motions[stone.shape].draw[1].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[2].x,
stone.y + motions[stone.shape].draw[2].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[3].x,
stone.y + motions[stone.shape].draw[3].y,
motions[stone.shape].color);
res = 1;
}
return res;

18
game-ctrl/sound.c Normal file
View File

@ -0,0 +1,18 @@
#include <stdint.h>
#include "sound.h"
#include "spi.h"
void soundInit() {
}
void soundCtrl(uint8_t cmd) {
spiSendBegin(e_SPI_SOUND);
spiSendOctet(cmd);
spiSendEnd(e_SPI_SOUND);
}

15
game-ctrl/sound.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _SOUND_H_
#define _SOUND_H_
#include <stdint.h>
#define MUTE_DELAY 30 // seconds
#include "../sound-driver/soundCodes.h"
void soundInit();
void soundCtrl(uint8_t cmd);
#endif // _SOUND_H_

56
game-ctrl/spi.c Normal file
View File

@ -0,0 +1,56 @@
#include <msp430g2553.h>
#include "spi.h"
void spiInit() {
// SPI in master mode, most significant bit first
UCB0CTL0 = UCCKPH | UCMST | UCMSB;
// SPI timing config
UCB0CTL1 = UCSSEL_3;
// Faster than 8 ends up in strange communication errors
// between the both MCUs.
// With 8 the transfer of a complete 110 pixel canvas takes
// about 720us.
// 8 was still too fast and caused problems.
UCB0BR0 = 16;
UCB0BR1 = 0;
// BIT5: UCB0CLK
// BIT6: UCB0SOMI
// BIT7: UCB0SIMO
P1SEL |= BIT5 | BIT6 | BIT7;
P1SEL2 |= BIT5 | BIT6 | BIT7;
// P1DIR |= BIT5 | BIT7;
// Device Select Lines: 0: Canvas, 1: Display, 2: Sound, 4: EEPROM
P1DIR |= BIT0 | BIT1 | BIT2 | BIT4;
// Disable all of them
P1OUT |= BIT0 | BIT1 | BIT2 | BIT4;
// enable SPI module
UCB0CTL1 &= ~UCSWRST;
}
void spiSendBegin(t_SpiDeviceSelector d) {
uint16_t bit = ((uint16_t[]){ BIT0, BIT1, BIT2, BIT4 })[d];
P1OUT &= ~bit;
}
void spiSendEnd(t_SpiDeviceSelector d) {
while (UCB0STAT & UCBUSY);
uint16_t bit = ((uint16_t[]){ BIT0, BIT1, BIT2, BIT4 })[d];
P1OUT |= bit;
}
void spiSendOctet(uint8_t v) {
// wait for TX buffer empty
while (!(UC0IFG & UCB0TXIFG));
// load octet into TX buffer
UCB0TXBUF = v;
}
uint8_t spiReceiveOctet() {
while (!(UC0IFG & UCB0RXIFG));
uint8_t v = UCB0RXBUF;
return v;
}

17
game-ctrl/spi.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _SPI_H_
#define _SPI_H_
#include <stdint.h>
typedef enum { e_SPI_CANVAS, e_SPI_DISPLAY, e_SPI_SOUND, e_SPI_EEPROM } t_SpiDeviceSelector;
void spiInit();
void spiSendBegin(t_SpiDeviceSelector d);
void spiSendEnd(t_SpiDeviceSelector d);
void spiSendOctet(uint8_t v);
uint8_t spiReceiveOctet();
#endif // _SPI_H_

View File

@ -1,16 +0,0 @@
#include <msp430g2553.h>
#include "time.h"
#include "PontCoopScheduler.h"
void __attribute__ ((interrupt (TIMER0_A0_VECTOR))) ta0_isr() {
schUpdate();
}
void timeInit() {
TACCR0 = 32;
TACCTL0 = CCIE;
TACTL = MC_1 | ID_0 | TASSEL_1 | TACLR;
}

View File

@ -1,10 +0,0 @@
#ifndef TIME_H_
#define TIME_H_
#include <stdint.h>
void timeInit();
#endif /* TIME_H_ */

60
readme.md Normal file
View File

@ -0,0 +1,60 @@
# Tetris - Hardware and Software
![](./docs/IMG_4936.jpg)
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.
Further documentation including calculations and drawing can be found in the `docs` subdirs of the four main subdirs.
## Game Play
Code is in subdir `game-ctrl` (https://gitea.hottis.de/wn/tetris/src/branch/main/game-ctrl).
In the firmware for this MSP430 microcontroller the whole game mechanics, reading the buttons, reading and writing the highscore EEPROM and the control of the peripherial microcontrollers are implemented.
The buttons are debounced using RC circuitry and Schmitt triggers and connected to GPIOs of the microcontroller.
The peripherial microcontrollers and the EEPROM are connected via SPI including individual chip select lines.
![](./docs/game-ctrl.jpg)
## Play Ground Canvas
Code is in subdir `rgb-driver` (https://gitea.hottis.de/wn/tetris/src/branch/main/rgb-driver).
The play ground is implemented using a 10 * 20 matrix of PL9823 RGB LEDs which are controlled by another MSP430 microcontroller. The firmware for this microcontroller is implemented for performance and real time requirements in assembly code. Through some discret logic the signals for PL9823 LEDs are generated. Major challenge was to generated the signals according the datasheet of all 200 (including a mini canvas for the stone preview: 212) LEDs in real time without interrupts.
The communcation with the game play controller is implemented as a sequences of tuples of LED address (0 to 211) and color code. A single octet of 253 where the LED address is expected is taken as the end-of-telegram mark. Readiness to receive a telegram is signaled to the game play controller via a single line connected to a GPIO of the game play controller.
![](./docs/rgb-driver.jpg)
## Score Display
Code is in subdir `display-driver` (https://gitea.hottis.de/wn/tetris/src/branch/main/display-driver).
In the first place, a MAX7221 was meant to be used for connecting a multiple digit seven-segment display. However, it appears, that the MAX7221 requires 3.5V as minimum voltage for the high-level, which caan't be provided by the MSP430 (which runs on 3.3V) and level-shifters haven't been around. Thus, the minimal required amount of functionality of the MAX7221 has been implemented in C on an MSP430. Just four digits are supported.
Communication with the game play controller is just a 16 bit number to be displayed.
![](./docs/display-driver.jpg)
## Sound Effects
Code is in subdir `sound-driver` (https://gitea.hottis.de/wn/tetris/src/branch/main/sound-driver).
An MSP430 microcontroller and two mediaeval AY-3-8913 sound chips are deployed. The sound chips themselve run on 5V, their 8-bit-address/data bus is connected to the port 2 (bit 0 to 7) of the microcontroller. The bus control signal `_CS`, `BC1` and `BDIR` are generated in software and provided via GPIOs.
An amplifier following the proposal of the AY-3-8913 datasheet is implemented using a LM386 chip. A MOSFET BS108 controlled via a GPIO is use the shortcut the input of the amplifier to ground to mute sound effects.
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.
![](./docs/sound-driver-1.jpg)
![](./docs/sound-driver-2.jpg)
![](./docs/sound-driver-3.jpg)
![](./docs/sound-driver-4.jpg)

View File

@ -4,7 +4,8 @@ OBJDUMP=$(TOOLCHAIN_PREFIX)/bin/msp430-elf-objdump
MCU=msp430g2553
ARTIFACT=firmware
COMMON=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -Os -g0 -fdata-sections -ffunction-sections -ggdb -gdwarf-2
COMMON=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -Os -g0 -fdata-sections -ffunction-sections
#COMMON+= -ggdb -gdwarf-2 # debug
CFLAGS=$(COMMON)
ASFLAGS=$(COMMON) -D__ASSEMBLER__

10
rgb-driver/canvasSize.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _CANVAS_SIZE_H_
#define _CANVAS_SIZE_H_
#define CANVAS_WIDTH 10
#define CANVAS_HEIGHT 20
#define MINI_CANVAS_WIDTH 3
#define MINI_CANVAS_HEIGHT 4
#endif // _CANVAS_SIZE_H_

View File

@ -1,5 +1,7 @@
#include <msp430g2553.h>
#include "colors.h"
#include "canvasSize.h"
#define PC r0
#define SP r1
@ -59,13 +61,11 @@
.section ".data"
screendata:
.rept 110 ;; number of leds in hardward
.rept (CANVAS_HEIGHT*CANVAS_WIDTH) + (MINI_CANVAS_HEIGHT*MINI_CANVAS_WIDTH) ;; number of leds in hardward
.byte 0
.endr
screendataend:
.byte 0xff
data_forward_pointer:
.word 0
;; .text is the name of the section, it is a hint for the linker to
@ -96,11 +96,12 @@ init:
;; BIT3: Signal waiting for data
mov.b #BIT0|BIT1|BIT2|BIT3, &P1DIR
mov.b #0,&P1OUT
;; BIT4: spi, UCB0STE
;; BIT5: spi, UCB0CLK
;; BIT6: spi, UCB0SOMI
;; BIT7: spi, UCB0SIMO
mov.b #BIT5|BIT6|BIT7, &P1SEL
mov.b #BIT5|BIT6|BIT7, &P1SEL2
mov.b #BIT4|BIT5|BIT6|BIT7, &P1SEL
mov.b #BIT4|BIT5|BIT6|BIT7, &P1SEL2
;; BIT4: long pulse
;; BIT1: short pulse
mov.b #BIT1|BIT4,&P2DIR
@ -121,8 +122,8 @@ init:
mov.w #OUTMOD_7,&TA1CCTL2
;; spi configuration
;; USCI B to slave mode
mov.b #UCSYNC, &UCB0CTL0
;; USCI B to slave mode, enable STE and most significant bit first
mov.b #UCCKPH|UCSYNC|UCMODE_2|UCMSB, &UCB0CTL0
mov.b #0x00, &UCB0CTL1
;; make sure the isr will not immediately start
@ -136,70 +137,20 @@ init:
;; ----------------------------------------------------
mainloop:
call #forwardscreen_init
call #resetscreen
mainloop_draw:
call #drawscreen
;; signal waiting for data
set_signal_waiting_for_data
;call #forwardscreen
;call #wait
call #receivedata
;; data has been received, clear signal
clear_signal_waiting_for_data
jmp mainloop_draw
;; ----------------------------------------------------
wait:
push r11
push r12
mov.w #0x0040, r11
wait_continue_1:
mov.w #0xffff, r12
wait_continue_2:
dec.w r12
jnz wait_continue_2
dec.w r11
jnz wait_continue_1
pop r12
pop r11
ret
;; ----------------------------------------------------
forwardscreen_init:
mov.w #screendata, &data_forward_pointer
ret
;; ----------------------------------------------------
forwardscreen:
push r8
push r10
mov.w #screendataend, r8
mov.w data_forward_pointer, r10
mov.b #_off, @r10
inc.w r10
mov.b #_blue, @r10
cmp.w r10, r8
jnz forwardscreen_done
mov.w #screendata, r10
forwardscreen_done:
mov.w r10, data_forward_pointer
pop r10
pop r8
ret
;; ----------------------------------------------------
resetscreen:
push r7
@ -231,11 +182,6 @@ receivedata_wait_for_control_octet:
;; get control or address octet from buffer register
mov.b UCB0RXBUF, r9
;; check whether value == 0xff (wait for the whole
;; set of data to fill the screendata)
cmp.b #0xff, r9
;; receive all data
jz receivedata_wait_for_all_data
;; check whether value == 0xfe (no more data)
cmp.b #0xfe, r9
;; no more data
@ -253,10 +199,6 @@ receivedata_wait_for_octet:
;; next address/control octet
jmp receivedata_wait_for_control_octet
receivedata_wait_for_all_data:
;; this is a bit dangerous, if the application controller
;; sends too few data, we are in a dead lock
receivedata_end:
pop r10
pop r9

37
sound-driver/Makefile Normal file
View File

@ -0,0 +1,37 @@
TOOLCHAIN_PREFIX=/opt/msp430-gcc
CC=$(TOOLCHAIN_PREFIX)/bin/msp430-elf-gcc
OBJDUMP=$(TOOLCHAIN_PREFIX)/bin/msp430-elf-objdump
ARTIFACT=firmware
MCU=msp430g2553
COMMONFLAGS=-Wall -mmcu=$(MCU) -I $(TOOLCHAIN_PREFIX)/include -g0 -fdata-sections -ffunction-sections
DEBUGFLAGS=
# DEBUGFLAGS+= -g3 -ggdb -gdwarf-2
CFLAGS=$(COMMONFLAGS) -std=gnu99 -O0 $(DEBUGFLAGS)
ASFLAGS=$(COMMONFLAGS) -D__ASSEMBLER__ -Os $(DEBUGFLAGS)
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include -Wl,-Map,firmware.map
$(ARTIFACT).elf: main.o scheduler.o spi.o spi_init.o sequencer.o melody_tetris.o melody_tusch1.o psg.o mute.o melody_pling.o
$(CC) -o $@ $(LDFLAGS) $^
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt
.c.o:
$(CC) $(CFLAGS) -c $<
.S.o:
$(CC) $(ASFLAGS) -c $<
.PHONY: all
all: $(ARTIFACT).elf
.PHONY: clean
clean:
-rm -f *.o $(ARTIFACT).elf $(ARTIFACT).txt
.PHONY: upload
upload: $(ARTIFACT).elf
mspdebug rf2500 "prog $(ARTIFACT).elf"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

BIN
sound-driver/docs/Oktavskala.pdf Executable file

Binary file not shown.

BIN
sound-driver/docs/Registers.pdf Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
target remote localhost:2000
file firmware.elf

35
sound-driver/main.c Normal file
View File

@ -0,0 +1,35 @@
#include <msp430g2553.h>
#include <stdint.h>
#include <stdlib.h>
#include "spi.h"
#include "psg.h"
#include "scheduler.h"
#include "sequencer.h"
#include "mute.h"
int main() {
WDTCTL = WDTPW | WDTHOLD;
__disable_interrupt();
// highest possible system clock
DCOCTL = DCO0 | DCO1 | DCO2;
BCSCTL1 = XT2OFF | RSEL0 | RSEL1 | RSEL2 | RSEL3;
BCSCTL2 = 0;
BCSCTL3 = 0;
schInit();
spiInit();
psgInit();
muteInit();
sequencerInit();
__enable_interrupt();
while (1) {
schExec();
}
}

View File

@ -0,0 +1,30 @@
#include <stdbool.h>
#include <stddef.h>
#include "psg.h"
#include "sequencer.h"
#include "scheduler.h"
const t_tone plingVoice1[] = {
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
{ .octave = e_O_5, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = true },
{ .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_EndMark, .legato = false, .staccato = false },
};
t_melodies pling = {
.melodies = { { .amplitude = 12, .tones = plingVoice1 } },
.chip = 1,
.numOfMelodies = 1,
.pace = 200,
.slotMask = 0x02
};
void playPling() {
sequencerPlayMelodies(&pling);
}

View File

@ -0,0 +1,8 @@
#ifndef _MELODY_PLING_H_
#define _MELODY_PLING_H_
void playPling();
#endif // _MELODY_PLING_H_

View File

@ -0,0 +1,948 @@
#include <stdbool.h>
#include <stddef.h>
#include "psg.h"
#include "sequencer.h"
#include "scheduler.h"
/*
* three voices theme from https://www.gamemusicthemes.com/sheetmusic/gameboy/tetris/themea/Tetris_-_Theme_A_by_Gori_Fater.pdf
*/
const t_tone voice1[] = {
// -------
// 1. bar
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_E, .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_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 2. bar
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .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_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 3. bar
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = true, .staccato = false }, // diese und die naechste zusammen: ein punktiertes Viertel
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 4. bar
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 5. bar
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 6. bar
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = true, .staccato = false }, // punktiert
{ .octave = e_O_5, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .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_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 7. bar
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 8. bar
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 1. bar, repeat
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_E, .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_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 2. bar, repeat
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .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_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 3. bar, repeat
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = true, .staccato = false }, // diese und die naechste zusammen: ein punktiertes Viertel
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 4. bar, repeat
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 5. bar, repeat
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 6. bar, repeat
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = true, .staccato = false }, // punktiert
{ .octave = e_O_5, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .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_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 7. bar, repeat
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 8. bar, repeat
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 9. bar
{ .octave = e_O_4, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 10. bar
{ .octave = e_O_4, .note = e_D, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 11. bar
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 12. bar
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 13. bar
{ .octave = e_O_4, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 14. bar
{ .octave = e_O_4, .note = e_D, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 15. bar
{ .octave = e_O_4, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 16. bar
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 9. bar, repeat
{ .octave = e_O_4, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 10. bar, repeat
{ .octave = e_O_4, .note = e_D, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 11. bar, repeat
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 12. bar, repeat
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 13. bar, repeat
{ .octave = e_O_4, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 14. bar, repeat
{ .octave = e_O_4, .note = e_D, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 15. bar, repeat
{ .octave = e_O_4, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 16. bar, repeat
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1, .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_EndMark, .legato = false, .staccato = false },
};
const t_tone voice2[] = {
// -------
// 1. bar
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .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_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 2. bar
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 3. bar
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 4. bar
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 5. bar
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 6. bar
{ .octave = e_O_4, .note = e_G, .length = e_L_1_4, .legato = true, .staccato = false }, // punktiert
{ .octave = e_O_4, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_G, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .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 },
// 7. bar
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 8. bar
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 1. bar, repeat
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .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_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 2. bar, repeat
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 3. bar, repeat
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 4. bar, repeat
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 5. bar, repeat
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 6. bar, repeat
{ .octave = e_O_4, .note = e_G, .length = e_L_1_4, .legato = true, .staccato = false }, // punktiert
{ .octave = e_O_4, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_G, .length = e_L_1_16, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .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 },
// 7. bar, repeat
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 8. bar, repeat
{ .octave = e_O_4, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 9. bar
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 10. bar
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 11. bar
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 12. bar
{ .octave = e_O_3, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 13. bar
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 14. bar
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 15. bar
{ .octave = e_O_3, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 16. bar
{ .octave = e_O_3, .note = e_E, .length = e_L_1, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 9. bar, repeat
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 10. bar, repeat
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 11. bar, repeat
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 12. bar, repeat
{ .octave = e_O_3, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 13. bar, repeat
{ .octave = e_O_4, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 14. bar, repeat
{ .octave = e_O_3, .note = e_H, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 15. bar, repeat
{ .octave = e_O_3, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 16. bar, repeat
{ .octave = e_O_3, .note = e_E, .length = e_L_1, .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_EndMark, .legato = false, .staccato = false },
};
const t_tone voice3[] = {
// -------
// 1. bar
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 2. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 3. bar
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 4. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 5. bar
{ .octave = e_O_3, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 6. bar
{ .octave = e_O_2, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 7. bar
{ .octave = e_O_2, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 8. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 1. bar,repeat
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 2. bar,repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 3. bar,repeat
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 4. bar,repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 5. bar,repeat
{ .octave = e_O_3, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_D, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_F, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 6. bar,repeat
{ .octave = e_O_2, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_C, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_G, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 7. bar,repeat
{ .octave = e_O_2, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_H, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// 8. bar,repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
// -------
// 9. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 10. bar
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 11. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 12. bar
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 13. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 14. bar
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 15. bar
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 16. bar
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// -------
// 9. bar, repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 10. bar, repeat
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 11. bar, repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 12. bar, repeat
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 13. bar, repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 14. bar, repeat
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 15. bar, repeat
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_A, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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 },
// 16. bar, repeat
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_2, .note = e_Gis, .length = e_L_1_8, .legato = false, .staccato = false },
{ .octave = e_O_3, .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_EndMark, .legato = false, .staccato = false },
};
t_melodies tetrisTheme = {
.melodies = { { .amplitude = 8, .tones = voice1 }, { .amplitude = 8, .tones = voice2 }, { .amplitude = 8, .tones = voice3 } },
.chip = 0,
.numOfMelodies = 3,
.pace = 160,
.slotMask = 0x01
};
void playMelodyTetris() {
tetrisTheme.pace = 160; // reset to start value each time
sequencerPlayMelodies(&tetrisTheme);
}
void playMelodyTetrisFaster() {
tetrisTheme.pace += 10;
sequencerChangePace(&tetrisTheme);
}
void stopMelodyTetris() {
sequencerStopMelodies(&tetrisTheme);
}

View File

@ -0,0 +1,9 @@
#ifndef _MELODY_TETRIS_H_
#define _MELODY_TETRIS_H_
void playMelodyTetris();
void stopMelodyTetris();
void playMelodyTetrisFaster();
#endif // _MELODY_TETRIS_H_

View File

@ -0,0 +1,87 @@
#include <stdbool.h>
#include <stddef.h>
#include "psg.h"
#include "sequencer.h"
#include "scheduler.h"
#include "melody_tetris.h"
const t_tone tusch1voice1[] = {
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .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_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .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_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
{ .octave = e_O_5, .note = e_F, .length = e_L_1_2, .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_EndMark, .legato = false, .staccato = false },
};
const t_tone tusch1voice2[] = {
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .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_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .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_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_5, .note = e_C, .length = e_L_1_2, .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 tusch1voice3[] = {
{ .octave = e_O_Null, .note = e_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .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_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .legato = false, .staccato = false },
{ .octave = e_O_Null, .note = e_Pause, .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_Pause, .length = e_L_1_4, .legato = false, .staccato = false },
{ .octave = e_O_4, .note = e_A, .length = e_L_1_2, .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 tusch1 = {
.melodies = { { .amplitude = 12, .tones = tusch1voice1 }, { .amplitude = 12, .tones = tusch1voice2 }, { .amplitude = 12, .tones = tusch1voice3 } },
.chip = 1,
.numOfMelodies = 3,
.pace = 200,
.slotMask = 0x02
};
void playTusch1() {
sequencerPlayMelodies(&tusch1);
}

View File

@ -0,0 +1,8 @@
#ifndef _MELODY_TUSCH1_H_
#define _MELODY_TUSCH1_H_
void playTusch1();
#endif // _MELODY_TUSCH1_H_

22
sound-driver/mute.c Normal file
View File

@ -0,0 +1,22 @@
#include <msp430g2553.h>
#include "mute.h"
void muteInit() {
// BIT6: MuteCtrl
P1DIR |= BIT6;
// initially, mute
P1OUT |= BIT6;
}
void mute() {
P1OUT |= BIT6;
}
void unMute() {
P1OUT &= ~BIT6;
}

8
sound-driver/mute.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _MUTE_H_
#define _MUTE_H_
void muteInit();
void mute();
void unMute();
#endif // _MUTE_H_

195
sound-driver/psg.c Normal file
View File

@ -0,0 +1,195 @@
#include <msp430g2553.h>
#include <stdint.h>
#include <stdlib.h>
#include "psg.h"
#include "scheduler.h"
const uint16_t frequencyCodes[8][12] = {
// C, Cis, D, Dis, E, F, Fis, G, Gis, A, Ais, H
{ 06535, 06234, 05747, 05474, 05233, 05002, 04563, 04353, 04153, 03762, 03600, 03424 }, // Octave 1
{ 03256, 03116, 02764, 02636, 02515, 02401, 02271, 02165, 02065, 01771, 01700, 01612 }, // Octave 2
{ 01527, 01447, 01372, 01317, 01247, 01201, 01135, 01073, 01033, 00774, 00740, 00705 }, // Octave 3
{ 00654, 00624, 00575, 00550, 00523, 00500, 00456, 00435, 00415, 00376, 00360, 00342 }, // Octave 4
{ 00326, 00312, 00276, 00264, 00252, 00240, 00227, 00217, 00207, 00177, 00170, 00161 }, // Octave 5
{ 00153, 00145, 00137, 00132, 00125, 00120, 00114, 00107, 00103, 00100, 00074, 00071 }, // Octave 6
{ 00065, 00062, 00060, 00055, 00052, 00050, 00046, 00044, 00042, 00040, 00036, 00034 }, // Octave 7
{ 00033, 00031, 00030, 00026, 00025, 00024, 00023, 00022, 00021, 00020, 00017, 00016 } // Octave 8
};
#define ADDR_DATA_REG P2OUT
#define BUS_CTRL_REG P1OUT
#define BC1 BIT3
#define BDIR BIT1
#define _CS0 BIT2
#define _CS1 BIT0
#define R0 0
#define CHANNEL_A_TONE_PERIOD_FINE_REG R0
#define R1 1
#define CHANNEL_A_TONE_PERIOD_COARSE_REG R1
#define R2 2
#define CHANNEL_B_TONE_PERIOD_FINE_REG R2
#define R3 3
#define CHANNEL_B_TONE_PERIOD_COARSE_REG R3
#define R4 4
#define CHANNEL_C_TONE_PERIOD_FINE_REG R4
#define R5 5
#define CHANNEL_C_TONE_PERIOD_COARSE_REG R5
#define R6 6
#define NOISE_PERIOD_REG R6
#define R7 7
#define _ENABLE_REG R7
#define R10 010
#define CHANNEL_A_AMPLITUDE_REG R10
#define R11 011
#define CHANNEL_B_AMPLITUDE_REG R11
#define R12 012
#define CHANNEL_C_AMPLITUDE_REG R12
#define R13 013
#define ENVELOPE_PERIOD_FINE_REG R13
#define R14 014
#define ENVELOPE_PERIOD_COARSE_REG R13
#define R15 015
#define ENVELOPE_SHAPE_REG R15
uint8_t psgShadowRegisters[2][14];
inline static void BUS_OP_NACT() {
BUS_CTRL_REG &= ~(BDIR | BC1);
}
inline static void BUS_OP_INTAK() {
BUS_CTRL_REG |= BDIR | BC1;
}
inline static void BUS_OP_DWS() {
BUS_CTRL_REG |= BDIR;
BUS_CTRL_REG &= ~BC1;
}
inline static void BUS_OP_CS0_ENABLE() {
BUS_CTRL_REG &= ~_CS0;
}
inline static void BUS_OP_CS0_DISABLE() {
BUS_CTRL_REG |= _CS0;
}
inline static void BUS_OP_CS1_ENABLE() {
BUS_CTRL_REG &= ~_CS1;
}
inline static void BUS_OP_CS1_DISABLE() {
BUS_CTRL_REG |= _CS1;
}
#if 0
static void delay() {
asm volatile (
"push r12\n"
"mov.w #5, r12\n"
"loop:\n"
"dec.w r12\n"
"jnz loop\n"
"pop r12\n"
);
}
#endif
static uint8_t psgReadShadow(uint8_t chip, uint8_t address) {
return psgShadowRegisters[chip][address];
}
static void psgWrite(uint8_t chip, uint8_t address, uint8_t data) {
psgShadowRegisters[chip][address] = data;
// according to "State Timing" (p. 15) of datasheet
if (chip == 0) {
BUS_OP_CS0_ENABLE();
} else {
BUS_OP_CS1_ENABLE();
}
// put bus into inactive state
BUS_OP_NACT();
// put address on bus
ADDR_DATA_REG = address;
// address latch mode
BUS_OP_INTAK();
// latch address
BUS_OP_NACT();
// put data on bus
ADDR_DATA_REG = data;
// set write to psg
BUS_OP_DWS();
// set inactive again
BUS_OP_NACT();
if (chip == 0) {
BUS_OP_CS0_DISABLE();
} else {
BUS_OP_CS1_DISABLE();
}
}
static void psgWriteFrequency(uint8_t chip, uint8_t channel, uint16_t frequencyCode) {
psgWrite(chip, CHANNEL_A_TONE_PERIOD_FINE_REG + (channel * 2), (frequencyCode & 0x00ff));
psgWrite(chip, CHANNEL_A_TONE_PERIOD_COARSE_REG + (channel * 2), ((frequencyCode >> 8) & 0x000f));
}
void psgPlayTone(uint8_t chip, uint8_t channel, uint8_t volume, t_octave octave, t_note note) {
if (note == e_Pause) {
psgWrite(chip, _ENABLE_REG, psgReadShadow(chip, _ENABLE_REG) | (1 << channel));
} else {
psgWrite(chip, _ENABLE_REG, psgReadShadow(chip, _ENABLE_REG) & ~(1 << channel));
psgAmplitude(chip, channel, volume);
psgWriteFrequency(chip, channel, frequencyCodes[octave][note]);
}
}
void psgAmplitude(uint8_t chip, uint8_t channel, uint8_t volume) {
psgWrite(chip, CHANNEL_A_AMPLITUDE_REG + channel, volume);
}
void psgInit() {
// address/data bus
P2DIR = 0xff;
P2SEL = 0;
P2SEL2 = 0;
// bus control lines
// BIT3: BC1
// BIT1: BDIR
// BIT0: _CS1
// BIT2: _CS0
P1DIR |= BIT0 | BIT1 | BIT2 | BIT3 ;
// put bus into inactive state
BUS_CTRL_REG &= ~(BDIR | BC1);
// disable everything
psgWrite(0, _ENABLE_REG, 0xff);
psgWrite(1, _ENABLE_REG, 0xff);
// volume to 0 on all channels
psgWrite(0, CHANNEL_A_AMPLITUDE_REG, 0);
psgWrite(0, CHANNEL_B_AMPLITUDE_REG, 0);
psgWrite(0, CHANNEL_C_AMPLITUDE_REG, 0);
psgWrite(1, CHANNEL_A_AMPLITUDE_REG, 0);
psgWrite(1, CHANNEL_B_AMPLITUDE_REG, 0);
psgWrite(1, CHANNEL_C_AMPLITUDE_REG, 0);
// frequency preset
psgWriteFrequency(0, 0, 0);
psgWriteFrequency(0, 1, 0);
psgWriteFrequency(0, 2, 0);
psgWriteFrequency(1, 0, 0);
psgWriteFrequency(1, 1, 0);
psgWriteFrequency(1, 2, 0);
}

46
sound-driver/psg.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _PSG_H_
#define _PSG_H_
#include <stdint.h>
typedef enum {
e_O_1 = 0,
e_O_2,
e_O_3,
e_O_4,
e_O_5,
e_O_6,
e_O_7,
e_O_8,
e_O_Null
} t_octave;
typedef enum {
e_C = 0,
e_Cis,
e_D,
e_Dis,
e_E,
e_F,
e_Fis,
e_G,
e_Gis,
e_A,
e_Ais,
e_H,
e_Pause,
e_Null
} t_note;
#define e_Es e_Dis
#define e_As e_Gis
#define e_B e_Ais
void psgInit();
void psgPlayTone(uint8_t chip, uint8_t channel, uint8_t volume, t_octave octave, t_note note);
void psgAmplitude(uint8_t chip, uint8_t channel, uint8_t volume);
#endif // _PSG_H_

View File

@ -1,21 +1,15 @@
/*
* PontCoopScheduler.c
*
* Created on: 29.08.2016
* Author: wn
*/
#include <stdlib.h>
#include <msp430g2553.h>
#include "PontCoopScheduler.h"
#include "scheduler.h"
tTask tasks[MAX_NUM_OF_TASKS];
void schInit() {
TACCR0 = 19600;
TACCTL0 = CCIE;
TACTL = MC_1 | ID_0 | TASSEL_2 | TACLR;
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
tasks[i].delay = 0;
tasks[i].period = 0;
@ -25,7 +19,21 @@ void schInit() {
}
}
void schAdd(void (*exec)(void *), void *handle, uint32_t delay, uint32_t period) {
void __attribute__ ((interrupt (TIMER0_A0_VECTOR))) schUpdate() {
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
if (tasks[i].exec != NULL) {
if (tasks[i].delay == 0) {
tasks[i].delay = tasks[i].period;
tasks[i].run++;
} else {
tasks[i].delay--;
}
}
}
}
uint16_t schAdd(void (*exec)(void *), void *handle, uint32_t delay, uint32_t period) {
uint16_t taskId = 0xffff;
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
if (tasks[i].exec == NULL) {
tasks[i].delay = delay;
@ -37,9 +45,11 @@ void schAdd(void (*exec)(void *), void *handle, uint32_t delay, uint32_t period)
}
tasks[i].exec = exec;
tasks[i].handle = handle;
taskId = i;
break;
}
}
return taskId;
}
/*
@ -52,6 +62,9 @@ void schDel(void (*exec)(void *), void *handle) {
}
}
*/
void schDel(uint16_t taskId) {
tasks[taskId].exec = NULL;
}
void schExec() {
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
@ -75,16 +88,3 @@ void schExec() {
}
void schUpdate() {
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
if (tasks[i].exec != NULL) {
if (tasks[i].delay == 0) {
tasks[i].delay = tasks[i].period;
tasks[i].run++;
} else {
tasks[i].delay--;
}
}
}
}

28
sound-driver/scheduler.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef PONTCOOPSCHEDULER_H_
#define PONTCOOPSCHEDULER_H_
#include <stdint.h>
#define MAX_NUM_OF_TASKS 4
typedef struct {
uint16_t delay;
uint16_t period;
uint8_t run;
void (*exec)(void *handle);
void *handle;
} tTask;
void schInit();
uint16_t schAdd(void (*exec)(void *), void *handle, uint32_t delay, uint32_t period);
// void schDel(void (*exec)(void *), void *handle);
void schDel(uint16_t taskId);
void schExec();
#endif /* PONTCOOPSCHEDULER_H_ */

133
sound-driver/sequencer.c Normal file
View File

@ -0,0 +1,133 @@
#include <stdint.h>
#include <stdbool.h>
#include <sys/param.h>
#include "sequencer.h"
#include "scheduler.h"
#include "psg.h"
uint8_t slots;
void sequencerInit() {
slots = 0;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wreturn-type"
static uint16_t calcLength(t_melodies *m, t_noteLength l) {
switch (l) {
case e_L_1:
return m->quarterLength << 2;
case e_L_1_2:
return m->quarterLength << 1;
case e_L_1_4:
return m->quarterLength;
case e_L_1_8:
return m->quarterLength >> 1;
case e_L_1_16:
return m->quarterLength >> 2;
case e_L_1_32:
return m->quarterLength >> 4;
}
}
#pragma GCC diagnostic pop
void sequencerExec(void *handle) {
t_melodies *melodies = (t_melodies*) handle;
for (uint8_t channel = 0; channel < melodies->numOfMelodies; channel++) {
t_melody *melody = &(melodies->melodies[channel]);
switch (melody->state) {
case e_Init:
melody->state = e_PlayTone;
break;
case e_PlayTone:
if (melody->tones[melody->idx].length == e_L_SyncMark) {
if (melodies->sync == 0) {
melodies->sync = melodies->numOfMelodies;
}
melodies->sync -= 1;
melody->state = e_Sync;
} else if (melody->tones[melody->idx].length == e_L_HoldMark) {
melody->state = e_Hold;
} else if (melody->tones[melody->idx].length == e_L_StopMark) {
melody->state = e_Terminate;
} else {
if (melody->tones[melody->idx].length == e_L_EndMark) {
melody->idx = 0;
}
psgPlayTone(melodies->chip, channel, melody->amplitude, melody->tones[melody->idx].octave, melody->tones[melody->idx].note);
melody->lengthCnt = (melody->tones[melody->idx].staccato) ?
(calcLength(melodies, melody->tones[melody->idx].length) / 2) :
calcLength(melodies, melody->tones[melody->idx].length);
melody->state = e_HoldTone;
}
break;
case e_Sync:
if (melodies->sync == 0) {
melody->state = e_SeparateTone;
}
break;
case e_HoldTone:
melody->lengthCnt -= 1;
if (melody->lengthCnt == 0) {
melody->state = (melody->tones[melody->idx].staccato) ? e_StaccatoBreak : e_SeparateTone;
}
break;
case e_StaccatoBreak:
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
melody->lengthCnt = calcLength(melodies, melody->tones[melody->idx].length) / 2;
melody->state = e_HoldStaccatoBreak;
break;
case e_HoldStaccatoBreak:
melody->lengthCnt -= 1;
if (melody->lengthCnt == 0) {
melody->state = e_SeparateTone;
}
break;
case e_SeparateTone:
if (! (melody->tones[melody->idx].legato)) {
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
}
melody->idx += 1;
melody->state = e_PlayTone;
break;
case e_Hold:
break;
case e_Terminate:
schDel(melodies->taskId);
slots &= ~(melodies->slotMask);
break;
}
}
}
void sequencerPlayMelodies(t_melodies *melodies) {
if ((slots & melodies->slotMask) != 0) {
return;
}
slots |= melodies->slotMask;
for (uint8_t i = 0; i < NUM_OF_CHANNELS; i++) {
melodies->melodies[i].idx = 0;
melodies->melodies[i].lengthCnt = 0;
melodies->melodies[i].state = e_Init;
}
melodies->sync = 0;
melodies->quarterLength = 60000 / melodies->pace / SEQUENCER_PERIOD; // duration of a 1/4 tone in ms
melodies->taskId = schAdd(sequencerExec, (void*) melodies, 0, SEQUENCER_PERIOD);
}
void sequencerStopMelodies(t_melodies *melodies) {
slots &= ~(melodies->slotMask);
schDel(melodies->taskId);
}
void sequencerChangePace(t_melodies *melodies) {
melodies->quarterLength = 60000 / melodies->pace / SEQUENCER_PERIOD; // duration of a 1/4 tone in ms
}

69
sound-driver/sequencer.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef _SEQUENCER_H_
#define _SEQUENCER_H_
#include <stdint.h>
#include <stdbool.h>
#include "psg.h"
typedef enum {
e_L_1 = 0,
e_L_1_2 = 1,
e_L_1_4 = 2,
e_L_1_8 = 3,
e_L_1_16 = 4,
e_L_1_32 = 5,
e_L_LengthEnd = 6,
e_L_HoldMark = 252,
e_L_StopMark = 253,
e_L_EndMark = 254,
e_L_SyncMark = 255,
} t_noteLength;
typedef struct {
t_octave octave;
t_note note;
t_noteLength length;
bool legato;
bool staccato;
} t_tone;
typedef enum {
e_Init,
e_PlayTone,
e_Sync,
e_HoldTone,
e_StaccatoBreak,
e_HoldStaccatoBreak,
e_SeparateTone,
e_Hold,
e_Terminate
} t_sequencerState;
typedef struct {
uint16_t idx;
uint16_t lengthCnt;
t_sequencerState state;
uint8_t amplitude;
const t_tone *tones;
} t_melody;
#define SEQUENCER_PERIOD 4 // ms
#define NUM_OF_CHANNELS 3
typedef struct {
uint8_t chip;
uint8_t slotMask;
uint8_t taskId;
uint16_t quarterLength;
uint8_t numOfMelodies;
uint16_t pace; // quarter notes per minute
uint8_t sync;
t_melody melodies[NUM_OF_CHANNELS];
} t_melodies;
void sequencerInit();
void sequencerPlayMelodies(t_melodies *melodies);
void sequencerStopMelodies(t_melodies *melodies);
void sequencerChangePace(t_melodies *melodies);
#endif // _SEQUENCER_H_

14
sound-driver/soundCodes.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _SOUND_CODES_H_
#define _SOUND_CODES_H_
#define SOUND_IDLE 0x00
#define SOUND_MUTE 0x01
#define SOUND_UNMUTE 0x02
#define SOUND_START 0x04
#define SOUND_GAMEOVER 0x08
#define SOUND_FANFARE 0x10
#define SOUND_LOCK 0x20
#define SOUND_MOTION 0x40
#define SOUND_PLING 0x80
#endif // _SOUND_CODES_H_

67
sound-driver/spi.S Normal file
View File

@ -0,0 +1,67 @@
#include <msp430g2553.h>
#include "soundCodes.h"
;; .global cmd
;; .section .data.spi,"aw"
;;cmd:
;; .byte
.section ".text","ax",@progbits
receive_isr:
bit #UCB0RXIFG, &UC0IFG
jz receive_isr_no_data
bis UCB0RXBUF, &cmd
receive_isr_no_data:
reti
.global spiCmdHandler
spiCmdHandler:
spiCmdHandler_1:
bit #SOUND_MUTE, &cmd
jz spiCmdHandler_2
call #mute
bic #SOUND_MUTE, &cmd
spiCmdHandler_2:
bit #SOUND_UNMUTE, &cmd
jz spiCmdHandler_3
call #unMute
bic #SOUND_UNMUTE, &cmd
spiCmdHandler_3:
bit #SOUND_START, &cmd
jz spiCmdHandler_4
;;call #playMelodyTetris
bic #SOUND_START, &cmd
spiCmdHandler_4:
bit #SOUND_GAMEOVER, &cmd
jz spiCmdHandler_5
;;call #stopMelodyTetris
;; insert a call here
bic #SOUND_GAMEOVER, &cmd
spiCmdHandler_5:
bit #SOUND_FANFARE, &cmd
jz spiCmdHandler_6
;;call #playMelodyTetrisFaster
;;call #playTusch1
bic #SOUND_FANFARE, &cmd
spiCmdHandler_6:
bit #SOUND_LOCK, &cmd
jz spiCmdHandler_7
;; insert a call here
bic #SOUND_LOCK, &cmd
spiCmdHandler_7:
bit #SOUND_MOTION, &cmd
jz spiCmdHandler_8
;; insert a call here
bic #SOUND_MOTION, &cmd
spiCmdHandler_8:
bit #SOUND_PLING, &cmd
jz spiCmdHandler_end
;;call #playPling
bic #SOUND_PLING, &cmd
spiCmdHandler_end:
ret
.section "__interrupt_vector_8","ax",@progbits
.word receive_isr
.end

9
sound-driver/spi.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _SPI_H_
#define _SPI_H_
void spiInit();
void spiCmdHandler();
#endif // _SPI_H_

31
sound-driver/spi_init.c Normal file
View File

@ -0,0 +1,31 @@
#include <stddef.h>
#include <msp430g2553.h>
#include <stdint.h>
#include "scheduler.h"
#include "spi.h"
#include "soundCodes.h"
uint8_t cmd;
void spiInit() {
// SPI slave
// BIT4: UCB0STE
// BIT5: UCB0CLK
// BIT6: UCB0SOMI
// BIT7: UCB0SIMO
P1SEL |= BIT4 | BIT5 | BIT7;
P1SEL2 |= BIT4 | BIT5 | BIT7;
// most significant bit first, enable STE
UCB0CTL0 = UCCKPH | UCSYNC | UCMSB | UCMODE_2;
UCB0CTL1 = 0x00;
// enable RX interrupt
UC0IE |= UCB0RXIE;
cmd = SOUND_IDLE;
schAdd(spiCmdHandler, NULL, 0, 100);
}

View File

@ -0,0 +1,64 @@
N = 3579545.0
factor = 1.0594631
base = 440.0
frequencies = []
BEFORE_A = 46
f = base
for i in range (BEFORE_A):
idx = BEFORE_A - i - 1
print(f"{idx}: {f}")
frequencies.append(f)
f = base / factor
base = f
frequencies.reverse()
AFTER_A = 50
base = 440.0
for i in range(AFTER_A):
idx = BEFORE_A + i
f = base * factor
print(f"{idx}: {f}")
frequencies.append(f)
base = f
# print(f"{frequencies}")
codes = []
for i in range(len(frequencies)):
codes.append(round(N / (32.0 * frequencies[i])))
#const uint16_t frequencyCodes[8][12] = {
# // C, Cis, D, Dis, E, F, Fis, G, Gis, A, Ais, H
# { 06535, 06234, 05747, 05474, 05233, 05002, 04563, 04353, 04153, 03762, 03600, 03424 }, // Octave 1
# { 03256, 03116, 02764, 02636, 02515, 02401, 02271, 02165, 02065, 01771, 01700, 01612 }, // Octave 2
# { 01527, 01447, 01372, 01317, 01247, 01201, 01135, 01073, 01033, 00774, 00740, 00705 }, // Octave 3
# { 00654, 00624, 00575, 00550, 00523, 00500, 00456, 00435, 00415, 00376, 00360, 00342 }, // Octave 4
# { 00326, 00312, 00276, 00264, 00252, 00240, 00227, 00217, 00207, 00177, 00170, 00161 }, // Octave 5
# { 00153, 00145, 00137, 00132, 00125, 00120, 00114, 00107, 00103, 00100, 00074, 00071 }, // Octave 6
# { 00065, 00062, 00060, 00055, 00052, 00050, 00046, 00044, 00042, 00040, 00036, 00034 }, // Octave 7
# { 00033, 00031, 00030, 00026, 00025, 00024, 00023, 00022, 00021, 00020, 00017, 00016 } // Octave 8
#};
print("const uint16_t frequencyCodes[8][12] = {")
step = 12
for i in range(len(codes)):
if (i % step == 0):
print(" { ", end='')
print(f"{codes[i]}", end='')
if ((i+1) % step != 0):
print(", ", end='')
if ((i+1) % step == 0):
print(" }", end='')
if ((i+1) != len(codes)):
print(", ")
else:
print()
print("};")