Updated the DreamRoq Lib
This commit is contained in:
parent
5939601c42
commit
f1d0a507df
64
samples/dreamroq/LICENSE.KOS
Normal file
64
samples/dreamroq/LICENSE.KOS
Normal 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.
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ); \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user