basic audio stream.

This commit is contained in:
Samuel Walker 2025-02-01 23:58:55 -07:00
parent 36a428bcea
commit e0fc6123fc
Signed by: piwalker
GPG Key ID: 616B1928705EA4C9
8 changed files with 142 additions and 3 deletions

3
.gitmodules vendored
View File

@ -8,3 +8,6 @@
[submodule "deps/SDL_ttf"]
path = deps/SDL_ttf
url = https://github.com/libsdl-org/SDL_ttf.git
[submodule "deps/portaudio"]
path = deps/portaudio
url = https://github.com/PortAudio/portaudio.git

View File

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10)
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(deps/SDL)
add_subdirectory(deps/SDL_ttf)
add_subdirectory(deps/portaudio)
add_subdirectory(lib/)
add_subdirectory(gbemu/)
add_subdirectory(deps/check/)

1
deps/portaudio vendored Submodule

@ -0,0 +1 @@
Subproject commit aa1cfb046f93b18db4d12986ddbff84cbaa952cb

14
include/audio.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <common.h>
typedef struct {
float sq1_freq;
float sq1_duty;
float sq1_amp;
float sq2_freq;
float sq2_duty;
float sq2_amp;
} audio_context;
void audio_init();

View File

@ -2,5 +2,5 @@ cmake_minimum_required(VERSION 3.10)
project(Lib)
file(GLOB SRCS *.c)
add_library(Lib STATIC ${SRCS})
target_include_directories(Lib PUBLIC ../include ../deps/SDL/include ../deps/SDL_ttf)
target_link_libraries(Lib SDL2-static SDL2_ttf::SDL2_ttf-static)
target_include_directories(Lib PUBLIC ../include ../deps/SDL/include ../deps/SDL_ttf ../deps/portaudio/include)
target_link_libraries(Lib SDL2-static SDL2_ttf::SDL2_ttf-static portaudio)

119
lib/audio.c Normal file
View File

@ -0,0 +1,119 @@
#include <audio.h>
#include <math.h>
#include <portaudio.h>
#define SAMPLE_RATE 44100
#define FRAMES_PER_BUFFER 64
#define TABLE_SIZE 44100
#define M_PI 3.14159265
static float sine[TABLE_SIZE];
static unsigned long ind = 0;
static unsigned long ind2 = 0;
static int sq1_on_time;
static int sq1_off_time;
static float sq1 = 1;
static int sq1_timer = 0;
static int sq2_on_time;
static int sq2_off_time;
static float sq2 = 1;
static int sq2_timer = 0;
static audio_context ctx;
static int audio_callback(const void* input_uffer, void *output_buffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *time_info,
PaStreamCallbackFlags status_flags,
void *userData ) {
//printf("Audio Callback!\n");
audio_context *ctx = (audio_context *) userData;
float *out = (float *)output_buffer;
PaTime time = time_info->currentTime;
sq1_on_time = 1/(ctx->sq1_freq/(float)SAMPLE_RATE) * ctx->sq1_duty;
sq1_off_time = 1/(ctx->sq1_freq/(float)SAMPLE_RATE) * (1 - ctx->sq1_duty);
sq2_on_time = 1/(ctx->sq2_freq/(float)SAMPLE_RATE) * ctx->sq2_duty;
sq2_off_time = 1/(ctx->sq2_freq/(float)SAMPLE_RATE) * (1 - ctx->sq2_duty);
for(int i = 0; i < framesPerBuffer; i++) {
float val = 0;
//handle audio channels
//val += 0.2 * sine[ind];
//ind += 500;
if((sq1_timer >= sq1_on_time && sq1 == 1)) {
sq1 = 0;
sq1_timer = 0;
} else if((sq1_timer >= sq1_off_time && sq1 == 0)){
sq1 = 1;
sq1_timer = 0;
}
sq1_timer++;
val += ctx->sq1_amp * sq1;
if((sq2_timer >= sq2_on_time && sq2 == 1)) {
sq2 = 0;
sq2_timer = 0;
} else if((sq2_timer >= sq2_off_time && sq2 == 0)){
sq2 = 1;
sq2_timer = 0;
}
sq2_timer++;
val += ctx->sq2_amp * sq2;
//val += 0.2 * sine[ind2];
//ind2 += 200;
if(ind >= TABLE_SIZE) ind -= TABLE_SIZE;
if(ind2 >= TABLE_SIZE) ind2 -= TABLE_SIZE;
*out++ = val;
}
return paContinue;
}
void audio_init(){
PaStreamParameters output_parameters;
PaStream *stream;
PaError err;
ctx.sq1_amp = 0;
ctx.sq1_duty = 0;
ctx.sq1_freq = 0;
ctx.sq2_amp = 0;
ctx.sq2_duty = 0;
ctx.sq2_freq = 0;
for(int i = 0; i < TABLE_SIZE; i++) {
sine[i] = (float) sin(((double)i/(double)TABLE_SIZE) * M_PI * 2.);
}
err = Pa_Initialize();
if (err != paNoError) goto error;
output_parameters.device = Pa_GetDefaultOutputDevice();
if(output_parameters.device == paNoDevice) {
fprintf(stderr, "No default audio device!\n");
goto error;
}
output_parameters.channelCount = 1;
output_parameters.sampleFormat = paFloat32;
output_parameters.suggestedLatency = Pa_GetDeviceInfo(output_parameters.device)->defaultLowOutputLatency;
output_parameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(&stream,
NULL,
&output_parameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
NULL,
audio_callback,
&ctx);
if(err != paNoError) goto error;
err = Pa_StartStream(stream);
if(err != paNoError) goto error;
return;
error:
Pa_Terminate();
fprintf(stderr, "portaudio stream error\n\tError Number: %d\n\tError Message: %s\n", err, Pa_GetErrorText(err));
}

View File

@ -6,6 +6,7 @@
#include <timer.h>
#include <dma.h>
#include <ppu.h>
#include <audio.h>
#ifdef _WIN32
#include <windows.h>
@ -25,6 +26,7 @@ DWORD WINAPI cpu_run(void *p) {
ppu_init();
timer_init();
cpu_init();
audio_init();
ctx.running = true;
ctx.paused = false;

View File

@ -260,7 +260,6 @@ void pipeline_push_pixel() {
ppu_get_context()->rendering_window = true;
pipeline_fifo_reset();
ppu_get_context()->pfc.cur_fetch_state = FS_TILE;
printf("Window X: %d\n", lcd_get_context()->win_x);
ppu_get_context()->pfc.fetch_x = 0;
ppu_get_context()->pfc.fifo_x = 0;
return;