Working on apu
This commit is contained in:
parent
4823aeae93
commit
020feb2a6f
@ -7,6 +7,7 @@ typedef struct {
|
|||||||
bool running;
|
bool running;
|
||||||
bool die;
|
bool die;
|
||||||
u64 ticks;
|
u64 ticks;
|
||||||
|
const char *app_path;
|
||||||
} emu_context;
|
} emu_context;
|
||||||
|
|
||||||
int emu_run(int, char**);
|
int emu_run(int, char**);
|
||||||
|
@ -80,6 +80,8 @@ typedef struct {
|
|||||||
|
|
||||||
bool rendering_window;
|
bool rendering_window;
|
||||||
u32 target_frame_time;
|
u32 target_frame_time;
|
||||||
|
bool paused;
|
||||||
|
bool frame;
|
||||||
} ppu_context;
|
} ppu_context;
|
||||||
|
|
||||||
void ppu_init();
|
void ppu_init();
|
||||||
|
97
lib/audio.c
97
lib/audio.c
@ -1,6 +1,7 @@
|
|||||||
#include <audio.h>
|
#include <audio.h>
|
||||||
|
|
||||||
#include <emu.h>
|
#include <emu.h>
|
||||||
|
#include <ppu.h>
|
||||||
|
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
#include <pa_ringbuffer.h>
|
#include <pa_ringbuffer.h>
|
||||||
@ -22,12 +23,14 @@ static float audio_time = 0;
|
|||||||
static float wave_time = 0;
|
static float wave_time = 0;
|
||||||
static float lfsr_timer = 0;
|
static float lfsr_timer = 0;
|
||||||
static float lfsr_clock = LFSR_BASE_CLOCK;
|
static float lfsr_clock = LFSR_BASE_CLOCK;
|
||||||
|
static float lfsr_clock_buffer = LFSR_BASE_CLOCK;
|
||||||
|
|
||||||
static float left_cap = 0.0f;
|
static float left_cap = 0.0f;
|
||||||
static float right_cap = 0.0f;
|
static float right_cap = 0.0f;
|
||||||
|
|
||||||
static int history_timer = 0;
|
static int history_timer = 0;
|
||||||
const int history_interval = 5;
|
const int history_interval = 5;
|
||||||
|
static int lfsr_clocks = 0;
|
||||||
|
|
||||||
const u8 square_sample_00[8] = {
|
const u8 square_sample_00[8] = {
|
||||||
0x0,
|
0x0,
|
||||||
@ -87,6 +90,11 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
void *userData ) {
|
void *userData ) {
|
||||||
float *out = (float *)output_buffer;
|
float *out = (float *)output_buffer;
|
||||||
for(int i = 0; i < framesPerBuffer; i++) {
|
for(int i = 0; i < framesPerBuffer; i++) {
|
||||||
|
if(ppu_get_context()->paused) {
|
||||||
|
*out++ = 0;
|
||||||
|
*out++ = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
float left = 0;
|
float left = 0;
|
||||||
float right = 0;
|
float right = 0;
|
||||||
audio_time += TIME_PER_SAMPLE;
|
audio_time += TIME_PER_SAMPLE;
|
||||||
@ -118,17 +126,29 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
}
|
}
|
||||||
lfsr_timer += TIME_PER_SAMPLE;
|
lfsr_timer += TIME_PER_SAMPLE;
|
||||||
for(;lfsr_timer >= lfsr_clock;lfsr_timer -= lfsr_clock) {
|
for(;lfsr_timer >= lfsr_clock;lfsr_timer -= lfsr_clock) {
|
||||||
if(ctx.ch4_enable) {
|
//if(ctx.ch4_enable) {
|
||||||
lfsr_timer = 0;
|
lfsr_clocks++;
|
||||||
u8 new = !((ctx.ch4_lfsr & 0b1) ^ ((ctx.ch4_lfsr >> 1) & 0b1)) & 0b1;
|
lfsr_clock = lfsr_clock_buffer;
|
||||||
ctx.ch4_lfsr |= (new << 15);
|
//lfsr_timer = 0;
|
||||||
if(ctx.ch4_lfsr_width) {
|
//u16 new = ~((ctx.ch4_lfsr & 0b1) ^ ((ctx.ch4_lfsr & 0b10) >> 1)) & 0b1;
|
||||||
ctx.ch4_lfsr &= ~(1 << 7);
|
//ctx.ch4_lfsr &= ~(1 << 15);
|
||||||
ctx.ch4_lfsr |= (new << 7);
|
//ctx.ch4_lfsr |= ((new << 15) & 0x8000);
|
||||||
}
|
//printf("new bit: %02X\n", (new << 15));
|
||||||
ctx.ch4_lfsr = ctx.ch4_lfsr >> 1;
|
//if(ctx.ch4_lfsr_width) {
|
||||||
|
// ctx.ch4_lfsr &= ~(1 << 7);
|
||||||
|
// ctx.ch4_lfsr |= (new << 7);
|
||||||
|
//}
|
||||||
|
//ctx.ch4_lfsr = ctx.ch4_lfsr >> 1;
|
||||||
//printf("lfsr: %02X, bit: %d\n", ctx.ch4_lfsr, new);
|
//printf("lfsr: %02X, bit: %d\n", ctx.ch4_lfsr, new);
|
||||||
}
|
unsigned bit_mask = ctx.ch4_lfsr_width ? 0x4040 : 0x4000;
|
||||||
|
bool new_bit = (ctx.ch4_lfsr ^ (ctx.ch4_lfsr >> 1) ^ 1) & 1;
|
||||||
|
ctx.ch4_lfsr >>= 1;
|
||||||
|
if(new_bit) {
|
||||||
|
ctx.ch4_lfsr |= bit_mask;
|
||||||
|
} else {
|
||||||
|
ctx.ch4_lfsr &= ~bit_mask;
|
||||||
|
}
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
float sq1_val = 0;
|
float sq1_val = 0;
|
||||||
float sq2_val = 0;
|
float sq2_val = 0;
|
||||||
@ -206,7 +226,7 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
if(ctx.ch4_dac){
|
if(ctx.ch4_dac){
|
||||||
ch4_val = -1;
|
ch4_val = -1;
|
||||||
if(ctx.ch4_enable) {
|
if(ctx.ch4_enable) {
|
||||||
ch4_val = (ctx.ch4_lfsr & 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f;
|
ch4_val = ((ctx.ch4_lfsr & 0b1) == 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f;
|
||||||
if(ctx.ch4_left) {
|
if(ctx.ch4_left) {
|
||||||
left += ch4_val;
|
left += ch4_val;
|
||||||
//printf("left: %d\n", ctx.ch3_volume);
|
//printf("left: %d\n", ctx.ch3_volume);
|
||||||
@ -248,7 +268,16 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
right_out /= 4;
|
right_out /= 4;
|
||||||
|
|
||||||
if(left_out < -1.0f) {
|
if(left_out < -1.0f) {
|
||||||
printf("Uh Oh! %f\n", left_out);
|
left_out = -1;
|
||||||
|
}
|
||||||
|
if(left_out > 1.0f) {
|
||||||
|
left_out = 1;
|
||||||
|
}
|
||||||
|
if(right_out < -1.0f) {
|
||||||
|
right_out = -1;
|
||||||
|
}
|
||||||
|
if(right_out > 1.0f) {
|
||||||
|
right_out = 1;
|
||||||
}
|
}
|
||||||
history_timer++;
|
history_timer++;
|
||||||
if(history_timer >= history_interval){
|
if(history_timer >= history_interval){
|
||||||
@ -382,6 +411,7 @@ void sq1_sweep() {
|
|||||||
|
|
||||||
static int change = 1;
|
static int change = 1;
|
||||||
static u32 ticks = 0;
|
static u32 ticks = 0;
|
||||||
|
static u32 start, end = 0;
|
||||||
|
|
||||||
void audio_tick(){
|
void audio_tick(){
|
||||||
u32 prev_ticks = ticks;
|
u32 prev_ticks = ticks;
|
||||||
@ -415,7 +445,7 @@ void audio_tick(){
|
|||||||
|
|
||||||
if(ctx.ch4_len_enable && ctx.ch4_enable) {
|
if(ctx.ch4_len_enable && ctx.ch4_enable) {
|
||||||
ctx.ch4_len++;
|
ctx.ch4_len++;
|
||||||
//printf("Ch4 env: %02X\n", ctx.ch4_len);
|
//printf("Ch4 len: %02X\n", ctx.ch4_len);
|
||||||
if(ctx.ch4_len >= 64) {
|
if(ctx.ch4_len >= 64) {
|
||||||
ctx.ch4_len = 0;
|
ctx.ch4_len = 0;
|
||||||
ctx.ch4_enable = false;
|
ctx.ch4_enable = false;
|
||||||
@ -454,19 +484,20 @@ void audio_tick(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ctx.ch4_env_pace != 0){
|
//if(ctx.ch4_env_pace != 0){
|
||||||
ctx.ch4_env_timer++;
|
ctx.ch4_env_timer--;
|
||||||
if(ctx.ch4_env_timer >= ctx.ch4_env_pace) {
|
if(ctx.ch4_env_timer <= 0) {
|
||||||
ctx.ch4_env_timer = 0;
|
ctx.ch4_env_timer = ctx.ch4_env_pace_buffer != 0 ? ctx.ch4_env_pace_buffer : 8;
|
||||||
if((ctx.ch4_env_direction && ctx.ch4_volume != 15) || (!ctx.ch4_env_direction && ctx.ch4_volume != 0)){
|
if(ctx.ch4_env_pace != 0 && ((ctx.ch4_env_direction && ctx.ch4_volume != 15) || (!ctx.ch4_env_direction && ctx.ch4_volume != 0))){
|
||||||
ctx.ch4_volume += ctx.ch4_env_direction ? 1 : -1;
|
ctx.ch4_volume += ctx.ch4_env_direction ? 1 : -1;
|
||||||
if(ctx.ch4_volume < 0)
|
//printf("Noise Vol: %02X\n", ctx.ch4_volume);
|
||||||
ctx.ch4_volume = 0;
|
if(ctx.ch4_volume < 0)
|
||||||
if(ctx.ch4_volume > 15)
|
ctx.ch4_volume = 0;
|
||||||
ctx.ch4_volume = 15;
|
if(ctx.ch4_volume > 15)
|
||||||
}
|
ctx.ch4_volume = 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,12 +559,15 @@ void enable_noise() {
|
|||||||
if(!ctx.ch4_dac){
|
if(!ctx.ch4_dac){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
start = get_ticks();
|
||||||
ctx.ch4_enable = true;
|
ctx.ch4_enable = true;
|
||||||
ctx.ch4_env_timer = 0;
|
ctx.ch4_env_timer = ctx.ch4_env_pace_buffer != 0 ? ctx.ch4_env_pace_buffer : 8;
|
||||||
ctx.ch4_env_direction = ctx.ch4_env_direction_buffer;
|
ctx.ch4_env_direction = ctx.ch4_env_direction_buffer;
|
||||||
ctx.ch4_env_pace = ctx.ch4_env_pace_buffer;
|
ctx.ch4_env_pace = ctx.ch4_env_pace_buffer;
|
||||||
ctx.ch4_volume = ctx.ch4_initial_volume;
|
ctx.ch4_volume = ctx.ch4_initial_volume;
|
||||||
ctx.ch4_lfsr = 0;
|
ctx.ch4_lfsr = 0;
|
||||||
|
lfsr_clock = lfsr_clock_buffer;
|
||||||
|
lfsr_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 audio_read(u16 address) {
|
u8 audio_read(u16 address) {
|
||||||
@ -928,6 +962,7 @@ void audio_write(u16 address, u8 value){
|
|||||||
ctx.ch4_len = ctx.ch4_initial_len;
|
ctx.ch4_len = ctx.ch4_initial_len;
|
||||||
ctx.ch4_len_fz = false;
|
ctx.ch4_len_fz = false;
|
||||||
//printf("ch4 len: %02X\n", ctx.ch4_len);
|
//printf("ch4 len: %02X\n", ctx.ch4_len);
|
||||||
|
printf("Write Ch4 Len: %02X\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(address == 0xFF21) {
|
if(address == 0xFF21) {
|
||||||
@ -940,15 +975,18 @@ void audio_write(u16 address, u8 value){
|
|||||||
} else {
|
} else {
|
||||||
ctx.ch4_dac = true;
|
ctx.ch4_dac = true;
|
||||||
}
|
}
|
||||||
|
printf("Write Ch4 env: %02X\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(address == 0xFF22) {
|
if(address == 0xFF22) {
|
||||||
ctx.ch4_clock_shift = (value >> 4);
|
ctx.ch4_clock_shift = (value >> 4) & 0xF;
|
||||||
ctx.ch4_lfsr_width = (value & 0x08);
|
ctx.ch4_lfsr_width = (value & 0x08);
|
||||||
ctx.ch4_clock_divider = value & 0b111;
|
ctx.ch4_clock_divider = value & 0b111;
|
||||||
float div = (ctx.ch4_clock_divider == 0 ? 0.5f : ctx.ch4_clock_divider);
|
float div = (ctx.ch4_clock_divider == 0 ? 0.5f : (float)ctx.ch4_clock_divider);
|
||||||
float lfsr_rate = (LFSR_BASE_CLOCK) / (div * (1 << ctx.ch4_clock_shift));
|
float lfsr_rate = (LFSR_BASE_CLOCK) / (div * (float)(1 << ctx.ch4_clock_shift));
|
||||||
lfsr_clock = 1.0f / (lfsr_rate/1000.0f/1000.0f);
|
lfsr_clock_buffer = 1.0f / (lfsr_rate/1000.0f/1000.0f);
|
||||||
|
//printf("Ch4 clock: Shift: %01X, Width: %d, Div: %f (%01X), Rate: %f, Clock %f\n", ctx.ch4_clock_shift, ctx.ch4_lfsr_width, div, ctx.ch4_clock_divider, lfsr_rate, lfsr_clock);
|
||||||
|
printf("Write Ch4 Clock: %02X\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(address == 0xFF23) {
|
if(address == 0xFF23) {
|
||||||
@ -975,5 +1013,6 @@ void audio_write(u16 address, u8 value){
|
|||||||
if(value & 0x80) {
|
if(value & 0x80) {
|
||||||
enable_noise();
|
enable_noise();
|
||||||
}
|
}
|
||||||
|
printf("Write Ch4 Trigger: %02X\n", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,7 @@ int emu_run(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("Cart loaded..\n");
|
printf("Cart loaded..\n");
|
||||||
|
ctx.app_path = argv[0];
|
||||||
|
|
||||||
ui_init();
|
ui_init();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -158,6 +158,14 @@ void ppu_mode_hblank() {
|
|||||||
delay((ppu_get_context()->target_frame_time - frame_time));
|
delay((ppu_get_context()->target_frame_time - frame_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while(ppu_get_context()->paused) {
|
||||||
|
delay(10);
|
||||||
|
if(ppu_get_context()->frame){
|
||||||
|
ppu_get_context()->frame = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (end - start_timer >= 1000) {
|
if (end - start_timer >= 1000) {
|
||||||
u32 fps = frame_count;
|
u32 fps = frame_count;
|
||||||
start_timer = end;
|
start_timer = end;
|
||||||
|
@ -39,7 +39,7 @@ void timer_tick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((prev_div & (1 << 13)) && (!(ctx.div & (1 << 13)))){
|
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
|
||||||
audio_tick();
|
audio_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
lib/ui.c
20
lib/ui.c
@ -4,6 +4,7 @@
|
|||||||
#include <gamepad.h>
|
#include <gamepad.h>
|
||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
#include <audio.h>
|
#include <audio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
@ -131,7 +132,11 @@ void ui_update() {
|
|||||||
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
|
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
|
||||||
SDL_RenderClear(sdlRenderer);
|
SDL_RenderClear(sdlRenderer);
|
||||||
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
|
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
|
||||||
TTF_Font* sans = TTF_OpenFont("Sans.ttf", 24);
|
char buffer[1024];
|
||||||
|
strcpy(buffer, emu_get_context()->app_path);
|
||||||
|
*strrchr(buffer, '\\') = 0;
|
||||||
|
strcat(buffer,"/Sans.ttf");
|
||||||
|
TTF_Font* sans = TTF_OpenFont(buffer, 24);
|
||||||
if ( !sans ) {
|
if ( !sans ) {
|
||||||
printf("Failed to load font: %s\n", TTF_GetError());
|
printf("Failed to load font: %s\n", TTF_GetError());
|
||||||
}
|
}
|
||||||
@ -289,6 +294,19 @@ void ui_on_key(bool down, u32 key_code) {
|
|||||||
}
|
}
|
||||||
printf("target frame time: %d\n", ppu_get_context()->target_frame_time);
|
printf("target frame time: %d\n", ppu_get_context()->target_frame_time);
|
||||||
}
|
}
|
||||||
|
if(ppu_get_context()->paused) {
|
||||||
|
if(key_code == SDLK_PERIOD && down == true){
|
||||||
|
ppu_get_context()->frame = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(key_code == SDLK_p && down == true) {
|
||||||
|
ppu_get_context()->paused = !ppu_get_context()->paused;
|
||||||
|
if(ppu_get_context()->paused) {
|
||||||
|
printf("Paused Emulation\n");
|
||||||
|
} else {
|
||||||
|
printf("Resumed Emulation\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
switch(key_code){
|
switch(key_code){
|
||||||
case SDLK_z: gamepad_get_state()->b = down; break;
|
case SDLK_z: gamepad_get_state()->b = down; break;
|
||||||
case SDLK_x: gamepad_get_state()->a = down; break;
|
case SDLK_x: gamepad_get_state()->a = down; break;
|
||||||
|
Loading…
Reference in New Issue
Block a user