This commit is contained in:
ABelliqueux 2021-10-21 16:35:08 +02:00
commit 42529842bb
6 changed files with 482 additions and 0 deletions

13
Makefile Normal file
View File

@ -0,0 +1,13 @@
.PHONY: all cleansub
all:
mkpsxiso -y ./isoconfig.xml
cleansub:
$(MAKE) clean
rm -f hello_str.cue hello_str.bin
rm -f *.mcd *.frag *.lua *.vert
TARGET = hello_str
SRCS = hello_str.c \
include common.mk

36
README.md Normal file
View File

@ -0,0 +1,36 @@
This example show how to use Lameguy64's [STR playback library](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str#str-playback-library).
For a barebone example, see the [hello_str](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str) example.
## Compiling
You need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.
Typing
```bash
make
```
in a terminal will compile and generate the bin/cue files.
Typing
```bash
make cleansub
```
will clean the current directory.
## STR playback library
@Lameguy64 has spent some time making a STR playback library that's easily included in a project :
> One thing that I find somewhat missing here is a decent piece of code for playing STR video files easily. So, what I did was take the old and messy PsyQ STR player example, clean it up entirely, and finally make it into a cute little c library for easy implementation.
Original post : http://www.psxdev.net/forum/viewtopic.php?t=507
Original download link : https://www.mediafire.com/download/s61u86sxd1djncy/strplay.7z
Mirror : http://psx.arthus.net/code/strplay.7z
## Video encoding and more informations
See the [wiki](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/STR).
## Video credits
The video and song used in this example are by Nina Paley : https://archive.org/details/CopyingIsNotTheft-ScratchTrack1280X720Hdv

53
common.mk Normal file
View File

@ -0,0 +1,53 @@
# If you change this to exe, you'll have to rename the file ./thirdparty/nugget/ps-exe.ld too.
TYPE = ps-exe
THISDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
SRCS += $(THISDIR)../nolibgs_hello_worlds/thirdparty/nugget/common/crt0/crt0.s
SRCS += $(THISDIR)../nolibgs_hello_worlds/thirdparty/nugget/common/syscalls/printf.s
CPPFLAGS += -I$(THISDIR)../nolibgs_hello_worlds/thirdparty/nugget/psyq/include -I$(THISDIR)psyq-4_7-converted/include -I$(THISDIR)psyq-4.7-converted-full/include -I$(THISDIR)../psyq/include
LDFLAGS += -L$(THISDIR)../nolibgs_hello_worlds/thirdparty/nugget/psyq/lib -L$(THISDIR)psyq-4_7-converted/lib -L$(THISDIR)psyq-4.7-converted-full/lib -L$(THISDIR)../psyq/lib
# add support for NDR008's VScode setup
CPPFLAGS += -I$(THISDIR)../third_party/psyq/include
LDFLAGS += -L$(THISDIR)../third_party/psyq/lib
LDFLAGS += -Wl,--start-group
LDFLAGS += -lapi
LDFLAGS += -lc
LDFLAGS += -lc2
LDFLAGS += -lcard
LDFLAGS += -lcomb
LDFLAGS += -lds
LDFLAGS += -letc
LDFLAGS += -lgpu
LDFLAGS += -lgs
LDFLAGS += -lgte
LDFLAGS += -lgun
LDFLAGS += -lhmd
LDFLAGS += -lmath
LDFLAGS += -lmcrd
LDFLAGS += -lmcx
LDFLAGS += -lpad
LDFLAGS += -lpress
LDFLAGS += -lsio
LDFLAGS += -lsnd
LDFLAGS += -lspu
LDFLAGS += -ltap
LDFLAGS += -lcd
LDFLAGS += -Wl,--end-group
include $(THISDIR)../nolibgs_hello_worlds/thirdparty/nugget/common.mk
define OBJCOPYME
$(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O $(FORMAT) -B mips $< $@
endef
# convert TIM file to bin
%.o: %.tim
$(call OBJCOPYME)
# convert VAG files to bin
%.o: %.vag
$(call OBJCOPYME)

275
hello_str.c Normal file
View File

@ -0,0 +1,275 @@
// Stream a STR file from CD, decompress and play it.
// Schnappy 07-2021
// based on Lameguy64 strplay library : http://www.psxdev.net/forum/viewtopic.php?t=507
// Original PsyQ sample code : /psyq/addons/cd/MOVIE
// Video to STR conversion : https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_str
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
// CD library
#include <libcd.h>
// CODEC library
#include <libpress.h>
#include "../nolibgs_hello_worlds/thirdparty/nugget/common/syscalls/syscalls.h"
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define TRUECOL 0 // 0 : 16bpp, 1: 24bpp
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 + (VMODE << 4) // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 8 // margins for text display
#define MARGINY 16
#define FONTSIZE 8 * 7 // Text Field Height
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
short db = 0; // index of which buffer is used, values 0, 1
#define STR_POS_X 0
// If PAL mode, add 8 pixels offset on Y (256-240)/2
#define STR_POS_Y (VMODE << 4)/2
// Ring Buffer size (32 sectors seems good enough)
#define RING_SIZE 32
#if TRUECOL
// pixels per short word (16b/2B)
// 1px is 3B in 24bpp
// 1px is 2B(one word) in 16bpp
// therefore 2B will hold 3/2 pixels
#define PPW 3/2
// DCT mode - bit 0 : depth (0 = 16b, 1 = 24b), bit 1: in 16b mode, set STP(Semi-Transparency) bit 15.
// 24bpp = 01b => 1
#define DCT_MODE 1
#else
#define PPW 1
// 16bpp = 10b => 2
#define DCT_MODE 2
#endif
// Stop playback if set
static int endPlayback = 0;
// STR file infos : Filename on CD, Width, Height, Length in frames
static char * StrFileName = "\\MENU.STR;1";
static int StrFileX = 320;
static int StrFileY = 240;
static int StrFileLength = 30;
// When using RGB24, a special routine has to be setup as a callback function to avoid MDEC/CDROM conflict
// See http://psx.arthus.net/sdk/Psy-Q/DOCS/LibRef47.pdf , p.713
static void strCheckRGB24();
void init(void)
{
ResetCallback();
ResetGraph(0); // Initialize drawing engine with a complete reset (0)
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES); // Set display area for both &disp[0] and &disp[1]
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES); // &disp[0] is on top of &disp[1]
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES); // Set draw for both &draw[0] and &draw[1]
SetDefDrawEnv(&draw[1], 0, 0 , SCREENXRES, SCREENYRES); // &draw[0] is below &draw[1]
// Set video mode
#if VMODE
SetVideoMode(MODE_PAL);
disp[0].disp.y = 8;
disp[1].disp.y = 8;
#endif
SetDispMask(1); // Display on screen
setRGB0(&draw[0], 155, 0, 150); // set color for first draw area
setRGB0(&draw[1], 155, 0, 150); // set color for second draw area
draw[0].isbg = 0; // set mask for draw areas. 1 means repainting the area with the RGB color each frame
draw[1].isbg = 0;
#if TRUECOL
disp[0].isrgb24 = 1;
disp[1].isrgb24 = 1;
#endif
PutDispEnv(&disp[db]); // set the disp and draw environnments
PutDrawEnv(&draw[db]);
//~ FntLoad(960, 0); // Load font to vram at 960,0(+128)
//~ FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height, black_bg, max. nbr. chars
}
void display(void)
{
DrawSync(0); // Wait for all drawing to terminate
VSync(0); // Wait for the next vertical blank
PutDispEnv(&disp[db]); // set alternate disp and draw environnments
PutDrawEnv(&draw[db]);
//~ db = !db; // flip db value (0 or 1)
}
int main() {
// CD File descriptor
CdlFILE STRfile;
// Parameter we want to set the CDROM with
u_char param=CdlModeSpeed;
// Buffers total ~110KB in memory
// SECTOR_SIZE is defined in words : 512 * 4 == 2048 Bytes/sector
// Ring buffer : 32 * 2048 = 65536 Bytes
u_long RingBuff[ RING_SIZE * SECTOR_SIZE ];
// VLC buffers : display area in words (hence /2), 160*320 == 38400 Bytes
u_long VlcBuff[2][ SCREENXRES / 2 * StrFileY ];
// If using 16bpp, fetch 16xYres strips, if 24bpp, fetch 24xYres strips, 5120*PPW Bytes
u_short ImgBuff[2][ 16 * PPW * StrFileY];
//~ u_long * curVLCptr = VlcBuff[0];
// Init Disp/Draw env, Font, etc.
init();
// Init CDrom system
CdInit();
// Reset the MDEC
DecDCTReset(0);
// Set callback routine
DecDCToutCallback(strCheckRGB24);
// Set ring buffer
StSetRing(RingBuff, RING_SIZE);
// Set streaming parameters
StSetStream(TRUECOL, 1, StrFileLength, 0, 0);
// Get the CD location of the STR file to play
if ( CdSearchFile(&STRfile, StrFileName) == 0 ) {
FntPrint("File not found :%s\n", StrFileName);
}
// Set the seek target position
CdControl(CdlSetloc, (u_char *)&STRfile.pos, 0);
// Set CD mode to CdlModeSpeed
CdControl(CdlSetmode, &param, 0);
// Read from CD at position &STRfile.pos
// Enable streaming, double speed and ADPCM playback
CdRead2(CdlModeStream|CdlModeSpeed|CdlModeRT);
// Use a counter to avoid deadlocks
int wait = WAIT_TIME;
// Next Ring Buffer Frame address
u_long * nextFrame = 0;
// Ring buffer frame address
u_long * frameAddr = 0;
// Ring buffer frame header
StHEADER * sectorHeader;
// Set Channel
//~ StSetChannel( 0 );
u_long * curVLCptr = &VlcBuff[!db][0];
u_short * curIMGptr = &ImgBuff[db][0];
// Main loop
while (1) {
// Set some pointers to the relevant buffer addresses
//~ u_long * curVLCptr = &VlcBuff[!db][0];
//~ u_short * curIMGptr = &ImgBuff[db][0];
// While end of str is not reached, play it
if (endPlayback == 1)
{
u_long * curVLCptr = &VlcBuff[!db][0];
u_short * curIMGptr = &ImgBuff[db][0];
// Set the seek target position
CdControl(CdlSetloc, (u_char *)&STRfile.pos, 0);
// Set CD mode to CdlModeSpeed
CdControl(CdlSetmode, &param, 0);
// Read from CD at position &STRfile.pos
// Enable streaming, double speed and ADPCM playback
CdRead2(CdlModeStream|CdlModeSpeed|CdlModeRT);
endPlayback = 0;
}
while ( endPlayback == 0)
{
// Use this area to draw the slices
RECT curSlice = { 0,
(db * StrFileY) + STR_POS_Y,
// In 24bpp, use 24 pixels wide slices
16 * PPW ,
StrFileY};
int frameDone = 0;
// Reset counter
wait = WAIT_TIME;
// Dont try decoding if not data has been loaded from ring buffer
if ( frameAddr ){
// Begin decoding RLE-encoded MDEC image data
DecDCTin( curVLCptr , DCT_MODE);
// Prepare to receive the decoded image data from the MDEC
while (curSlice.x < STR_POS_X + SCREENXRES * PPW) {
// Receive decoded data : a 16*ppw*240 px slice
DecDCTout( (u_long *) curIMGptr, curSlice.w * curSlice.h / 2);
// Wait for transfer end
DecDCToutSync(1);
// Transfer data from main memory to VRAM
LoadImage(&curSlice, (u_long *) curIMGptr );
// Increment drawArea's X with slice width (16 or 24 pix)
curSlice.x += 16 * PPW;
}
// Set frameDone flag to 1
frameDone = 1;
curSlice.x = STR_POS_X;
curSlice.y = (db * StrFileY) + STR_POS_Y;
}
// Get one frame of ring buffer data
// StGetNext is non-blocking, so we wait for it to return 0.
// StGetNext will lock the region at &frameAddr until StFreeRing() is called.
while ( StGetNext((u_long **)&frameAddr,(u_long **)&sectorHeader) ) {
wait--;
if (wait == 0)
break;
}
// Grab a frame from the stream
wait = WAIT_TIME;
while ((nextFrame = frameAddr) == 0) {
wait--;
if ( wait == 0 ){
break;
}
}
// Decode the Huffman/VLC compressed data
DecDCTvlc(nextFrame, curVLCptr);
// Unlock area obtained by StGetNext()
StFreeRing(nextFrame);
// Reset counter
wait = WAIT_TIME;
// Wait until the whole frame is loaded to VRAM
while ( frameDone == 0 ) {
wait--;
if ( wait == 0 ) {
// If a timeout occurs, force switching buffers
frameDone = 1;
curSlice.x = STR_POS_X;
curSlice.y = (db * StrFileY) + STR_POS_Y;
}
}
// If the current frame's number is bigger than the number of frames in STR,
// set the endPlayback flag.
ramsyscall_printf("Frame %d / %d\n", sectorHeader->frameCount, StrFileLength);
if (sectorHeader->frameCount >= (StrFileLength - 1) )
{
endPlayback = 1;
}
display();
}
display();
// Disable callback
//~ DecDCToutCallback(0);
// Release two interrupt functions CdDataCallback() and CdReadyCallback() hooked by CDRead2()
//~ StUnSetRing();
// Put CDROM on pause at current position
//~ CdControlB(CdlPause, 0, 0);
}
return 0;
};
static void strCheckRGB24() {
/* From http://psx.arthus.net/sdk/Psy-Q/DOCS/, p.713
* When playing a movie in 24-bit mode, there is a potential hardware conflict between the CD subsystem
* and the MDEC image decompression system which can result in corrupted data. To avoid this,
* StCdInterrupt() may defer transferring a sector and instead set a flag variable called StCdInterFlag to
* indicate that a CD sector is ready to be transferred. Once the MDEC is finished transferring data, your
* application should check StCdIntrFlag and call StCdInterrupt() directly if it is set.
*/
#if TRUECOL
extern int StCdIntrFlag;
// If flag was set
if ( StCdIntrFlag ) {
// Trigger data transfer
StCdInterrupt();
// Reset flag
StCdIntrFlag = 0;
}
#endif
}

101
isoconfig.xml Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- MKPSXISO example XML script -->
<!-- <iso_project>
Starts an ISO image project to build. Multiple <iso_project> elements may be
specified within the same xml script which useful for multi-disc projects.
<iso_project> elements must contain at least one <track> element.
Attributes:
image_name - File name of the ISO image file to generate.
cue_sheet - Optional, file name of the cue sheet for the image file
(required if more than one track is specified).
-->
<iso_project image_name="hello_str.bin" cue_sheet="hello_str.cue">
<!-- <track>
Specifies a track to the ISO project. This example element creates a data
track for storing data files and CD-XA/STR streams.
Only one data track is allowed and data tracks must only be specified as the
first track in the ISO image and cannot be specified after an audio track.
Attributes:
type - Track type (either data or audio).
source - For audio tracks only, specifies the file name of a wav audio
file to use for the audio track.
-->
<track type="data">
<!-- <identifiers>
Optional, Specifies the identifier strings to use for the data track.
Attributes:
system - Optional, specifies the system identifier (PLAYSTATION if unspecified).
application - Optional, specifies the application identifier (PLAYSTATION if unspecified).
volume - Optional, specifies the volume identifier.
volume_set - Optional, specifies the volume set identifier.
publisher - Optional, specifies the publisher identifier.
data_preparer - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO
will fill it with lengthy text telling that the image file was generated
using MKPSXISO.
-->
<identifiers
system ="PLAYSTATION"
application ="PLAYSTATION"
volume ="HELOCD"
volume_set ="HELOCD"
publisher ="SCHNAPPY"
data_preparer ="MKPSXISO"
/>
<!-- <license>
Optional, specifies the license file to use, the format of the license file must be in
raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\cdgen\LCNSFILE.
License data is not included within the MKPSXISO program to avoid possible legal problems
in the open source environment... Better be safe than sorry.
Attributes:
file - Specifies the license file to inject into the ISO image.
-->
<!--
<license file="LICENSEA.DAT"/>
-->
<!-- <directory_tree>
Specifies and contains the directory structure for the data track.
Attributes:
None.
-->
<directory_tree>
<!-- <file>
Specifies a file in the directory tree.
Attributes:
name - File name to use in the directory tree (can be used for renaming).
type - Optional, type of file (data for regular files and is the default, xa for
XA audio and str for MDEC video).
source - File name of the source file.
-->
<!-- Stores system.txt as system.cnf -->
<file name="system.cnf" type="data" source="system.cnf"/>
<file name="SCES_313.37" type="data" source="hello_str.ps-exe"/>
<file name="MENU.STR" type="str" source="render/bg_only_mc.str"/>
<dummy sectors="1024"/>
<!-- <dir>
Specifies a directory in the directory tree. <file> and <dir> elements inside the element
will be inside the specified directory.
-->
</directory_tree>
</track>
</iso_project>

4
system.cnf Normal file
View File

@ -0,0 +1,4 @@
BOOT=cdrom:\SCES_313.37;1
TCB=4
EVENT=10
STACK=801FFFF0