Updated the DreamRoq Lib

This commit is contained in:
lerabot 2023-08-22 23:03:23 -04:00
parent 5939601c42
commit f1d0a507df
6 changed files with 484 additions and 186 deletions

View File

@ -0,0 +1,64 @@
Dreamroq is covered under the same terms as the KallistiOS license which
is copied below:
Most of the code of KallistiOS proper is currently covered under the KOS
License, which are the terms of the *new* BSD license with our names
inserted as the copyright holders and the "advertising clause" removed
entirely. In all files that state that they are part of the KallistiOS
operating system, you can assume that the following text is inserted in
the header:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the KOS License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* KOS License (README.KOS) for more details.
*
* You should have received a copy of the KOS License along with this
* program; if not, please visit Cryptic Allusion DCDev at:
*
* http://dcdev.allusion.net/
*
The text of that license follows. In layman's terms, all it really
says is that you have to give credit where credit is due (both in
derived source files and binary compilations; a credit in the
documentation is ok) and there is no warranty.
Dan Potter
All of the documentation and software included in the KallistiOS Releases
is copyrighted (c)2000-2002 by Dan Potter and others (as noted in each file).
Copyright 2000, 2001, 2002
Dan Potter and others (as noted in each file). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Cryptic Allusion nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@ -434,7 +434,6 @@ static void dma_chain(ptr_t data) {
/* Poll streamer to load more data if necessary */
int snd_stream_poll(snd_stream_hnd_t hnd) {
uint32 ch0pos, ch1pos;
// Ian micheal fixed all threading problems
/* int realbuffer; */ // Remove this line
int current_play_pos;
int needed_samples;
@ -444,7 +443,7 @@ int snd_stream_poll(snd_stream_hnd_t hnd) {
CHECK_HND(hnd);
if (!streams[hnd].get_data) return -1;
// Ian micheal fixed all threading problems
/* Get "real" buffer */
ch0pos = g2_read_32(SPU_RAM_BASE + AICA_CHANNEL(streams[hnd].ch[0]) + offsetof(aica_channel_t, pos));
ch1pos = g2_read_32(SPU_RAM_BASE + AICA_CHANNEL(streams[hnd].ch[1]) + offsetof(aica_channel_t, pos));
@ -466,8 +465,8 @@ int snd_stream_poll(snd_stream_hnd_t hnd) {
needed_samples &= ~0x7ff;
/* printf("last_write_pos %6i, current_play_pos %6i, needed_samples %6i\n",last_write_pos,current_play_pos,needed_samples); */
//if (needed_samples > 0) {
if (needed_samples ==4096) {
//Ian micheal wtf was this set to 4096? was causing a delay
if (needed_samples ==2048) {
if (streams[hnd].stereo) {
data = streams[hnd].get_data(hnd, needed_samples * 4, &got_samples);
process_filters(hnd, &data, &got_samples);

View File

@ -18,6 +18,13 @@
** at that point the decoder signals sndbuf_status=SNDDRV_STATUS_HAVEBUF
**
*/
/*
Name: Ian micheal
Copyright:
Author: Ian micheal
Date: 12/08/23 05:17
Description: kos 2.0 up port threading fix and wrappers and all warnings fixed
*/
#include <kos/thread.h>
#include <dc/sound/stream.h>
@ -26,10 +33,12 @@
#include <string.h>
#include "snddrv.h"
snd_stream_hnd_t shnd;
kthread_t * snddrv_thd;
static int snddrv_vol = 255;
snd_drv snddrv;
snd_stream_hnd_t shnd;
kthread_t * snddrv_thd;
static int snddrv_vol = 255;
struct snddrv snddrv;
struct snddrv_song_info snd_sinfo;
/* Increase the Sound Driver volume */
int snddrv_volume_up() {
@ -118,6 +127,13 @@ static int snddrv_thread() {
return snddrv.drv_status;
}
/* Wrapper function for snddrv_thread */
static void *snddrv_thread_wrapper(void *arg)
{
int status = snddrv_thread(); // Get the status value
return (void *)(size_t)status; // Cast the int status to void pointer
}
/* Start the AICA Sound Stream Thread */
int snddrv_start( int rate, int chans ) {
@ -134,7 +150,11 @@ int snddrv_start( int rate, int chans ) {
snd_stream_init();
/*libdcmc/snddrv.c:136: warning: passing arg 1 of `thd_create' from incompatible pointer type */ //Ian micheal 2020 warning
snddrv_thd = thd_create(0, snddrv_thread, NULL );
/* Use the wrapper function here */
snddrv_thd = thd_create(0, snddrv_thread_wrapper, NULL);
printf("SNDDRV: Creating Driver Thread\n");
return snddrv.drv_status;

View File

@ -35,8 +35,11 @@
/* This seems to be a good number for file seeking on compressed audio */
#define SEEK_LEN 16384*48
extern struct snddrv snddrv;
extern struct snddrv_song_info snd_sinfo;
/* SNDDRV (C) AICA Audio Driver */
typedef struct _snd_drv {
struct snddrv {
int rate;
int channels;
int pcm_bytes;
@ -46,15 +49,13 @@ typedef struct _snd_drv {
volatile int buf_status;
unsigned int pcm_buffer[65536+16384];
unsigned int *pcm_ptr;
} snd_drv;
extern snd_drv snddrv;
};
#define SNDDRV_FREE_STRUCT() { \
snddrv.rate = snddrv.channels = snddrv.drv_status = \
snddrv.dec_status = snddrv.buf_status = 0; }
typedef struct snddrv_song_info {
struct snddrv_song_info {
char *artist[128];
char * title[128];
char * track[128];
@ -65,7 +66,7 @@ typedef struct snddrv_song_info {
volatile float spos;
int fsize;
float slen;
} snd_sinfo;
};
#define SNDDRV_FREE_SINFO() { \
sq_clr( snd_sinfo.artist, 128 ); \

View File

@ -1,12 +1,40 @@
/*
* 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.
*/
/*
Name: Iaan micheal
Copyright:
Author: Ian micheal
Date: 12/08/23 05:17
Description: kos 2.0 up port threading fix and wrappers and all warnings fixed
Redone threading and main added benchmarking for timing acia and roq decoding audio
redone rendering order and code commented to be much easier to read.
example OUTPUT:> Wait for AICA Driver: 88 ms
OUTPUT:> Wait for RoQ Decoder: 1 ms
OUTPUT:> Copy PCM Samples: 1 ms
OUTPUT:> Inform AICA Driver: 0 ms
OUTPUT:> Wait for AICA Driver: 88 ms
OUTPUT:> Wait for RoQ Decoder: 0 ms
Before
OUTPUT:> Wait for AICA Driver: 168 ms
OUTPUT:> Wait for RoQ Decoder: 0 ms
OUTPUT:> Copy PCM Samples: 1 ms
OUTPUT:> Inform AICA Driver: 0 ms
OUTPUT:> Wait for AICA Driver: 187 ms
OUTPUT:> Wait for RoQ Decoder: 0 ms
OUTPUT:> Copy PCM Samples: 1 ms
OUTPUT:> Inform AICA Driver: 0 ms
OUTPUT:> Wait for AICA Driver: 197 ms
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glu.h>
#include <GL/glkos.h>
#include <kos.h>
#include <dc/pvr.h>
#include <dc/maple.h>
@ -14,152 +42,202 @@
#include <kos/mutex.h>
#include <kos/thread.h>
#include "libdcmc/snddrv.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glkos.h>
#include "dreamroqlib.h"
#include "libdcmc/dc_timer.h"
#include "libdcmc/snddrv.h"
#include <dc/sound/sound.h>
#include <stdio.h>
#ifdef __DREAMCAST__
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define VIDEO_FILENAME "/rd/video.roq"
#else
#define VIDEO_FILENAME "../samples/dreamroq/romdisk/video.roq"
#endif
maple_device_t *cont;
cont_state_t *state;
/* 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;
#define PCM_BUF_SIZE (1024 * 1024)
static unsigned char *pcm_buf = NULL;
static int pcm_size = 0;
#define AUDIO_THREAD_PRIO 0
kthread_t *audio_thread; // Thread handle for the audio thread
int audio_init = 0; // Flag to indicate audio initialization status
static mutex_t pcm_mut = MUTEX_INITIALIZER;
/* Video Global variables */
static int current_frame = 0;
static int graphics_initialized = 0;
static float video_delay = 0.0f;
static int frame = 0;
static const float VIDEO_RATE = 30.0f; /* Video FPS */
static pvr_ptr_t textures[2];
static int current_frame = 0;
static int graphics_initialized = 0;
static float video_delay;
static GLint frameTexture[2];
//static GLVertexKOS vertices[4];
GLfloat vertices[4][5];
GLuint frameTexture[2];
// Define the target frame rate
#define TARGET_FRAME_RATE 30
// maybe should aling this better?
typedef struct {
float x, y, z;
} Vec3;
typedef struct {
float u, v;
} UV;
static Vec3 vertices[4];
static UV uv[4];
static void snd_thd()
{
do
{
/* Wait for AICA Driver to request some samples */
while( snddrv.buf_status != SNDDRV_STATUS_NEEDBUF )
thd_pass();
unsigned int start_time, end_time;
/* Wait for RoQ Decoder to produce enough samples */
while( pcm_size < snddrv.pcm_needed )
// Measure time taken by waiting for AICA Driver request
start_time = dc_get_time();
while (snddrv.buf_status != SNDDRV_STATUS_NEEDBUF)
thd_pass();
end_time = dc_get_time();
printf("Wait for AICA Driver: %u ms\n", end_time - start_time);
// Measure time taken by waiting for RoQ Decoder
start_time = dc_get_time();
while (pcm_size < snddrv.pcm_needed)
{
if( snddrv.dec_status == SNDDEC_STATUS_DONE )
goto done;
thd_pass();
if (snddrv.dec_status == SNDDEC_STATUS_DONE)
goto done;
thd_pass();
}
end_time = dc_get_time();
printf("Wait for RoQ Decoder: %u ms\n", end_time - start_time);
/* Copy the Requested PCM Samples to the AICA Driver */
mutex_lock( pcm_mut );
memcpy( snddrv.pcm_buffer, pcm_buf, snddrv.pcm_needed );
/* Shift the Remaining PCM Samples Back */
// Measure time taken by copying PCM samples
start_time = dc_get_time();
mutex_lock(&pcm_mut);
memcpy(snddrv.pcm_buffer, pcm_buf, snddrv.pcm_needed);
pcm_size -= snddrv.pcm_needed;
memmove( pcm_buf, pcm_buf+snddrv.pcm_needed, pcm_size );
mutex_unlock( pcm_mut );
/* Let the AICA Driver know the PCM samples are ready */
memmove(pcm_buf, pcm_buf + snddrv.pcm_needed, pcm_size);
mutex_unlock(&pcm_mut);
end_time = dc_get_time();
printf("Copy PCM Samples: %u ms\n", end_time - start_time);
// Measure time taken by informing AICA Driver
start_time = dc_get_time();
snddrv.buf_status = SNDDRV_STATUS_HAVEBUF;
} while( snddrv.dec_status == SNDDEC_STATUS_STREAMING );
done:
end_time = dc_get_time();
printf("Inform AICA Driver: %u ms\n", end_time - start_time);
} while (snddrv.dec_status == SNDDEC_STATUS_STREAMING);
done:
snddrv.dec_status = SNDDEC_STATUS_NULL;
}
static int renderGLdc_cb(unsigned short *buf, int width, int height, int stride, int texture_height)
static int render_cb(unsigned short *buf, int width, int height, int stride,
int texture_height)
{
/* send the video frame as a texture over to video RAM */
//pvr_txr_load(buf, textures[current_frame], stride * texture_height * 2);
glBindTexture(GL_TEXTURE_2D, frameTexture[current_frame]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buf);
/* Delay the frame to match Frame Rate */
frame_delay(VIDEO_RATE, video_delay, ++frame);
pvr_poly_cxt_t cxt;
static pvr_poly_hdr_t hdr[2];
static pvr_vertex_t vert[4];
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
float ratio;
// screen coordinates of upper left and bottom right corners
static int ul_x, ul_y, br_x, br_y;
glVertexPointer (3, GL_FLOAT, 0, vertices);
glTexCoordPointer (2, GL_FLOAT, 0, uv);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Initialize textures, drawing coordinates, and other parameters
if (!graphics_initialized)
{
textures[0] = pvr_mem_malloc(stride * texture_height * 2);
textures[1] = pvr_mem_malloc(stride * texture_height * 2);
if (!textures[0] || !textures[1])
{
return ROQ_RENDER_PROBLEM;
}
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// Precompile the poly headers
for (int i = 0; i < 2; i++) {
pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED,
stride, texture_height, textures[i], PVR_FILTER_NONE);
pvr_poly_compile(&hdr[i], &cxt);
}
glKosSwapBuffers();
// Calculate drawing coordinates
ratio = 640.0 / width;
ul_x = 0;
br_x = (int)(ratio * stride);
ul_y = (int)((480 - ratio * height) / 2);
br_y = ul_y + (int)(ratio * texture_height);
/*
if (current_frame)
current_frame = 0;
else
current_frame = 1;
*/
// Set common vertex properties
for (int i = 0; i < 4; i++) {
vert[i].z = 1.0f;
vert[i].argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
vert[i].oargb = 0;
vert[i].flags = (i < 3) ? PVR_CMD_VERTEX : PVR_CMD_VERTEX_EOL;
}
// Initialize vertex coordinates and UV coordinates
vert[0].x = ul_x;
vert[0].y = ul_y;
vert[0].u = 0.0;
vert[0].v = 0.0;
vert[1].x = br_x;
vert[1].y = ul_y;
vert[1].u = 1.0;
vert[1].v = 0.0;
vert[2].x = ul_x;
vert[2].y = br_y;
vert[2].u = 0.0;
vert[2].v = 1.0;
vert[3].x = br_x;
vert[3].y = br_y;
vert[3].u = 1.0;
vert[3].v = 1.0;
// Get the current hardware timing
video_delay = (float)dc_get_time();
graphics_initialized = 1;
}
// Send the video frame as a texture over to video RAM
pvr_txr_load(buf, textures[current_frame], stride * texture_height * 2);
// Calculate the elapsed time since the last frame
unsigned int current_time = dc_get_time();
unsigned int elapsed_time = current_time - video_delay;
unsigned int target_frame_time = 1000 / TARGET_FRAME_RATE;
// If the elapsed time is less than the target frame time, introduce a delay
if (elapsed_time < target_frame_time) {
unsigned int delay_time = target_frame_time - elapsed_time;
thd_sleep(delay_time);
}
// Update the hardware timing for the current frame
video_delay = (float)current_time;
pvr_wait_ready();
pvr_scene_begin();
pvr_list_begin(PVR_LIST_OP_POLY);
// Render the frame using precompiled headers and vertices
pvr_prim(&hdr[current_frame], sizeof(pvr_poly_hdr_t));
for (int i = 0; i < 4; i++) {
pvr_prim(&vert[i], sizeof(pvr_vertex_t));
}
pvr_list_finish();
pvr_scene_finish();
// Toggle between frames
current_frame = 1 - current_frame;
return ROQ_SUCCESS;
}
static int audio_cb( unsigned char *buf, int size, int channels)
static int renderGLdc_cb(unsigned short *buf, int width, int height, int stride, int texture_height)
{
/* 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 int quit_cb()
{
/*
state = (cont_state_t *)maple_dev_status(cont);
if(state->buttons & CONT_START)
return 1;
else
return 0;
*/
}
int main(int argc, char **argv)
{
printf("--- DreamRoQ Player for Dreamcast\n");
glKosInit();
//cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
//state = (cont_state_t *)maple_dev_status(cont);
if(!graphics_initialized) {
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // This Will Clear The Background Color To Black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -187,32 +265,32 @@ int main(int argc, char **argv)
float h = 512;
int v = 0;
vertices[v].x = 0;
vertices[v].y = 0;
vertices[v].z = 0;
uv[v].u = 0.0f;
uv[v].v = 1.0f;
vertices[v][0] = 0;
vertices[v][1] = 0;
vertices[v][2] = 0;
vertices[v][3] = 0.0f;
vertices[v][4] = 1.0f;
v++;
vertices[v].x = 0;
vertices[v].y = 480;
vertices[v].z = 0;
uv[v].u = 0.0f;
uv[v].v = 0.0f;
vertices[v][0] = 0;
vertices[v][1] = 480;
vertices[v][2] = 0;
vertices[v][3] = 0.0f;
vertices[v][4] = 0.0f;
v++;
vertices[v].x = 640;
vertices[v].y = 0;
vertices[v].z = 0;
uv[v].u = 1.0f;
uv[v].v = 1.0f;
vertices[v][0] = 640;
vertices[v][1] = 0;
vertices[v][2] = 0;
vertices[v][3] = 1.0f;
vertices[v][4] = 1.0f;
v++;
vertices[v].x = 640;
vertices[v].y = 480;
vertices[v].z = 0;
uv[v].u = 1.0f;
uv[v].v = 0.0f;
vertices[v][0] = 640;
vertices[v][1] = 480;
vertices[v][2] = 0;
vertices[v][3] = 1.0f;
vertices[v][4] = 0.0f;
v++;
GLfloat drawColor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
@ -224,49 +302,185 @@ int main(int argc, char **argv)
graphics_initialized = 1;
}
/*
if(!audio_init) {
// allocate PCM buffer
pcm_buf = malloc(PCM_BUF_SIZE);
if( pcm_buf == NULL )
return ROQ_NO_MEMORY;
// Start AICA Driver
// Audio rate, channel number
snddrv_start( 22050, 2);
snddrv.dec_status = SNDDEC_STATUS_STREAMING;
// Create a thread to stream the samples to the AICA
thd_create(0, snd_thd, NULL);
// Create a mutex to handle the double-threaded buffer
//pcm_mut = mutex_create();
audio_init = 1;
/* send the video frame as a texture over to video RAM */
//pvr_txr_load(buf, textures[current_frame], stride * texture_height * 2);
glBindTexture(GL_TEXTURE_2D, frameTexture[current_frame]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buf);
// Calculate the elapsed time since the last frame
unsigned int current_time = dc_get_time();
unsigned int elapsed_time = current_time - video_delay;
unsigned int target_frame_time = 1000 / TARGET_FRAME_RATE;
// If the elapsed time is less than the target frame time, introduce a delay
if (elapsed_time < target_frame_time) {
unsigned int delay_time = target_frame_time - elapsed_time;
thd_sleep(delay_time);
}
*/
printf("--- Playing video using DreamRoQ\n");
int status = dreamroq_play(VIDEO_FILENAME, 0, renderGLdc_cb, 0, 0);
printf("dreamroq_play() status = %d\n", status);
// Update the hardware timing for the current frame
video_delay = (float)current_time;
/*
if(audio_init) {
snddrv.dec_status = SNDDEC_STATUS_DONE; // Singal audio thread to stop
while( snddrv.dec_status != SNDDEC_STATUS_NULL )
thd_pass();
free( pcm_buf );
pcm_buf = NULL;
pcm_size = 0;
mutex_destroy(pcm_mut); // Destroy the PCM mutex
snddrv_exit(); // Exit the AICA Driver
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if(graphics_initialized) {
glDeleteTextures(2, frameTexture);
glEnable(GL_LIGHTING);
}
*/
return status;
glVertexPointer (3, GL_FLOAT, sizeof(vertices[0]), &vertices[0][0]);
glTexCoordPointer (2, GL_FLOAT, sizeof(vertices[0]), &vertices[0][3]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glKosSwapBuffers();
current_frame = 1 - current_frame;
return ROQ_SUCCESS;
}
static int audio_cb(unsigned char *buf, int size, int channels)
{
// 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;
}
// Audio thread function
static void *snd_thd_wrapper(void *arg)
{
printf("Audio Thread: Started\n");
unsigned int start_time = dc_get_time();
// Call the actual audio thread function
snd_thd();
unsigned int end_time = dc_get_time();
unsigned int elapsed_time = end_time - start_time;
printf("Audio Thread: Finished (Time: %u ms)\n", elapsed_time);
return NULL;
}
static int quit_cb()
{
static int frame_count = 0;
static unsigned int last_time = 0;
static unsigned int target_frame_time = 1000 / 30; // 30 FPS
// Calculate time difference since the last frame
unsigned int current_time = dc_get_time();
unsigned int elapsed_time = current_time - last_time;
// Check if the video has ended and the audio decoding status is done
if (snddrv.dec_status == SNDDEC_STATUS_DONE) {
printf("Exiting due to audio decoding status\n");
return 1; // Exit the loop
}
// Check if the "Start" button is pressed
MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
if (st->buttons & CONT_START) {
printf("Exiting due to Start button\n");
return 1; // Exit the loop
}
MAPLE_FOREACH_END()
// Delay if necessary to maintain the target frame rate
if (elapsed_time < target_frame_time) {
unsigned int delay_time = target_frame_time - elapsed_time;
thd_sleep(delay_time);
}
// Print FPS information every second
if (elapsed_time >= 1000) {
// double fps = (double)frame_count / (elapsed_time / 1000.0);
// printf("FPS: %.2lf\n", fps);
frame_count = 0;
last_time = current_time;
}
// printf("Continuing loop\n");
fflush(stdout); // Flush the output buffer to ensure immediate display
frame_count++;
return 0; // Continue the loop
}
int main()
{
int status = 0;
glKosInit();
printf("dreamroq_play(C) Multimedia Mike Melanson & Josh PH3NOM Pearson 2011\n");
printf("dreamroq_play(C) Ian micheal Up port to Kos2.0 sound fix and threading\n");
printf("dreamroq_play(C) Ian micheal Kos2.0 free and exit when loop ends 2023\n");
printf("dreamroq_play(C) Ian micheal redo frame limit code and rendering and comment what it does 2023\n");
// Initialize audio resources and create the audio thread
if (!audio_init)
{
pcm_buf = malloc(PCM_BUF_SIZE);
if (pcm_buf == NULL)
{
printf("Failed to allocate PCM buffer\n");
return 1;
}
snddrv_start(22050, 2);
snddrv.dec_status = SNDDEC_STATUS_STREAMING;
printf("Creating Audio Thread\n");
audio_thread = thd_create(AUDIO_THREAD_PRIO, snd_thd_wrapper, NULL);
if (!audio_thread)
{
printf("Failed to create audio thread\n");
free(pcm_buf);
pcm_buf = NULL;
return 1;
}
audio_init = 1;
}
/* To disable a callback, simply replace the function name by 0 */
status = dreamroq_play("/rd/movie.roq", 0, renderGLdc_cb, audio_cb, quit_cb);
//status = dreamroq_play("/cd/romdisk/movie.roq", 0, renderGLdc_cb, audio_cb, quit_cb);
printf("dreamroq_play() status = %d\n", status);
// Terminate and clean up the audio thread
if (audio_init)
{
snddrv.dec_status = SNDDEC_STATUS_DONE;
while (snddrv.dec_status != SNDDEC_STATUS_NULL)
{
thd_sleep(1);
printf("Waiting for audio thread to finish...\n");
}
thd_destroy(audio_thread); // Destroy the audio thread
free(pcm_buf);
pcm_buf = NULL;
pcm_size = 0;
}
if (graphics_initialized)
{
pvr_mem_free(textures[0]);
pvr_mem_free(textures[1]);
printf("Freed PVR memory\n");
}
printf("Exiting main()\n");
return 0;
}