Files
ascii/ascii.cpp
T
JailDoctor 65b71361ae - [FIX] Reajustat el buffer de só per a notes llargues, que s'havia fotut en el pas a SDL3
- [NEW] al usar play(), amb "w" es pot canviar de tipus de ona: 0: la quadrada de sempre, 1: sawtooth, 2: roido
- [FIX] Al executar play() de nou no se resetejaven la duració de nota ni el tipus de ona.
2026-05-16 12:42:38 +02:00

764 lines
22 KiB
C++

#include "ascii.h"
#include <stdio.h>
#include <string.h>
#include "lua.h"
#include "rom.h"
#include "play.h"
#include <vector>
#include <string>
#include <SDL3/SDL.h>
#define swap(a, b) {auto tmp=a;a=b;b=tmp;}
#define AUDIO_NONE 0
#define AUDIO_SOUND 1
#define AUDIO_PLAY 2
uint8_t audio_state = AUDIO_NONE;
int audio_freq = 0;
uint32_t audio_len = 0;
SDL_AudioDeviceID mini_audio_device;
SDL_AudioStream* audio_stream;
uint8_t mix_buffer[4096]; // tamaño configurable
int play_len = 0;
uint8_t* play_pos = nullptr;
uint8_t play_buffer[132300];
char lua_filename[1024];
char window_title[256];
uint8_t mem[8192]; //2400
uint8_t *char_screen = NULL;
uint8_t *color_screen = NULL;
uint8_t screen_width = 40;
uint8_t screen_height = 30;
int v_screen_w = 640;
int v_screen_h = 480;
uint8_t hborder = 40;
uint8_t vborder = 40;
uint8_t current_color = 0x1e;
uint8_t current_border = 0;
uint8_t current_mode = 1;
uint8_t cursor_x = 0;
uint8_t cursor_y = 0;
#define CHRSCR(x, y) char_screen[x+y*screen_width]
#define COLSCR(x, y) color_screen[x+y*screen_width]
#define MEM_CHAR_OFFSET 2560
#define MEM_BOOT_OFFSET 4608
SDL_Window *mini_win;
SDL_Renderer *mini_ren;
SDL_Texture *mini_bak = NULL;
Uint32 *pixels;
int pitch;
Uint32 counter=0;
uint32_t palette[16] = { 0xFF000000, 0xFF0000AA, 0xFF00AA00, 0xFF00AAAA, 0xFFAA0000, 0xFFAA00AA, 0xFFAA5500, 0xFFAAAAAA,
0xFF555555, 0xFF5555FF, 0xFF55FF55, 0xFF55FFFF, 0xFFFF5555, 0xFFFF55FF, 0xFFFFFF55, 0xFFFFFFFF };
int debug_prompt = -1;
int debug_cursor_blink = 30;
std::vector<std::string> cmd_list;
bool should_reset = false;
const bool *keys;
Uint8 key_just_pressed = 0;
int mouse_x, mouse_y, mouse_wheel;
Uint32 mouse_buttons;
const char* get_filename() {
return lua_filename;
}
void reinit() {
if (mini_bak != NULL) SDL_DestroyTexture(mini_bak);
counter=0;
hborder = vborder = 40;
v_screen_w = 640; v_screen_h = 480;
switch (current_mode) {
case 0:
screen_width = 80;
screen_height = 30;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
color_screen = &mem[1200];
//SDL_RenderSetLogicalSize(mini_ren, 640, 480);
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 640, 240);
break;
case 1:
screen_width = 40;
screen_height = 30;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
color_screen = &mem[1200];
//SDL_RenderSetLogicalSize(mini_ren, 320, 240);
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 240);
break;
case 2:
screen_width = 20;
screen_height = 15;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
color_screen = &mem[300];
//SDL_RenderSetLogicalSize(mini_ren, 160, 120);
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 160, 120);
break;
case 3:
hborder = 104;
vborder = 88;
v_screen_w = 512;
v_screen_h = 384;
screen_width = 32;
screen_height = 24;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
color_screen = &mem[768];
//SDL_RenderSetLogicalSize(mini_ren, 640, 480);
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 256, 192);
break;
case 4:
screen_width = 80;
screen_height = 30;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
color_screen = &mem[0x1200];
//SDL_RenderSetLogicalSize(mini_ren, 640, 480);
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 640, 240);
break;
}
SDL_SetTextureScaleMode(mini_bak, SDL_SCALEMODE_NEAREST);
}
void pump_audio() {
if (audio_state == AUDIO_NONE) return;
const int TARGET_MS = 20;
const int BYTES_PER_MS = 22; // 44100 Hz, 8-bit mono
const int TARGET_BYTES = TARGET_MS * BYTES_PER_MS;
const int CHUNK = 256; // bloque pequeño y constante
int queued = SDL_GetAudioStreamAvailable(audio_stream);
while (queued < TARGET_BYTES) {
int to_generate = CHUNK;
uint8_t* out = mix_buffer;
int remaining = to_generate;
while (remaining > 0) {
if (audio_state == AUDIO_SOUND) {
static int period = 0;
static int v = 16;
for (int i = 0; i < remaining; ++i) {
out[i] = v;
period++;
if (period >= audio_freq) {
period = 0;
v = -v;
}
}
remaining = 0;
}
else if (audio_state == AUDIO_PLAY) {
while (play_len == 0) {
play_len = interpret_next_token(play_buffer);
if (play_len == -1) {
audio_state = AUDIO_NONE;
return;
}
play_pos = play_buffer;
}
int n = (remaining < play_len ? remaining : play_len);
SDL_memcpy(out, play_pos, n);
out += n;
play_pos += n;
play_len -= n;
remaining -= n;
}
}
SDL_PutAudioStreamData(audio_stream, mix_buffer, to_generate);
queued += to_generate;
}
}
void romcpy() {
SDL_memcpy(&mem[2560], rom, rom_size);
}
void debug_set_prompt();
int main(int argc,char*argv[]) {
SDL_strlcpy(lua_filename, "game.lua", 9);
if (argc > 1) SDL_strlcpy(lua_filename, argv[1], 1023);
//[TODEL]for (int i=0; i<debug_total_size;++i) debug_text[i] = 32;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS);
mini_win = SDL_CreateWindow(window_title, 640+80, 480+80, 0);
mini_ren = SDL_CreateRenderer(mini_win, NULL);
SDL_SetRenderVSync(mini_ren, 1);
bool exit = false;
SDL_Event mini_eve;
SDL_AudioSpec spec = {};
spec.freq = 22050;
spec.format = SDL_AUDIO_S8;
spec.channels = 1;
mini_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec);
audio_stream = SDL_CreateAudioStream(&spec, &spec);
SDL_BindAudioStream(mini_audio_device, audio_stream);
SDL_ResumeAudioDevice(mini_audio_device);
romcpy();
reinit();
debug("ASCII SYSTEM BOOTING...");
lua_init(NULL);
lua_call_init();
SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, true);
while(!exit) {
if (should_reset) {
should_reset = false;
mode(1);
reinit();
lua_init(lua_filename);
lua_call_init();
}
pump_audio();
key_just_pressed = 0;
mouse_wheel = 0;
while(SDL_PollEvent(&mini_eve)) {
if (mini_eve.type == SDL_EVENT_QUIT) { exit=true; break; }
if (mini_eve.type == SDL_EVENT_DROP_FILE) {
const char* dropped_filedir = mini_eve.drop.data;
load(dropped_filedir);
}
if (mini_eve.type == SDL_EVENT_KEY_DOWN) {
if (mini_eve.key.scancode == SDL_SCANCODE_ESCAPE) {
if (lua_is_playing()) {
lua_pause();
//lua_quit();
debug_set_prompt();
//old_mode = current_mode;
//setmode(0);
} else {
//setmode(old_mode);
lua_resume();
//lua_quit();
//reinit();
//lua_init(lua_filename);
//lua_call_init();
}
} else if (mini_eve.key.scancode == SDL_SCANCODE_F5) {
execute_run();
lua_quit();
reinit();
lua_init(lua_filename);
lua_call_init();
} else {
key_just_pressed = mini_eve.key.scancode;
}
}
if (mini_eve.type == SDL_EVENT_MOUSE_WHEEL) {
mouse_wheel = mini_eve.wheel.y;
}
}
keys = SDL_GetKeyboardState(NULL);
float mx, my;
mouse_buttons = SDL_GetMouseState(&mx, &my);
if (mx>=hborder && my>=vborder && mx<(v_screen_w+hborder) && my<(v_screen_h+vborder)) {
mouse_x = (mx-hborder) / (v_screen_w/screen_width);
mouse_y = (my-vborder) / (v_screen_h/screen_height);
}
if (lua_is_playing()) {
lua_call_update();
if (!lua_is_playing()) debug_set_prompt();
} else {
debug_cursor_blink--;
if (debug_cursor_blink == 0) {
debug_cursor_blink = 60;
//const int pos = cursor_x+cursor_y*screen_width;
//char_screen[pos] = char_screen[pos]==32 ? 95 : 32;
}
loop();
}
SDL_LockTexture(mini_bak, NULL, (void**)&pixels, &pitch);
switch (current_mode) {
case 0:
for (int y=0; y<screen_height; ++y) {
for (int x=0; x<screen_width; ++x) {
uint8_t chr_color = current_color; //COLSCR(x,y);
if ((debug_cursor_blink<30)&&(cursor_x==x)&&(cursor_y==y)) {
chr_color = (chr_color>>4)+((chr_color&0x0f)<<4);
}
const uint32_t ink_color = palette[chr_color & 0x0f];
const uint32_t paper_color = palette[chr_color >> 4];
const uint8_t chr = CHRSCR(x,y);
for (int l=0; l<8; ++l) {
const uint8_t line = mem[MEM_CHAR_OFFSET+chr*8+l];
for (int b=0; b<8; ++b) {
if ((line >> (7-b)) & 0x01) {
pixels[b+(x*8)+((y*8)+l)*(screen_width*8)] = ink_color;
} else {
pixels[b+(x*8)+((y*8)+l)*(screen_width*8)] = paper_color;
}
}
}
}
}
break;
case 1:
case 2:
case 3:
case 4:
for (int y=0; y<screen_height; ++y) {
for (int x=0; x<screen_width; ++x) {
uint8_t chr_color = COLSCR(x,y);
if ((debug_cursor_blink<30)&&(cursor_x==x)&&(cursor_y==y)) {
chr_color = (chr_color>>4)+((chr_color&0x0f)<<4);
}
const uint32_t ink_color = palette[chr_color & 0x0f];
const uint32_t paper_color = palette[chr_color >> 4];
const uint8_t chr = CHRSCR(x,y);
for (int l=0; l<8; ++l) {
const uint8_t line = mem[MEM_CHAR_OFFSET+chr*8+l];
for (int b=0; b<8; ++b) {
if ((line >> (7-b)) & 0x01) {
pixels[b+(x*8)+((y*8)+l)*(screen_width*8)] = ink_color;
} else {
pixels[b+(x*8)+((y*8)+l)*(screen_width*8)] = paper_color;
}
}
}
}
}
break;
}
//for (int i=0;i<screen_surface->size;++i) pixels[i] = palette[screen_surface->p[i]];
SDL_UnlockTexture(mini_bak);
SDL_SetRenderDrawColor(mini_ren, (palette[current_border] >> 16)&0xff, (palette[current_border] >> 8)&0xff, palette[current_border]&0xff, 0);
//SDL_SetRenderDrawColor(mini_ren, 255, 0, 0, 0);
SDL_RenderClear(mini_ren);
SDL_FRect rect = {(float)hborder, (float)vborder, (float)v_screen_w, (float)v_screen_h};
SDL_RenderTexture(mini_ren, mini_bak, NULL, &rect);
//SDL_RenderCopy(mini_ren, mini_bak, NULL, NULL);
SDL_RenderPresent(mini_ren);
counter++;
}
lua_quit();
SDL_Quit();
return 0;
}
void cls(uint8_t value) {
SDL_memset(char_screen, value, screen_width*screen_height);
if (current_mode != 0) SDL_memset(color_screen, current_color, screen_width*screen_height);
cursor_x = cursor_y = 0;
//if (!lua_is_playing()) {
// debug_set_prompt()
//}
}
void ink(uint8_t value) {
current_color = (current_color & 0xf0) + (value & 0x0f);
}
void paper(uint8_t value) {
current_color = (current_color & 0x0f) + (value << 4);
}
void border(uint8_t value) {
current_border = value & 0xf;
}
void color(uint8_t ink, uint8_t paper, int8_t border) {
current_color = (ink & 0x0f) + (paper << 4);
if (border >= 0) current_border = border & 0xf;
}
void locate(uint8_t x, uint8_t y) {
cursor_x = min(x, screen_width-1);
cursor_y = min(y, screen_height-1);
}
void print(const char *str, int x, int y) {
if (x >= 0) cursor_x = min(x, screen_width-1);
if (y >= 0) cursor_y = min(y, screen_height-1);
int len = SDL_strlen(str);
const int pos = cursor_x+cursor_y*screen_width;
if (pos+len > screen_width*screen_height) len -= ((pos+len) - screen_width*screen_height);
//int offset = x+y*screen_width;
for (int i=0; i < len; ++i) {
char_screen[pos+i] = str[i];
if (current_mode != 0) color_screen[pos+i] = current_color;
//char_screen[offset+i] = str[i];
//if (current_mode != 0) color_screen[offset+i] = current_color;
}
cursor_x = (pos+len)%screen_width;
cursor_y = (pos+len)/screen_width;
}
void crlf() {
cursor_x=0;
cursor_y = min(cursor_y+1, screen_height-1);
}
bool btn(uint8_t i) {
return keys[i];
}
bool btnp(uint8_t i) {
return key_just_pressed == i;
}
uint8_t whichbtn() {
return key_just_pressed;
}
int mousex() {
return mouse_x;
}
int mousey() {
return mouse_y;
}
int mousewheel() {
return mouse_wheel;
}
bool mousebutton(uint8_t i) {
return mouse_buttons & SDL_BUTTON_MASK(i);
}
int time() {
return SDL_GetTicks();
}
/*float abs(float x) {
return SDL_fabsf(x);
}*/
float flr(float x) {
return SDL_floorf(x);
}
float sgn(float x) {
return x >= 0 ? 1 : -1;
}
//#ifndef __LINUX__
//#ifndef __APPLE__
//
//float ceil(float x) {
// return SDL_ceilf(x);
//}
//
//float sin(float x) {
// return SDL_sinf(x);
//}
//
//float cos(float x) {
// return SDL_cosf(x);
//}
//
//float atan2(float dx, float dy) {
// return SDL_atan2f(dx, dy);
//}
//
//float sqrt(float x) {
// return SDL_sqrtf(x);
//}
//
//#endif
//#endif
float max(float x, float y) {
return SDL_max(x, y);
}
float mid(float x, float y, float z) {
return max(x, min(y, z));
}
float min(float x, float y) {
return SDL_min(x, y);
}
int rnd(int x) {
return rand()%x;
}
/*void srand(int x) {
srand(x);
}*/
char str_tmp[1024];
const char* tostr(float val) {
return SDL_itoa(val, str_tmp, 10);
}
void debug_one_line_up() {
int total = screen_width*screen_height-screen_width;
for (int i=0; i<total;++i) char_screen[i] = char_screen[i+screen_width];
for (int i=total; i<screen_width*screen_height;++i) char_screen[i] = 32;
cursor_y = screen_height-1;
//debug_set_prompt();
}
void debug_set_prompt() {
if (debug_prompt == cursor_x+cursor_y*screen_width) return;
if (cursor_x>0) { cursor_x=0;cursor_y++;if(cursor_y>=screen_height) debug_one_line_up(); }
char_screen[cursor_x+cursor_y*screen_width] = '>';
cursor_x++;
debug_prompt = cursor_x+cursor_y*screen_width;
}
void debugchr(const uint8_t chr) {
int pos = cursor_x+cursor_y*screen_width;
if (chr == 8) {
if (cursor_x>1) {
char_screen[pos++] = 32;
char_screen[pos] = 32;
cursor_x--;
} else {
play("c");
}
} else {
char_screen[pos] = chr;
cursor_x++;
if (cursor_x >= screen_width) {
cursor_x=0; cursor_y++;
if (cursor_y >= screen_height) debug_one_line_up();
}
}
}
void debug(const char *str, const bool newline) {
const int len = SDL_strlen(str);
int cursor = cursor_x+cursor_y*screen_width;
for (int i=0; i<len;++i) {
char_screen[cursor++] = str[i];
if (cursor >= screen_width*screen_height) debug_one_line_up();
}
if (newline) {
cursor_x = 0;
cursor_y = (cursor/screen_width)+1;
if (cursor_y >= screen_height) debug_one_line_up();
} else {
cursor_x = cursor%screen_width;
cursor_y = cursor/screen_width;
}
//debug_set_prompt();
}
/*[TODEL]
void pdebug() {
int i=0;
for (int y=0; y<debug_num_lines;++y) {
for (int x=0; x<debug_line_size;++x) {
CHRSCR(x, y) = debug_text[i++];
//COLSCR(x, y) = 0x1e;
}
}
}
*/
unsigned int cmd_index = 0;
void debug_get_cmd() {
char_screen[cursor_x+cursor_y*screen_width] = 0;
//char *tmp = (char*)&char_screen[1+cursor_y*screen_width];
char *tmp = (char*)&char_screen[debug_prompt];
cmd_list.push_back(tmp);
char_screen[cursor_x+cursor_y*screen_width] = 32;
cursor_x=0;cursor_y++;if(cursor_y>=screen_height)debug_one_line_up();
cmd_index=0;
const char* cmd = cmd_list[cmd_list.size()-1].c_str();
if (cmd[0]=='r' && cmd[1]=='u' && cmd[2]=='n' && cmd[3]=='\0') {
lua_quit();
reinit();
lua_init(lua_filename);
lua_call_init();
} else if (cmd[0]=='c' && cmd[1]=='o' && cmd[2]=='n' && cmd[3]=='t' && cmd[4]=='\0') {
lua_resume();
} else {
lua_call_cmd(cmd);
debug_set_prompt();
}
}
void get_cmd_by_index() {
if (cmd_list.size() == 0) return;
const char* cmd = cmd_list[cmd_list.size()-cmd_index-1].c_str();
int pos = cursor_x+cursor_y*screen_width;
for (int i=debug_prompt;i<=pos;++i) char_screen[i] = 32;
SDL_memcpy(&char_screen[debug_prompt], cmd, strlen(cmd));
pos = debug_prompt+strlen(cmd);
cursor_x = pos%screen_width;
cursor_y = pos/screen_width;
}
void next_cmd() {
if (cmd_index < cmd_list.size()-1) cmd_index++; else play("c");
get_cmd_by_index();
}
void prev_cmd() {
if (cmd_index > 0) cmd_index--; else play("c");
get_cmd_by_index();
}
void debug_set_cursor(uint8_t x, uint8_t y) {
cursor_x = x;
cursor_y = y;
}
uint8_t ascii(const char *str, uint8_t index) {
return str[index];
}
char chr_trans[2] = "X";
const char* chr(uint8_t ascii) {
uint8_t* peiv = (uint8_t*)chr_trans;
*peiv = ascii;
return chr_trans;
}
const char* substr(const char* str, uint8_t start, uint8_t length) {
memcpy(str_tmp, &str[start], length);
str_tmp[length] = '\0';
return str_tmp;
}
void setchar(uint8_t index, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7) {
mem[MEM_CHAR_OFFSET+index*8] = b0;
mem[MEM_CHAR_OFFSET+index*8+1] = b1;
mem[MEM_CHAR_OFFSET+index*8+2] = b2;
mem[MEM_CHAR_OFFSET+index*8+3] = b3;
mem[MEM_CHAR_OFFSET+index*8+4] = b4;
mem[MEM_CHAR_OFFSET+index*8+5] = b5;
mem[MEM_CHAR_OFFSET+index*8+6] = b6;
mem[MEM_CHAR_OFFSET+index*8+7] = b7;
}
uint8_t peek(uint16_t addr) {
if (addr >= 0x2000) return 0;
return mem[addr];
}
void poke(uint16_t addr, uint8_t val) {
if (addr >= 0x2000) return;
mem[addr] = val;
}
void memcpy(uint16_t dst, uint16_t src, uint16_t size) {
if ((dst<=src) && (dst+size>=src)) return;
if ((dst>=src) && (src+size>=dst)) return;
SDL_memcpy(&mem[dst], &mem[src], size);
}
void sound(float freq, uint32_t len) {
// [TODO]
audio_len = len*44.1f;
audio_freq = 22050.0f/freq/2.0f;
audio_state = AUDIO_SOUND;
}
void nosound() {
//SDL_PauseAudioDevice(mini_audio_device, 1);
audio_len = 0;
audio_state = AUDIO_NONE;
}
void play(const char* str) {
play_pos = play_buffer;
play_len = 0;
play_init(str);
audio_state = AUDIO_PLAY;
}
void mode(const uint8_t val) {
current_mode = val;
reinit();
cls();
}
void load(const char* str) {
if (str!=NULL) SDL_strlcpy(lua_filename, str, SDL_strlen(str)+1);
should_reset = true;
}
void fileout(const char* str, uint16_t addr, uint16_t size) {
FILE* f = fopen(str, "wb");
fwrite(&mem[addr], size, 1, f);
fclose(f);
}
void filein(const char* str, uint16_t addr, uint16_t size) {
FILE* f = fopen(str, "rb");
fread(&mem[addr], size, 1, f);
fclose(f);
}
void toclipboard(const char* str) {
SDL_SetClipboardText(str);
}
const char* fromclipboard() {
char* text = SDL_GetClipboardText();
int len = strlen(text);
if (len > 1023) {
len = 27;
SDL_memcpy(str_tmp, "ERROR! CLIPBOARD TOO LARGE", len);
} else {
SDL_memcpy(str_tmp, text, len);
}
str_tmp[len] = '\0';
SDL_free((void*)text);
return str_tmp;
}
uint32_t cnt() {
return counter;
}
void rst() {
counter = 0;
}