Another audio sync fix, Pi build, initial Sinden lightgun support, indexing display, and more.

This commit is contained in:
Scott Duensing 2020-02-16 17:33:08 -06:00
parent 57bb9c7703
commit fc859dc05c
18 changed files with 245 additions and 72 deletions

3
.gitignore vendored
View file

@ -39,5 +39,8 @@ singe/font.h
singe/icon.h
singe/kangarooPunchLogo.h
singe/singeLogo.h
singe/indexing.h
singe/laserDisc.h
singe/magnifyingGlass.h
videotest/indexing/
Makefile.in

View file

@ -21,6 +21,8 @@
source source.inc.sh
G_L="-------------------------------------------------------------------------------"
function doBuild() {
local TARGET=$1
@ -32,6 +34,9 @@ function doBuild() {
local OFILES=""
local O=
# Override this
QMAKE_CFLAGS="-isystem ../../thirdparty-build/${OSNAME}/${OSARCH}/installed/include -isystem ../../singe/thirdparty/arg_parser -isystem ../../singe/thirdparty/manymouse"
pushd "${SOURCE_DIR}/.."
mkdir -p build/${OSNAME}/${OSARCH}
cd build
@ -66,24 +71,29 @@ function doBuild() {
}
# 64 Bit Linux
echo -e "${G_L}\nLinux x86_64\n${G_L}"
CROSS="x86_64-linux-gnu"
EXTRA_CFLAGS="-O2"
EXTRA_OFILES=""
EXTRA_LD_FLAGS="-l:everything.a -lpthread -lXv -lX11 -lXext -lm -ldl -lrt"
#doBuild Singe-Linux-x86_64 linux 64
doBuild Singe-Linux-x86_64 linux 64
# 64 Bit Windows
echo -e "${G_L}\nWindows x86_64\n${G_L}"
CROSS="x86_64-w64-mingw32"
EXTRA_CFLAGS="-O2"
EXTRA_OFILES="/tmp/singe.res"
EXTRA_LD_FLAGS="-mwindows -static -lmingw32 -l:everything.a -lm -lbcrypt -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -Dmain=SDL_main"
icotool -c -o /tmp/icon.ico icon.png
xcf2png icon.xcf -o /tmp/icon.png
icotool -c -o /tmp/icon.ico /tmp/icon.png
x86_64-w64-mingw32-windres singe.rc -O coff -o /tmp/singe.res
#doBuild Singe-Windows-x86_64 mingw 64 .exe
doBuild Singe-Windows-x86_64 mingw 64 .exe
rm /tmp/icon.ico
rm /tmp/icon.png
rm /tmp/singe.res
# 32 Bit Raspbian
echo -e "${G_L}\nLinux armv6\n${G_L}"
SYSROOT="/opt/cross/pi/buster"
CROSS="/opt/cross/pi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf"
EXTRA_CFLAGS="-O2 --sysroot ${SYSROOT}"

BIN
singe/font.png (Stored with Git LFS)

Binary file not shown.

BIN
singe/font.xcf (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -242,6 +242,7 @@ int32_t frameFileSeek(int32_t frameFileHandle, int64_t seekFrame, int32_t *video
/*
// Daphne-like framefile searching
found = f->count - 1;
for (i=f->count - 1; i>=0; i--) {
if (seekFrame <= f->files[i].frame) {
found = i;

BIN
singe/icon.png (Stored with Git LFS)

Binary file not shown.

BIN
singe/icon.xcf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
singe/indexing.xcf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
singe/laserDisc.xcf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
singe/magnifyingGlass.xcf (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -22,6 +22,7 @@
// -c -x 720 -y 480 -d data/maddog_dvd -v maddog_dvd/frame_maddog_dvd.txt maddog_dvd/maddog_dvd.singe
// -c -x 640 -y 480 -v ActionMax/frame_SonicFury.txt ActionMax/SonicFury.singe
// -x 640 -y 480 -d data/ActionMax ActionMax/BlueThunder.singe
// -v ActionMax/BlueThunder.mp4 test.singe
@ -108,7 +109,7 @@ void showUsage(char *name, char *message) {
}
int main(int argc, const char *argv[]) {
int main(int argc, char *argv[]) {
int32_t x = 0;
int32_t err = 0;
@ -132,6 +133,7 @@ int main(int argc, const char *argv[]) {
SDL_Surface *icon = NULL;
SDL_DisplayMode mode;
const char *arg = NULL;
const char **cargv = (const char **)argv;
struct Arg_parser parser;
static struct ap_Option options[] = {
{ 'a', "aspect", ap_yes },
@ -189,7 +191,7 @@ int main(int argc, const char *argv[]) {
// For that dumb OS
utilRedirectConsole();
if (!ap_init(&parser, argc, argv, options, 0)) {
if (!ap_init(&parser, argc, cargv, options, 0)) {
utilDie("Out of memory parsing arguments.");
}
if (ap_error(&parser)) {
@ -613,6 +615,7 @@ int main(int argc, const char *argv[]) {
if (_confVideoFile) free(_confVideoFile);
if (_confScriptFile) free(_confScriptFile);
utilTraceEnd();
ap_free(&parser);
#ifdef _WIN32
getchar();

View file

@ -200,6 +200,17 @@ function createEmbeddedBinary() {
}
function createEmbeddedImage() {
local BASENAME=$1
if [[ ! -e ${BASENAME}.h ]]; then
xcf2png ${BASENAME}.xcf -o ${BASENAME}.png
createEmbeddedBinary ${BASENAME}.png ${BASENAME}.h ${BASENAME^^}_H
rm ${BASENAME}.png
fi
}
function createExtensionHeader() {
local FFMPEG=$1
local a=
@ -476,21 +487,22 @@ if [[ ! -e "${G_INSTALLED}/lib/everything.a" ]]; then
fi
# === Overlay Font ===
createEmbeddedBinary font.png font.h FONT_H
createEmbeddedImage font
# === Window Icon ===
createEmbeddedBinary icon.png icon.h ICON_H
createEmbeddedImage icon
# === Kangaroo Punch Logo ===
if [[ ! -e kangarooPunchLogo.h ]]; then
xcf2png kangarooPunchLogo.xcf -o kangarooPunchLogo.png
createEmbeddedBinary kangarooPunchLogo.png kangarooPunchLogo.h KANGAROOPUNCHLOGO_H
rm kangarooPunchLogo.png
fi
createEmbeddedImage kangarooPunchLogo
# === Singe Logo ===
if [[ ! -e singeLogo.h ]]; then
xcf2png singeLogo.xcf -o singeLogo.png
createEmbeddedBinary singeLogo.png singeLogo.h SINGELOGO_H
rm singeLogo.png
fi
createEmbeddedImage singeLogo
# === Laser Disc ===
createEmbeddedImage laserDisc
# === Magnifying Glass ===
createEmbeddedImage magnifyingGlass
# === "Indexing" Text ===
createEmbeddedImage indexing

View file

@ -40,6 +40,9 @@
#include "font.h"
#include "kangarooPunchLogo.h"
#include "singeLogo.h"
#include "laserDisc.h"
#include "magnifyingGlass.h"
#include "indexing.h"
#define AUDIO_MAX_VOLUME 63
@ -309,6 +312,7 @@ int32_t apiSingeQuit(lua_State *L);
int32_t apiSingeVersion(lua_State *L);
int32_t apiSingeSetGameName(lua_State *L);
int32_t apiSingeGetScriptPath(lua_State *L);
void doIndexDisplay(int32_t percent);
void doLogos(void);
void callLua(const char *func, const char *sig, ...);
void channelFinished(int channel);
@ -1849,6 +1853,116 @@ void channelFinished(int channel) {
}
void doIndexDisplay(int32_t percent) {
static int32_t oldW = 0;
static int32_t oldH = 0;
static int32_t screenW = 1280;
static int32_t screenH = 720;
static int32_t radius = 0;
static int32_t angle = 0;
static uint32_t nextUpdate = 0;
static uint32_t updateTicks = 0;
static SDL_Surface *surfDisc = NULL;
static SDL_Surface *surfGlass = NULL;
static SDL_Surface *surfIndex = NULL;
static SDL_Texture *texDisc = NULL;
static SDL_Texture *texGlass = NULL;
static SDL_Texture *texIndex = NULL;
SDL_Rect target;
int32_t vShift;
// If 'percent' is -1, we're setting this display up.
// 'percent' 0 to 100 is the actual display.
// 'percent' -2 shuts the display down.
if (percent == -1) {
// Setup
SDL_RenderGetLogicalSize(_renderer, &oldW, &oldH);
SDL_RenderSetLogicalSize(_renderer, screenW, screenH);
surfGlass = IMG_LoadPNG_RW(SDL_RWFromMem(magnifyingGlass_png, magnifyingGlass_png_len));
if (!surfGlass) utilDie("%s", IMG_GetError());
surfDisc = IMG_LoadPNG_RW(SDL_RWFromMem(laserDisc_png, laserDisc_png_len));
if (!surfDisc) utilDie("%s", IMG_GetError());
surfIndex = IMG_LoadPNG_RW(SDL_RWFromMem(indexing_png, indexing_png_len));
if (!surfIndex) utilDie("%s", IMG_GetError());
texDisc = SDL_CreateTextureFromSurface(_renderer, surfDisc);
if (!texDisc) utilDie("%s", SDL_GetError());
texGlass = SDL_CreateTextureFromSurface(_renderer, surfGlass);
if (!texGlass) utilDie("%s", SDL_GetError());
texIndex = SDL_CreateTextureFromSurface(_renderer, surfIndex);
if (!texIndex) utilDie("%s", SDL_GetError());
radius = surfDisc->w * 0.3;
updateTicks = 5;
nextUpdate = SDL_GetTicks() + updateTicks;
return;
}
if (percent == -2) {
// Shutdown
SDL_DestroyTexture(texDisc);
SDL_DestroyTexture(texGlass);
SDL_DestroyTexture(texIndex);
texDisc = NULL;
texGlass = NULL;
texIndex = NULL;
SDL_FreeSurface(surfDisc);
SDL_FreeSurface(surfGlass);
SDL_FreeSurface(surfIndex);
surfDisc = NULL;
surfGlass = NULL;
surfIndex = NULL;
SDL_RenderSetLogicalSize(_renderer, oldW, oldH);
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 255);
SDL_RenderClear(_renderer);
SDL_RenderPresent(_renderer);
return;
}
// Display animation
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 255);
SDL_RenderClear(_renderer);
// Draw "Indexing" text
vShift = surfIndex->h - 5;
target.x = (screenW * 0.5) - (surfIndex->w * 0.5);
target.y = screenH - vShift;
target.w = surfIndex->w;
target.h = surfIndex->h;
SDL_RenderCopy(_renderer, texIndex, NULL, &target);
// Draw laserdisc
target.x = (screenW * 0.5) - (surfDisc->w * 0.5);
target.y = (screenH * 0.5) - (surfDisc->h * 0.5) - vShift;
target.w = surfDisc->w;
target.h = surfDisc->h;
SDL_RenderCopy(_renderer, texDisc, NULL, &target);
// Draw magnifying glass
target.x = (surfDisc->w * 0.15) + (screenW * 0.5) - (surfGlass->w * 0.5) + cos(angle * M_PI / 180) * radius;
target.y = (surfDisc->h * 0.1) + (screenH * 0.5) - vShift - (surfGlass->h * 0.5) + sin(angle * M_PI / 180) * radius;
target.w = surfGlass->w;
target.h = surfGlass->h;
SDL_RenderCopy(_renderer, texGlass, NULL, &target);
// Update animation
if (SDL_GetTicks() > nextUpdate) {
angle++;
if (angle > 359) angle = 0;
nextUpdate = SDL_GetTicks() + updateTicks;
}
SDL_RenderPresent(_renderer);
}
void doLogos(void) {
int32_t i = 0;
int32_t w = 0;
@ -1878,10 +1992,10 @@ void doLogos(void) {
SDL_SetTextureAlphaMod(texKangaroo, i);
SDL_RenderCopy(_renderer, texKangaroo, NULL, NULL);
SDL_RenderPresent(_renderer);
SDL_Delay(5);
SDL_Delay(3);
}
SDL_Delay(1000);
SDL_Delay(750);
// Cross fade to Singe logo
for (i=0; i<256; i++) {
@ -1891,10 +2005,10 @@ void doLogos(void) {
SDL_SetTextureAlphaMod(texSinge, i);
SDL_RenderCopy(_renderer, texSinge, NULL, NULL);
SDL_RenderPresent(_renderer);
SDL_Delay(5);
SDL_Delay(3);
}
SDL_Delay(1000);
SDL_Delay(750);
// Fade to black
SDL_RenderSetLogicalSize(_renderer, surfSinge->w, surfSinge->h);
@ -1904,7 +2018,7 @@ void doLogos(void) {
SDL_SetTextureAlphaMod(texSinge, i);
SDL_RenderCopy(_renderer, texSinge, NULL, NULL);
SDL_RenderPresent(_renderer);
SDL_Delay(5);
SDL_Delay(3);
}
SDL_DestroyTexture(texSinge);
@ -2166,6 +2280,8 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) {
lua_register(_luaContext, "singeGetScriptPath", apiSingeGetScriptPath);
// Open main video file
doIndexDisplay(-1);
videoSetIndexCallback(doIndexDisplay);
if (_confIsFrameFile) {
_frameFileHandle = frameFileLoad(_confVideoFile, _confDataDir, (bool)_confStretchVideo, _renderer);
if (_frameFileHandle < 0) utilDie("Unable to load framefile: %s", _confVideoFile);
@ -2175,6 +2291,8 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) {
}
if (_videoHandle < 0) utilDie("Unable to load video file: %s", _confVideoFile);
videoSetVolume(_videoHandle, _confVolumeVldp, _confVolumeVldp);
videoSetIndexCallback(NULL);
doIndexDisplay(-2);
// Should we resize the window?
//***TODO***

View file

@ -31,7 +31,7 @@
// Don't forget to update singe.rc!
#define SINGE_VERSION 2.00
#define VERSION_STRING "v2.00b8"
#define VERSION_STRING "v2.00b9"
#define COPYRIGHT_END_YEAR "2020"

View file

@ -119,7 +119,10 @@ HEADERS += \
extensions.h \
font.h \
singeLogo.h \
kangarooPunchLogo.h
kangarooPunchLogo.h \
laserDisc.h \
magnifyingGlass.h \
indexing.h
SOURCES += \
$$ARGPARSER_SOURCES \

View file

@ -1,7 +1,7 @@
101 ICON "/tmp/icon.ico"
1 VERSIONINFO
FILEVERSION 2,0,0,8
PRODUCTVERSION 2,0,0,8
FILEVERSION 2,0,0,9
PRODUCTVERSION 2,0,0,9
BEGIN
BLOCK "StringFileInfo"
BEGIN
@ -9,12 +9,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Kangaroo Punch Studios"
VALUE "FileDescription", "Somewhat Interactive Nostalgic Game Engine"
VALUE "FileVersion", "2.00b8"
VALUE "FileVersion", "2.00b9"
VALUE "InternalName", "Singe"
VALUE "LegalCopyright", "Copyright 2006-2020 Scott C. Duensing"
VALUE "OriginalFilename", "singe.exe"
VALUE "ProductName", "Singe"
VALUE "ProductVersion", "2.00b8"
VALUE "ProductVersion", "2.00b9"
END
END
BLOCK "VarFileInfo"

View file

@ -62,7 +62,7 @@ typedef struct VideoPlayerS {
Uint16 audioFormat;
Uint32 lastTickTime;
Uint32 audioSilenceSize;
double audioAdjustment;
//double audioAdjustment;
Mix_Chunk *silenceChunk;
SDL_AudioStream *audioStream;
SDL_Texture *videoTexture;
@ -86,11 +86,12 @@ int FFMS_CC _indexCallBack(int64_t Current, int64_t Total, void *ICPrivate);
int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer);
static VideoPlayerT *_videoPlayerHash = NULL;
static int32_t _nextId = 0;
static int32_t _mixRate = -1;
static Uint8 _mixChannels = 0;
static SDL_AudioFormat _mixFormat = 0;
static videoIndexingCallback _indexingFunction = NULL;
static VideoPlayerT *_videoPlayerHash = NULL;
static int32_t _nextId = 0;
static int32_t _mixRate = -1;
static Uint8 _mixChannels = 0;
static SDL_AudioFormat _mixFormat = 0;
void _dequeueVideoAudio(int channel, void *stream, int bytes, void *udata) { // Callback. Not changing ints.
@ -135,10 +136,11 @@ void _dequeueVideoAudio(int channel, void *stream, int bytes, void *udata) { /
int FFMS_CC _indexCallBack(int64_t current, int64_t total, void *ICPrivate) { // Callback. Not changing int.
static int32_t lastPercent = 0;
int32_t thisPercent = 0;
static int32_t lastPercent = 0;
int32_t thisPercent = 0;
VideoPlayerT *v = (VideoPlayerT *)ICPrivate;
(void)ICPrivate; // Contains current VideoPlayerT
(void)v;
if ((current == 0) && (total == 0)) {
lastPercent = 0; // Reset
@ -146,8 +148,11 @@ int FFMS_CC _indexCallBack(int64_t current, int64_t total, void *ICPrivate) {
thisPercent = (int32_t)((double)current / (double)total * 100.0);
if (thisPercent != lastPercent) {
lastPercent = thisPercent;
utilSay("Indexing: %d%%", thisPercent);
//***TODO*** GUI
//utilSay("Indexing: %d%%", thisPercent);
// GUI
if (_indexingFunction) {
_indexingFunction(thisPercent);
}
}
}
@ -170,7 +175,7 @@ FFMS_Index *_createIndex(char *filename, char *indexPath, bool hasVideo, bool ha
}
}
if (!index) {
utilSay("Creating new index.");
//utilSay("Creating new index.");
indexer = FFMS_CreateIndexer(filename, &v->errInfo);
if (indexer == NULL) utilDie("%s", v->errInfo.Buffer);
if (hasAudio) FFMS_TrackTypeIndexSettings(indexer, FFMS_TYPE_AUDIO, 1, 0);
@ -500,6 +505,12 @@ int32_t videoSeek(int32_t playerHandle, int64_t seekFrame) {
}
int32_t videoSetIndexCallback(videoIndexingCallback callback) {
_indexingFunction = callback;
return 0;
}
int32_t videoSetVolume(int32_t playerHandle, int32_t leftPercent, int32_t rightPercent) {
VideoPlayerT *v = NULL;
@ -550,22 +561,16 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
int64_t threshold = 0;
VideoPlayerT *v = NULL;
// Get our player structure
HASH_FIND_INT(_videoPlayerHash, &playerHandle, v);
if (!v) utilDie("No video player at index %d in videoUpdate.", playerHandle);
// Audio drift limit
if (v->audioSource) {
threshold = (v->audioProps->SampleRate / 2);
} else {
threshold = 99999;
}
threshold = v->audioSource ? (v->audioProps->SampleRate / 2) : 99999;
// Handle video frames (and time)
if ((SDL_GetTicks() - v->lastTickTime >= v->frameDeltaTime) || (v->audioDelta > threshold) || v->resetTime) {
v->lastTickTime = SDL_GetTicks();
//if ((SDL_GetTicks() - v->lastTickTime >= v->frameDeltaTime) || (v->audioDelta > threshold) || v->resetTime) {
if ((SDL_GetTicks() - v->lastTickTime >= v->frameDeltaTime) || v->resetTime) {
if (v->frameData) {
SDL_UpdateTexture(v->videoTexture, NULL, v->frameData->Data[0], v->frameData->Linesize[0]);
@ -575,22 +580,6 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
result = v->frame;
v->framesPlayed++;
if (v->audioSource) {
// Did we trip the audio sync compensation?
if (v->audioDelta > threshold) {
// Adjust frame rate to try and match
if (v->audioDelta > 0) {
v->audioAdjustment += 0.000001;
} else {
v->audioAdjustment -= 0.000001;
}
}
// Used to determine if we should play two frames rapidly to catch up to audio
v->audioDelta = labs(v->audioPosition - (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate));
}
//utilSay("D %ld T %ld A %f", v->audioDelta, threshold, v->audioAdjustment);
v->frameData = FFMS_GetFrame(v->videoSource, v->frame, &v->errInfo);
if (v->frameData == NULL) utilDie("%s", v->errInfo.Buffer);
v->frameInfo = FFMS_GetFrameInfo(FFMS_GetTrackFromVideo(v->videoSource), v->frame);
@ -600,12 +589,14 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
if (v->playing) {
if (++v->frame >= v->videoProps->NumFrames) {
v->frame = 0;
v->frame = 0;
v->timestamp = 0;
v->resetTime = true;
}
}
v->lastTickTime = SDL_GetTicks();
if (v->resetTime) {
if (v->audioSource) {
SDL_AudioStreamClear(v->audioStream);
@ -621,6 +612,7 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
// Handle audio samples
if (v->audioSource) {
// Add more samples to queue?
if ((v->playing) && (SDL_AudioStreamAvailable(v->audioStream) < AUDIO_STREAM_LOW_WATERMARK) && (v->audioPosition < v->audioProps->NumSamples)) {
// Maximum samples we can read at a time
count = AUDIO_SAMPLE_PREREAD;
@ -637,6 +629,24 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
v->audioPosition += count;
}
}
// Used to determine if we should play two frames rapidly to catch up to audio
v->audioDelta = labs(v->audioPosition - (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate));
// Did we trip the audio sync compensation?
if (v->audioDelta > threshold) {
v->frameDeltaTime *= 0.5;
//utilSay("Adjusting delta %f", v->frameDeltaTime);
/*
// Adjust frame rate to try and match
if (v->audioDelta > 0) {
v->audioAdjustment += 0.000001;
} else {
v->audioAdjustment -= 0.000001;
}
*/
}
//utilSay("D %ld T %ld A %f F %f", v->audioDelta, threshold, v->audioAdjustment, v->frameDeltaTime);
}
return result;

View file

@ -29,6 +29,9 @@
#include "common.h"
typedef void (*videoIndexingCallback)(int32_t);
int32_t videoInit(void);
int32_t videoIsPlaying(int32_t playerHandle);
int64_t videoGetFrame(int32_t playerHandle);
@ -42,6 +45,7 @@ int32_t videoPause(int32_t playerHandle);
int32_t videoPlay(int32_t playerHandle);
int32_t videoQuit(void);
int32_t videoSeek(int32_t playerHandle, int64_t seekFrame);
int32_t videoSetIndexCallback(videoIndexingCallback callback);
int32_t videoSetVolume(int32_t playerHandle, int32_t leftPercent, int32_t rightPercent);
int32_t videoUnload(int32_t playerHandle);
int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture);