basic audio stream.
This commit is contained in:
parent
36a428bcea
commit
e0fc6123fc
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -8,3 +8,6 @@
|
|||||||
[submodule "deps/SDL_ttf"]
|
[submodule "deps/SDL_ttf"]
|
||||||
path = deps/SDL_ttf
|
path = deps/SDL_ttf
|
||||||
url = https://github.com/libsdl-org/SDL_ttf.git
|
url = https://github.com/libsdl-org/SDL_ttf.git
|
||||||
|
[submodule "deps/portaudio"]
|
||||||
|
path = deps/portaudio
|
||||||
|
url = https://github.com/PortAudio/portaudio.git
|
||||||
|
@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
add_subdirectory(deps/SDL)
|
add_subdirectory(deps/SDL)
|
||||||
add_subdirectory(deps/SDL_ttf)
|
add_subdirectory(deps/SDL_ttf)
|
||||||
|
add_subdirectory(deps/portaudio)
|
||||||
add_subdirectory(lib/)
|
add_subdirectory(lib/)
|
||||||
add_subdirectory(gbemu/)
|
add_subdirectory(gbemu/)
|
||||||
add_subdirectory(deps/check/)
|
add_subdirectory(deps/check/)
|
||||||
|
1
deps/portaudio
vendored
Submodule
1
deps/portaudio
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit aa1cfb046f93b18db4d12986ddbff84cbaa952cb
|
14
include/audio.h
Normal file
14
include/audio.h
Normal 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();
|
@ -2,5 +2,5 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
project(Lib)
|
project(Lib)
|
||||||
file(GLOB SRCS *.c)
|
file(GLOB SRCS *.c)
|
||||||
add_library(Lib STATIC ${SRCS})
|
add_library(Lib STATIC ${SRCS})
|
||||||
target_include_directories(Lib PUBLIC ../include ../deps/SDL/include ../deps/SDL_ttf)
|
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)
|
target_link_libraries(Lib SDL2-static SDL2_ttf::SDL2_ttf-static portaudio)
|
119
lib/audio.c
Normal file
119
lib/audio.c
Normal 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));
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
#include <dma.h>
|
#include <dma.h>
|
||||||
#include <ppu.h>
|
#include <ppu.h>
|
||||||
|
#include <audio.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -25,6 +26,7 @@ DWORD WINAPI cpu_run(void *p) {
|
|||||||
ppu_init();
|
ppu_init();
|
||||||
timer_init();
|
timer_init();
|
||||||
cpu_init();
|
cpu_init();
|
||||||
|
audio_init();
|
||||||
|
|
||||||
ctx.running = true;
|
ctx.running = true;
|
||||||
ctx.paused = false;
|
ctx.paused = false;
|
||||||
|
@ -260,7 +260,6 @@ void pipeline_push_pixel() {
|
|||||||
ppu_get_context()->rendering_window = true;
|
ppu_get_context()->rendering_window = true;
|
||||||
pipeline_fifo_reset();
|
pipeline_fifo_reset();
|
||||||
ppu_get_context()->pfc.cur_fetch_state = FS_TILE;
|
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.fetch_x = 0;
|
||||||
ppu_get_context()->pfc.fifo_x = 0;
|
ppu_get_context()->pfc.fifo_x = 0;
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user