PaCo v1.0
This commit is contained in:
6
main.cpp
6
main.cpp
@@ -2,6 +2,7 @@
|
||||
#include <stdio.h>
|
||||
#include "vm.h"
|
||||
#include "vdp.h"
|
||||
#include "sound.h"
|
||||
#include <SDL.h>
|
||||
#include "debug.h"
|
||||
|
||||
@@ -44,6 +45,11 @@ int main(int argc, char** argv) {
|
||||
vm_register_out_port(20, input_data_in);
|
||||
vm_register_in_port(21, input_data_out);
|
||||
|
||||
sound_init();
|
||||
vm_register_out_port(30, sound_data_out);
|
||||
vm_register_out_port(31, sound_cmd_out);
|
||||
vm_register_in_port(32, sound_in);
|
||||
|
||||
debug_init(vm_get_memory());
|
||||
const bool* breakpoints = debug_get_breakpoints();
|
||||
|
||||
|
||||
30
parser.cpp
30
parser.cpp
@@ -747,6 +747,28 @@ static void parse_wait() {
|
||||
emmit(OP_SLEEP);
|
||||
}
|
||||
|
||||
static void parse_setmusic() {
|
||||
parse_expression();
|
||||
parse_concatenation();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_spu_setmusic"));
|
||||
}
|
||||
|
||||
static void parse_playmusic() {
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_spu_playmusic"));
|
||||
}
|
||||
|
||||
static void parse_stopmusic() {
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_spu_stopmusic"));
|
||||
}
|
||||
|
||||
static void parse_ismusicplaying() {
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_spu_ismusicplaying"));
|
||||
}
|
||||
|
||||
|
||||
static void parse_statements() {
|
||||
while (!parser_finished) {
|
||||
@@ -817,6 +839,14 @@ static void parse_statements() {
|
||||
tkn_next(); parse_clrscr(); break;
|
||||
case TOKEN_WAIT:
|
||||
tkn_next(); parse_wait(); break;
|
||||
case TOKEN_SETMUSIC:
|
||||
tkn_next(); parse_setmusic(); break;
|
||||
case TOKEN_PLAYMUSIC:
|
||||
tkn_next(); parse_playmusic(); break;
|
||||
case TOKEN_STOPMUSIC:
|
||||
tkn_next(); parse_stopmusic(); break;
|
||||
case TOKEN_ISMUSICPLAYING:
|
||||
tkn_next(); parse_ismusicplaying(); break;
|
||||
|
||||
case TOKEN_IDENTIFIER:
|
||||
for (int i = 0; i < num_external_functions; i++) {
|
||||
|
||||
214
sound.cpp
Normal file
214
sound.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
#include "sound.h"
|
||||
#include <SDL.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BUFFER_SIZE 512
|
||||
|
||||
static const float lengths[10] = { 0.0f, 0.00390625f, 0.0078125f, 0.015625f, 0.03125f, 0.0625f, 0.125f, 0.25f, 0.5f, 1.0f };
|
||||
// 9 = redona, 8 = blanca, 7 = negra, 6 = corchea, 5 = semicorchea, 4 = fusa, 3 = semifusa, 2 = garrapatea, 1 = semigarrapatea
|
||||
static const Uint16 tempos[10] = { 13230, 8820, 6615, 5292, 4410, 3780, 3308, 2940, 2646, 2406 };
|
||||
static const float periods[108] = { 1348.49207, 1272.80688, 1201.37, 1133.94214, 1070.29871, 1010.22772, 953.527893, 900.010376, 849.496887, 801.818176, 756.815613, 714.338745, 674.246033, 636.403564, 600.684875, 566.971069, 535.149475, 505.11377, 476.763947, 450.005249, 424.748352, 400.909088, 378.407806, 357.169373, 337.123016, 318.201782, 300.342438, 283.485535, 267.574738, 252.556885, 238.381973, 225.002625, 212.374176, 200.454544, 189.203888, 178.584702, 168.561508, 159.100876, 150.171234, 141.742767, 133.787354, 126.278458, 119.190987, 112.501305, 106.187096, 100.227272, 94.6019516, 89.2923508, 84.2807541, 79.5504379, 75.0856171, 70.8713837, 66.8936768, 63.139225, 59.5954933, 56.2506561, 53.0935478, 50.113636, 47.3009758, 44.6461754, 42.140377, 39.775219, 37.5428085, 35.4356918, 33.4468384, 31.5696125, 29.7977467, 28.1253281, 26.5467739, 25.056818, 23.650486, 22.3230877, 21.0701885, 19.8876095, 18.7714043, 17.7178459, 16.7234192, 15.7848072, 14.8988733, 14.0626631, 13.273387, 12.528409, 11.8252439, 11.1615429, 10.5350943, 9.94380569, 9.38570118, 8.85892296, 8.36171055, 7.89240265, 7.44943666, 7.03133202, 6.636693, 6.2642045, 5.91262197, 5.58077145, 5.26754713, 4.97190285, 4.69285059, 4.42946148, 4.18085527, 3.94620132, 3.72471833, 3.51566601, 3.3183465, 3.13210225, 2.95631051, 2.7903862 };
|
||||
|
||||
static class c_channel {
|
||||
private:
|
||||
Uint8 volume{ 64 };
|
||||
Uint8 octave{ 4 };
|
||||
Uint32 tempo{ 44100 };
|
||||
float default_length{ 0.25f };
|
||||
char song[256];
|
||||
Uint8 pos{ 0 };
|
||||
|
||||
Uint32 length{ 0 };
|
||||
Uint16 period{ 0 };
|
||||
bool active{ false };
|
||||
|
||||
void program_pipeline(const char note, const char len, const float multip = 1.0f) {
|
||||
length = (len == -1 ? default_length : lengths[len]) * multip * tempo;
|
||||
period = note == 100 ? 0 : periods[note + octave * 12];
|
||||
}
|
||||
|
||||
bool parse_song() {
|
||||
while (true) {
|
||||
float multip = 1.0f;
|
||||
char note = 0;
|
||||
char param = -1;
|
||||
switch (song[pos++]) {
|
||||
case 'b': note += 2;
|
||||
case 'a': note += 2;
|
||||
case 'g': note += 2;
|
||||
case 'f': note += 1;
|
||||
case 'e': note += 2;
|
||||
case 'd': note += 2;
|
||||
case 'c':
|
||||
param = song[pos];
|
||||
if (param == '#' || param == '+') { note++; param = song[++pos]; } else if (param == '-') { note--; param = song[++pos]; }
|
||||
if (param >= 48 && param <= 57) { param -= 48; pos++; } else { param = -1; }
|
||||
if (song[pos] == '.') { multip = 1.5f; pos++; }
|
||||
program_pipeline(note, param, multip);
|
||||
return true;
|
||||
case 'r':
|
||||
param = song[pos];
|
||||
if (param >= 48 && param <= 57) { param -= 48; pos++; } else { param = -1; }
|
||||
if (song[pos] == '.') { multip = 1.5f; pos++; }
|
||||
program_pipeline(100, param, multip);
|
||||
return true;
|
||||
case 'o':
|
||||
param = song[pos];
|
||||
if (param >= 48 && param <= 57) { octave = (param - 48) % 8; pos++; }
|
||||
break;
|
||||
case '>':
|
||||
octave = (octave + 1) % 8;
|
||||
break;
|
||||
case '<':
|
||||
octave = (octave - 1) % 8;
|
||||
break;
|
||||
case 'l':
|
||||
param = song[pos];
|
||||
if (param >= 48 && param <= 57) { default_length = lengths[param - 48]; pos++; }
|
||||
else if (param == '+') { default_length *= 2; pos++; }
|
||||
else if (param == '-') { default_length /= 2; pos++; }
|
||||
break;
|
||||
case 'v':
|
||||
param = song[pos];
|
||||
if (param >= 48 && param <= 57) { volume = (param - 48) << 4; pos++; }
|
||||
break;
|
||||
case 't':
|
||||
param = song[pos];
|
||||
if (param >= 48 && param <= 57) { tempo = tempos[param - 48] * 10; pos++; }
|
||||
break;
|
||||
case '\0':
|
||||
active = false;
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Sint8 get_datum() {
|
||||
if (!active) return 0;
|
||||
if (length == 0) if (!parse_song()) { active = false; return 0; }
|
||||
length--;
|
||||
return period == 0 ? -128 : ((length % period) < (period >> 1) ? volume : - volume);
|
||||
}
|
||||
/* Uint8 get_datum() {
|
||||
if (!active) return 0;
|
||||
if (length == 0) if (!parse_song()) return 0;
|
||||
length--;
|
||||
return period == 0 ? 0 : ((length % period) < (period >> 1) ? 128 + volume : 128 - volume);
|
||||
}*/
|
||||
Sint8 get_noise() {
|
||||
static Sint8 last_noise;
|
||||
if (!active) return 0;
|
||||
if (length == 0) if (!parse_song()) { active = false; return 0; }
|
||||
length--;
|
||||
if (period == 0) return -128;
|
||||
if ((length % period) < (period >> 1)) { last_noise = rand() % (volume * 2) - volume; }
|
||||
return last_noise;
|
||||
}
|
||||
void set_song(const char* melody) {
|
||||
int len = SDL_strlen(melody);
|
||||
SDL_memcpy(song, melody, len);
|
||||
song[len] = 0;
|
||||
pos = 0; volume = 64; octave = 4; tempo = 44100; default_length = 0.25f;
|
||||
active = true;
|
||||
}
|
||||
bool is_active() {
|
||||
return active;
|
||||
}
|
||||
void stop() {
|
||||
length = 0;
|
||||
period = 0;
|
||||
active = false;
|
||||
}
|
||||
};
|
||||
|
||||
static c_channel channels[4];
|
||||
|
||||
static int sign(int number) { return number > 0 ? 1 : -1; }
|
||||
static bool samesign(int a, int b) { return (a > 0 && b > 0) || (a < 0 && b < 0); }
|
||||
|
||||
static void audio_callback(void* userdata, Uint8* stream, int len) {
|
||||
Uint8 datum = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
//for (auto& channel : channels) datum += channel.get_datum();
|
||||
Sint8 a = channels[0].get_datum();
|
||||
Sint8 b = channels[1].get_datum();
|
||||
Sint8 c = channels[2].get_datum();
|
||||
Sint8 d = channels[3].get_noise();
|
||||
//Sint16 dat = samesign(a,b) ? (a + b) - ((a * b) / sign(a)*127) : a + b;
|
||||
Sint16 dat = a + b + c + d;
|
||||
//Uint16 dat = (a + b) - ((a * b) / 256);
|
||||
if (dat > 127) dat = 127; if (dat < -128) dat = -128;
|
||||
//datum = dat;
|
||||
datum = (dat + 128);
|
||||
*stream = datum;
|
||||
stream++;
|
||||
}
|
||||
//SDL_MixAudio(tstream, channel.pos, actual_len, SDL_MIX_MAXVOLUME);
|
||||
if (!(channels[0].is_active() || channels[1].is_active() || channels[2].is_active() || channels[3].is_active()))
|
||||
SDL_PauseAudio(1);
|
||||
}
|
||||
|
||||
void sound_init() {
|
||||
SDL_Init(SDL_INIT_AUDIO);
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
spec.freq = 22050;
|
||||
spec.format = AUDIO_U8;
|
||||
spec.channels = 1;
|
||||
spec.samples = BUFFER_SIZE;
|
||||
spec.callback = audio_callback;
|
||||
spec.userdata = NULL;
|
||||
|
||||
SDL_OpenAudio(&spec, NULL);
|
||||
SDL_PauseAudio(1);
|
||||
}
|
||||
|
||||
void sound_load(const int channel, const char* string) {
|
||||
channels[channel].set_song(string);
|
||||
}
|
||||
|
||||
void sound_play() {
|
||||
//for (auto& channel : channels) channel.set_active();
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
|
||||
const bool sound_isplaying() {
|
||||
return channels[0].is_active() || channels[1].is_active() || channels[2].is_active() || channels[3].is_active(); // song_ended == 0;
|
||||
}
|
||||
|
||||
static unsigned char in_buffer[256];
|
||||
static unsigned char in_buffer_pos = 0;
|
||||
|
||||
#define CMD_SETMUSIC 0
|
||||
#define CMD_PLAYMUSIC 1
|
||||
#define CMD_STOPMUSIC 2
|
||||
#define CMD_ISMUSICPLAYING 3
|
||||
|
||||
void sound_data_out(const unsigned char& value) {
|
||||
in_buffer[in_buffer_pos++] = value;
|
||||
}
|
||||
|
||||
void sound_cmd_out(const unsigned char& value) {
|
||||
unsigned char channel;
|
||||
char revbuf[256]; char* prb = revbuf;
|
||||
switch (value) {
|
||||
case CMD_SETMUSIC:
|
||||
channel = in_buffer[--in_buffer_pos];
|
||||
while (in_buffer_pos > 0) { *prb++ = in_buffer[--in_buffer_pos]; } *prb = 0;
|
||||
channels[channel].set_song(revbuf);
|
||||
break;
|
||||
case CMD_PLAYMUSIC: sound_play(); break;
|
||||
case CMD_STOPMUSIC: for (auto& channel: channels) channel.stop(); SDL_PauseAudio(1); break;
|
||||
case CMD_ISMUSICPLAYING: in_buffer[0] = channels[0].is_active() || channels[1].is_active() || channels[2].is_active() || channels[3].is_active() ? 1 : 0; break;
|
||||
}
|
||||
in_buffer_pos = 0;
|
||||
}
|
||||
|
||||
unsigned char sound_in() {
|
||||
return in_buffer[0];
|
||||
}
|
||||
10
sound.h
Normal file
10
sound.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
void sound_init();
|
||||
void sound_load(const int channel, const char* string);
|
||||
void sound_play();
|
||||
const bool sound_isplaying();
|
||||
|
||||
void sound_data_out(const unsigned char& value);
|
||||
void sound_cmd_out(const unsigned char& value);
|
||||
unsigned char sound_in();
|
||||
2
test.bas
2
test.bas
@@ -5,6 +5,8 @@
|
||||
LOCATE 4 3 PRINT CHR &h85, CHR &h85, CHR &h85, CHR &h85, CHR &h85, CHR &h85, CHR &h85, CHR &h84
|
||||
LOCATE 4 4 PRINT CHR &h87, CHR &h81, CHR &h8D, CHR &h85, CHR &h85, CHR &h85, CHR &h8D, CHR &h85
|
||||
W = 0
|
||||
SETMUSIC 0 "cdef"
|
||||
PLAYMUSIC
|
||||
MENU_BLINK:
|
||||
LOCATE 3 8 PRINT "PRESS CTRL"
|
||||
LOCATE 4 9 PRINT "TO PLAY"
|
||||
|
||||
@@ -64,6 +64,10 @@ t_token_op tkn_tokens[] = {
|
||||
{ "border", TOKEN_BORDER },
|
||||
{ "cls", TOKEN_CLS },
|
||||
{ "wait", TOKEN_WAIT },
|
||||
{ "setmusic", TOKEN_SETMUSIC },
|
||||
{ "playmusic", TOKEN_PLAYMUSIC },
|
||||
{ "stopmusic", TOKEN_STOPMUSIC },
|
||||
{ "ismusicplaying", TOKEN_ISMUSICPLAYING },
|
||||
};
|
||||
|
||||
static char hex_digit(const char digit) { return digit - (digit <= 57 ? 48 : 55); }
|
||||
|
||||
@@ -69,6 +69,11 @@ enum t_tokentype {
|
||||
TOKEN_BORDER,
|
||||
TOKEN_CLS,
|
||||
TOKEN_WAIT,
|
||||
|
||||
TOKEN_SETMUSIC,
|
||||
TOKEN_PLAYMUSIC,
|
||||
TOKEN_STOPMUSIC,
|
||||
TOKEN_ISMUSICPLAYING,
|
||||
};
|
||||
|
||||
void tkn_init(const char* buffer);
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
<ClCompile Include="error.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="parser.cpp" />
|
||||
<ClCompile Include="sound.cpp" />
|
||||
<ClCompile Include="stack.cpp" />
|
||||
<ClCompile Include="tokenizer.cpp" />
|
||||
<ClCompile Include="vdp.cpp" />
|
||||
@@ -94,6 +95,7 @@
|
||||
<ClInclude Include="error.h" />
|
||||
<ClInclude Include="font.h" />
|
||||
<ClInclude Include="parser.h" />
|
||||
<ClInclude Include="sound.h" />
|
||||
<ClInclude Include="stack.h" />
|
||||
<ClInclude Include="stb_image.h" />
|
||||
<ClInclude Include="tokenizer.h" />
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
<ClCompile Include="debug.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sound.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="vm.h">
|
||||
@@ -71,5 +74,8 @@
|
||||
<ClInclude Include="debug.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sound.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user