You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
5.6 KiB
202 lines
5.6 KiB
/* |
|
* Dreamroq by Mike Melanson |
|
* Updated by Josh Pearson to add audio support |
|
* |
|
* This is the sample Dreamcast player app, designed to be run under |
|
* the KallistiOS operating system. |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
|
|
#include <dc/maple.h> |
|
#include <dc/maple/controller.h> |
|
#include <kos/mutex.h> |
|
#include <kos/thread.h> |
|
|
|
#include "dreamroqlib.h" |
|
|
|
#include "pvr_driver.h" |
|
#include "snddrv.h" |
|
|
|
/* Audio Global variables */ |
|
#define PCM_BUF_SIZE 1024*1024 |
|
static unsigned char *pcm_buf = NULL; |
|
static int pcm_size = 0; |
|
static int audio_init = 0; |
|
static mutex_t * pcm_mut; |
|
static long samples_done = 0; |
|
|
|
/* Video Global variables */ |
|
static int graphics_initialized = 0; |
|
static int frame=0; |
|
static kthread_t * render_thread; /* Video thread */ |
|
static volatile int render_thd = 0; /* Video thread status */ |
|
static const float VIDEO_RATE = 30.0f; /* Video FPS */ |
|
|
|
/* PVR Driver Handle */ |
|
static struct pvr_frame roq_vram_ptr; |
|
static struct pvr_frame_vertex roq_vram_vertex; |
|
|
|
static float ATS = 0, VTS = 0; /* A/V Timestamps For Synchronization */ |
|
|
|
/* This is called by the AICA Sound Driver when it needs more samples */ |
|
void *audio_drv_cb ( snd_stream_hnd_t hnd, int pcm_needed, int * pcm_done ) |
|
{ |
|
/* Wait for RoQ Decoder to produce enough samples */ |
|
while( pcm_size < pcm_needed ) |
|
thd_pass(); |
|
|
|
/* Copy the Requested PCM Samples to the AICA Driver */ |
|
mutex_lock( pcm_mut ); |
|
memcpy( snddrv.pcm_buffer, pcm_buf, pcm_needed ); |
|
pcm_size -= pcm_needed; |
|
memmove( pcm_buf, pcm_buf+pcm_needed, pcm_size ); |
|
mutex_unlock( pcm_mut ); |
|
|
|
samples_done += pcm_needed; /* Record the Audio Time Stamp */ |
|
ATS = (samples_done/(double)snddrv.rate)/((double)snddrv.channels*2.0); |
|
|
|
snddrv.pcm_ptr = snddrv.pcm_buffer; |
|
*pcm_done = pcm_needed; |
|
|
|
return snddrv.pcm_ptr; /* Return the requested samples to the AICA driver */ |
|
} |
|
|
|
static int audio_cb( unsigned char *buf, int size, int channels) |
|
{ |
|
if(!audio_init) |
|
{ |
|
/* allocate PCM buffer */ |
|
pcm_buf = malloc(PCM_BUF_SIZE); |
|
if( pcm_buf == NULL ) |
|
return ROQ_NO_MEMORY; |
|
|
|
/* Start AICA Driver */ |
|
snddrv_start_cb( 22050, channels, audio_drv_cb ); |
|
snddrv.dec_status = SNDDEC_STATUS_STREAMING; |
|
|
|
/* Create a mutex to handle the double-threaded buffer */ |
|
mutex_init(pcm_mut, MUTEX_TYPE_NORMAL); |
|
|
|
|
|
audio_init=1; |
|
} |
|
|
|
/* Copy the decoded PCM samples to our local PCM buffer */ |
|
mutex_lock( pcm_mut ); |
|
memcpy(pcm_buf+pcm_size, buf, size); |
|
pcm_size += size; |
|
mutex_unlock( pcm_mut ); |
|
|
|
return ROQ_SUCCESS; |
|
} |
|
|
|
static void *video_thd(void *ptr) |
|
{ |
|
render_thd=1; /* Signal Thread is active */ |
|
|
|
/* Match the Audio and Video Time Stamps */ |
|
VTS = ++frame / VIDEO_RATE; |
|
while( ATS < VTS ) thd_pass(); |
|
|
|
/* Draw the frame using the PVR */ |
|
pvr_draw_frame_dma(&roq_vram_ptr); |
|
//printf("Rendered Frame %u\n", frame); |
|
render_thd=0; /* Signal Thread is finished */ |
|
return NULL; |
|
} |
|
|
|
static int render_cb(unsigned short *buf, int width, int height, int stride, |
|
int texture_height) |
|
{ |
|
/* on first call, initialize textures and drawing coordinates */ |
|
if (!graphics_initialized) |
|
{ |
|
/* Allocate VRAM for current texture */ |
|
pvr_malloc( &roq_vram_ptr, width, height ); |
|
|
|
/* Compile the PVR Driver Handle */ |
|
//pvr_resize_resolution( roq_vram_ptr, &roq_vram_vertex ); |
|
pvr_set_resolution( roq_vram_ptr, 0, 0, 640, 480, &roq_vram_vertex ); |
|
pvr_compile_poly(roq_vram_vertex, &roq_vram_ptr, |
|
PVR_LIST_OP_POLY, PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED, 10.0f); |
|
|
|
graphics_initialized = 1; |
|
printf("Graphics initialized\n"); |
|
} |
|
|
|
/* Wait for last frame to finish render */ |
|
while(render_thd){ |
|
//printf("Still rendering"); |
|
thd_pass(); |
|
} |
|
|
|
/* Current decoded frame */ |
|
pvr_dma_load( (unsigned char *)buf, &roq_vram_ptr); |
|
|
|
/* Create a thread to render the current frame */ |
|
//Try 1 onr 0 for first arg |
|
render_thread = thd_create(0, video_thd, NULL); |
|
printf("Render Thread Active %d\n", render_thd); |
|
|
|
return ROQ_SUCCESS; |
|
} |
|
|
|
maple_device_t *cont; //Controller |
|
cont_state_t *state; //State of inputs |
|
static int quit_cb() |
|
{ |
|
|
|
/* |
|
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); |
|
// check controller state |
|
state = maple_dev_status(cont); |
|
|
|
// If the state/controller is unavailable |
|
if(!state) { |
|
printf("Error reading controller\n"); |
|
return(0); |
|
} |
|
|
|
state->buttons = ~state->buttons; |
|
return (state->buttons & CONT_START); |
|
*/ |
|
return ROQ_SUCCESS; |
|
} |
|
|
|
int main() |
|
{ |
|
int status=0; |
|
|
|
vid_set_mode(DM_640x480, PM_RGB565); |
|
pvr_init_defaults(); |
|
pvr_dma_init(); |
|
|
|
printf("dreamroq_play(C) Multimedia Mike Melanson & Josh PH3NOM Pearson 2011\n"); |
|
|
|
/* To disable a callback, simply replace the function name by 0 */ |
|
status = dreamroq_play("/cd/id_soft.roq", 1, render_cb, audio_cb, quit_cb); |
|
|
|
printf("dreamroq_play() status = %d\n", status); |
|
|
|
if(audio_init) |
|
{ |
|
free( pcm_buf ); |
|
pcm_buf = NULL; |
|
pcm_size = 0; |
|
samples_done = 0; |
|
mutex_destroy(pcm_mut); /* Destroy the PCM mutex */ |
|
snddrv_exit(); /* Exit the AICA Driver */ |
|
} |
|
|
|
if(graphics_initialized) |
|
{ |
|
pvr_free( &roq_vram_ptr ); /* Free the PVR memory */ |
|
} |
|
|
|
pvr_dma_shutdown(); |
|
|
|
return 0; |
|
}
|
|
|