Compare commits

..
19 Commits
Author SHA1 Message Date
kichikuou 9c73a34c35 Version 2.11.7 2024-11-12 08:57:54 +09:00
kichikuou 36e1dc152b Fix crash when canceling menu with two-finger touch
Fixes #58.

It was a regression by commit eeeab6e.
2024-11-12 08:55:36 +09:00
kichikuou f786db5a50 Android: Upgrade SDL to 2.30.9 2024-11-12 08:51:36 +09:00
kichikuou c515b21afb Refactor ags_eSpriteCopyArea() 2024-09-01 21:44:11 +09:00
kichikuou d3db3fa83e sdl_effect: Implement EFFECT_PAN_IN_* and EFFECT_SKIP_LINE_*
This also fixes incorrect behavior of `CD 1` and `CD 2`.
2024-09-01 14:57:59 +09:00
kichikuou 86068b0ab9 Prefer single precision float 2024-09-01 08:25:34 +09:00
kichikuou de4f3ebb0d sdl_effect: Implement EFFECT_RASTER_BLEND (CD 5)
Used in Mugen Houyou's title logo.
2024-08-31 22:00:07 +09:00
kichikuou 187a3ced35 Separate ags_eSpriteCopyArea() from ags_eCopyArea() 2024-08-31 16:10:42 +09:00
kichikuou b7703b6270 CMake: Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP 2024-08-31 12:36:22 +09:00
kichikuou b7d0efbe55 README.md: Add note for Windows 2024-08-31 10:52:29 +09:00
kichikuou 02fe55eb93 Remove console message on quit 2024-08-31 10:39:00 +09:00
kichikuou 058789b435 Fix fade-in when screen refresh is disabled
Fade-in by `PF` or `PW` command was updating sdl_display even if screen
update was disabled by the `WZ 0` command.

In Rance 3, this caused a screen artifact immediately after selecting
"Game Start".

This was a regression introduced by commit 605de28.
2024-08-31 10:27:09 +09:00
kichikuou c5dcb20ac3 Simplify midifile.c 2024-08-21 12:20:01 +09:00
kichikuou cb08f7ca76 Windows CI: Build with portmidi
Also update README.md.
2024-08-19 12:58:46 +09:00
kichikuou 7a7d94e60f Remove raw and OSS sequencer MIDI mackends
In favor of PortMidi.
2024-08-19 12:46:56 +09:00
kichikuou b7681982a6 Rework midi.portmidi.c
Copied midi.rawmidi.c and adapted it to use PortMidi. Now the main
thread and the MIDI thread communicate via a message queue.
2024-08-19 11:07:00 +09:00
kichikuou fefaf6c343 Remove RPM spec files 2024-08-02 15:17:49 +09:00
kichikuou 42e994dfba emscripten: Use EM_ASYNC_JS 2024-07-31 08:59:33 +09:00
kichikuou a6aa50b5cf emscripten: Use MODULARIZE=1 2024-07-30 12:30:50 +09:00
47 changed files with 944 additions and 2074 deletions
+1
View File
@@ -31,6 +31,7 @@ jobs:
SDL2_ttf:p
SDL2_mixer:p
libwebp:p
portmidi:p
${{ matrix.deps }}
- name: Checkout
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## 2.11.7 - 2024-11-12
- Fixed crash when canceling menu with two-finger touch (#58)
- Fixed screen artifact in Rance 3 immediately after selecting "Game Start"
## 2.11.6 - 2024-07-22
- Fixed strange behavior when canceling the battle selection menu in Kichikuou Rance. (#56)
- Use system mouse cursors whenever possible. They look better on high dpi displays.
+6 -20
View File
@@ -1,11 +1,16 @@
cmake_minimum_required(VERSION 3.13)
# Rebuild external projects when download URL changes
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW)
endif()
project(xsystem35 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
enable_testing()
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(XSYSTEM35_VERSION "2.11.6")
set(XSYSTEM35_VERSION "2.11.7")
include(CheckSymbolExists)
include(FetchContent)
@@ -185,25 +190,6 @@ else()
list(APPEND SUMMARY_MIDI "SDL_mixer")
set(ENABLE_MIDI_SDLMIXER 1)
if (HAVE_SIGACTION)
list(APPEND SUMMARY_MIDI "raw")
set(MIDI_DEVICE "/dev/midi" CACHE STRING "midi device")
set(ENABLE_MIDI_RAWMIDI 1)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
check_symbol_exists(SNDCTL_SEQ_NRSYNTHS "machine/soundcard.h" ENABLE_MIDI_SEQMIDI)
elseif (CMAKE_SYSTEM_NAME MATCHES "(NetBSD|OpenBSD)")
check_symbol_exists(SNDCTL_SEQ_NRSYNTHS "soundcard.h" ENABLE_MIDI_SEQMIDI)
else ()
check_symbol_exists(SNDCTL_SEQ_NRSYNTHS "sys/soundcard.h" ENABLE_MIDI_SEQMIDI)
endif()
if (ENABLE_MIDI_SEQMIDI)
list(APPEND SUMMARY_MIDI "OSS sequencer")
set(SEQ_DEVICE "/dev/sequencer" CACHE STRING "sequencer device")
endif()
if (HAVE_PORTMIDI)
list(APPEND SUMMARY_MIDI "PortMidi")
set(ENABLE_MIDI_PORTMIDI 1)
+11 -5
View File
@@ -63,8 +63,14 @@ and examine or modify game variables. There are two ways to use the debugger:
## Installation
Prebuilt packages for Windows and Android can be downloaded from the
[Releases](https://github.com/kichikuou/xsystem35-sdl2/releases) page. For
other platforms, refer to the [Building](#building) section.
[Releases](https://github.com/kichikuou/xsystem35-sdl2/releases) page.
Note for Windows:
- The 64-bit version supports Windows 10 or later. For older versions of
Windows, please use the 32-bit version.
- Debugging is supported only in the 64-bit version.
For other platforms, refer to the [Building](#building) section.
## Running
### Windows
@@ -90,7 +96,7 @@ See [xsystem35 command manual](doc/xsystem35.6.adoc) for detailed usage.
### Linux (Debian / Ubuntu)
```bash
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libcjson-dev asciidoctor
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libportmidi-dev libcjson-dev asciidoctor
$ mkdir -p out/debug
$ cd out/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
@@ -102,7 +108,7 @@ $ make && make install
[Homebrew](https://brew.sh/) is required.
```bash
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp cjson asciidoctor
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp portmidi cjson asciidoctor
$ mkdir -p out/debug
$ cd out/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
@@ -114,7 +120,7 @@ $ make && make install
[MSYS2](https://www.msys2.org) is required.
```bash
$ pacman -S cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_ttf mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-libwebp mingw-w64-ucrt-x86_64-cjson
$ pacman -S cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_ttf mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-libwebp mingw-w64-ucrt-x86_64-portmidi mingw-w64-ucrt-x86_64-cjson
$ mkdir -p out/debug
$ cd out/debug
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
+2 -2
View File
@@ -16,8 +16,8 @@ android {
defaultConfig {
minSdkVersion 19
targetSdkVersion 34
versionCode 24
versionName "2.11.6" + gitRevision()
versionCode 25
versionName "2.11.7" + gitRevision()
externalNativeBuild {
cmake {
arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
+2 -2
View File
@@ -7,8 +7,8 @@ set(PROJECT_ROOT_DIR ../../..)
include(FetchContent)
FetchContent_Declare(
SDL
URL https://github.com/libsdl-org/SDL/releases/download/release-2.30.2/SDL2-2.30.2.tar.gz
URL_HASH SHA1=37a0557fc39460dc2a4fbbf162d95f115d2c9be2
URL https://github.com/libsdl-org/SDL/releases/download/release-2.30.9/SDL2-2.30.9.tar.gz
URL_HASH SHA1=9403df0573d47f62f2de074b582b87576bb4abbc
)
FetchContent_Declare(
SDL_ttf
+1 -1
View File
@@ -80,7 +80,7 @@
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:theme="@style/AppTheme"
android:hardwareAccelerated="true"
>
@@ -277,6 +277,7 @@ public class HIDDeviceManager {
0x044f, // Thrustmaster
0x045e, // Microsoft
0x0738, // Mad Catz
0x0b05, // ASUS
0x0e6f, // PDP
0x0f0d, // Hori
0x10f5, // Turtle Beach
@@ -590,7 +591,13 @@ public class HIDDeviceManager {
} else {
flags = 0;
}
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
if (Build.VERSION.SDK_INT >= 33 /* Android 14.0 (U) */) {
Intent intent = new Intent(HIDDeviceManager.ACTION_USB_PERMISSION);
intent.setPackage(mContext.getPackageName());
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, intent, flags));
} else {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
}
} catch (Exception e) {
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(deviceID, false);
@@ -38,6 +38,10 @@ public class SDL {
}
public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
loadLibrary(libraryName, mContext);
}
public static void loadLibrary(String libraryName, Context context) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
if (libraryName == null) {
throw new NullPointerException("No library name provided.");
@@ -53,10 +57,10 @@ public class SDL {
// To use ReLinker, just add it as a dependency. For more information, see
// https://github.com/KeepSafe/ReLinker for ReLinker's repository.
//
Class<?> relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
Class<?> relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
Class<?> contextClass = mContext.getClassLoader().loadClass("android.content.Context");
Class<?> stringClass = mContext.getClassLoader().loadClass("java.lang.String");
Class<?> relinkClass = context.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
Class<?> relinkListenerClass = context.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
Class<?> contextClass = context.getClassLoader().loadClass("android.content.Context");
Class<?> stringClass = context.getClassLoader().loadClass("java.lang.String");
// Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if
// they've changed during updates.
@@ -66,7 +70,7 @@ public class SDL {
// Actually load the library!
Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
loadMethod.invoke(relinkInstance, mContext, libraryName, null, null);
loadMethod.invoke(relinkInstance, context, libraryName, null, null);
}
catch (final Throwable e) {
// Fall back
@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
private static final String TAG = "SDL";
private static final int SDL_MAJOR_VERSION = 2;
private static final int SDL_MINOR_VERSION = 30;
private static final int SDL_MICRO_VERSION = 2;
private static final int SDL_MICRO_VERSION = 9;
/*
// Display InputType.SOURCE/CLASS of events and devices
//
@@ -89,7 +89,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
| InputDevice.SOURCE_CLASS_POSITION
| InputDevice.SOURCE_CLASS_TRACKBALL);
if (s2 != 0) cls += "Some_Unkown";
if (s2 != 0) cls += "Some_Unknown";
s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
@@ -163,7 +163,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (s == FLAG_TAINTED) src += " FLAG_TAINTED";
s2 &= ~FLAG_TAINTED;
if (s2 != 0) src += " Some_Unkown";
if (s2 != 0) src += " Some_Unknown";
Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src);
}
@@ -281,7 +281,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
// Load the .so
public void loadLibraries() {
for (String lib : getLibraries()) {
SDL.loadLibrary(lib);
SDL.loadLibrary(lib, this);
}
}
@@ -995,8 +995,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
/* No valid hint, nothing is explicitly allowed */
if (!is_portrait_allowed && !is_landscape_allowed) {
if (resizable) {
/* All orientations are allowed */
req = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
/* All orientations are allowed, respecting user orientation lock setting */
req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
} else {
/* Fixed window and nothing specified. Get orientation from w/h of created window */
req = (w > h ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
@@ -1005,8 +1005,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
/* At least one orientation is allowed */
if (resizable) {
if (is_portrait_allowed && is_landscape_allowed) {
/* hint allows both landscape and portrait, promote to full sensor */
req = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
/* hint allows both landscape and portrait, promote to full user */
req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
} else {
/* Use the only one allowed "orientation" */
req = (is_landscape_allowed ? orientation_landscape : orientation_portrait);
+2 -3
View File
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen">
<!-- Customize your theme here. -->
</style>
</resources>
-4
View File
@@ -5,16 +5,12 @@
#cmakedefine ENABLE_DEBUGGER @ENABLE_DEBUGGER@
#cmakedefine ENABLE_GTK @ENABLE_GTK@
#cmakedefine ENABLE_MIDI_RAWMIDI @ENABLE_MIDI_RAWMIDI@
#cmakedefine ENABLE_MIDI_SDLMIXER @ENABLE_MIDI_SDLMIXER@
#cmakedefine ENABLE_MIDI_SEQMIDI @ENABLE_MIDI_SEQMIDI@
#cmakedefine ENABLE_MIDI_PORTMIDI @ENABLE_MIDI_PORTMIDI@
#cmakedefine ENABLE_NLS @ENABLE_NLS@
#cmakedefine DEFAULT_PLAYLIST_PATH "@DEFAULT_PLAYLIST_PATH@"
#cmakedefine JOY_DEVICE "@JOY_DEVICE@"
#cmakedefine MIDI_DEVICE "@MIDI_DEVICE@"
#cmakedefine SEQ_DEVICE "@SEQ_DEVICE@"
#cmakedefine HAVE_GETLOGIN @HAVE_GETLOGIN@
#cmakedefine HAVE_MMAP @HAVE_MMAP@
-9
View File
@@ -47,18 +47,9 @@ finds System 3.x game files (*.ALD) from the current directory.
Load the CD playlist from _file_. The playlist is a text file with one
filename per line, in the order of CD tracks. See <<FILES>> section for details.
*-devmidi* _device_::
Path to the midi device.
*-Me*::
Use SDL_mixer for MIDI playback.
*-Mr*::
Use raw MIDI device for MIDI playback.
**-Ms**_device_number_::
Use sequencer device of the given number for MIDI playback.
**-Mp**_device_number_::
Use ALSA (via PortMidi) for MIDI playback.
+1 -1
View File
@@ -58,7 +58,7 @@ int nt_sp_eupdate(int no, int time, int cancel) {
int edtime = curtime + time;
while ((curtime = sdl_getTicks()) < edtime) {
sdl_effect_step(eff, (double)(curtime - sttime) / (edtime - sttime));
sdl_effect_step(eff, (float)(curtime - sttime) / (edtime - sttime));
int rest = 16 - (sdl_getTicks() - curtime);
int key = sys_keywait(rest, cancel ? KEYWAIT_CANCELABLE : KEYWAIT_NONCANCELABLE);
if (cancel && key)
+10 -8
View File
@@ -39,10 +39,12 @@
#include "sdl_core.h"
#include "randMT.h"
typedef void entrypoint (double step, int p1, int p2, int *retx, int *rety);
#define M_PIf ((float)M_PI)
typedef void entrypoint (float step, int p1, int p2, int *retx, int *rety);
// 上下左右方向の揺らし
static void quake0(double step, int ampx, int ampy, int *adjx, int *adjy) {
static void quake0(float step, int ampx, int ampy, int *adjx, int *adjy) {
static int i = 0;
*adjx = (int)(genrand() * ampx/2);
@@ -53,12 +55,12 @@ static void quake0(double step, int ampx, int ampy, int *adjx, int *adjy) {
}
// 回転の揺らし
static void quake1(double curstep, int diam, int round, int *adjx, int *adjy) {
double R = (1 - curstep) * diam / 2;
double th = curstep * 2 * M_PI * round;
static void quake1(float curstep, int diam, int round, int *adjx, int *adjy) {
float R = (1 - curstep) * diam / 2;
float th = curstep * 2 * M_PIf * round;
*adjx = (int)(R * cos(th));
*adjy = (int)(R * sin(th));
*adjx = (int)(R * cosf(th));
*adjy = (int)(R * sinf(th));
}
/*
@@ -83,7 +85,7 @@ int sp_quake_screen(int type, int p1, int p2, int time, int cancel) {
while ((curtime = sdl_getTicks()) < edtime) {
int adjx, adjy;
cb[type]((double)(curtime - sttime)/(edtime - sttime), p1, p2, &adjx, &adjy);
cb[type]((float)(curtime - sttime)/(edtime - sttime), p1, p2, &adjx, &adjy);
ags_setViewArea(adjx, adjy, sf0->width, sf0->height);
ags_updateFull();
+1 -1
View File
@@ -59,7 +59,7 @@ int sp_eupdate(int type, int time, int cancel) {
int edtime = curtime + time * 10;
while ((curtime = sdl_getTicks()) < edtime) {
sdl_effect_step(eff, (double)(curtime - sttime) / (edtime - sttime));
sdl_effect_step(eff, (float)(curtime - sttime) / (edtime - sttime));
int rest = 16 - (sdl_getTicks() - curtime);
int key = sys_keywait(rest, cancel ? KEYWAIT_CANCELABLE : KEYWAIT_NONCANCELABLE);
if (cancel && key)
+1 -1
View File
@@ -129,7 +129,7 @@ void spev_move_setup(void* data, void* userdata) {
// speed から timeへ
int dx = sp->move.to.x - sp->loc.x;
int dy = sp->move.to.y - sp->loc.y;
int d = (int)sqrt(dx*dx+dy*dy);
int d = (int)sqrtf(dx*dx+dy*dy);
sp->move.time = d * 100 / sp->move.speed;
}
+6 -5
View File
@@ -112,9 +112,6 @@ elseif (ANDROID)
target_sources(xsystem35 PRIVATE midi.android.c)
else()
target_sources(xsystem35 PRIVATE midi.sdlmixer.c)
if (ENABLE_MIDI_RAWMIDI)
target_sources(xsystem35 PRIVATE midi.rawmidi.c midifile.c)
endif()
if (ENABLE_MIDI_PORTMIDI)
target_sources(xsystem35 PRIVATE midi.portmidi.c midifile.c)
endif()
@@ -159,15 +156,19 @@ if (EMSCRIPTEN)
target_link_options(xsystem35 PRIVATE
-sENVIRONMENT=web
-sMODULARIZE=1
-sEXPORT_ES6=1
-sASYNCIFY=1
-sASYNCIFY_IGNORE_INDIRECT=1
-sASYNCIFY_REMOVE=SDL_Delay
-sASYNCIFY_IMPORTS=muspcm_load_no,muspcm_load_data,muspcm_load_mixlr,muspcm_waitend,wait_vsync,load_mincho_font
-sASYNCIFY_IMPORTS=wait_vsync
-sASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite
-sALLOW_MEMORY_GROWTH=1
-sNO_EXIT_RUNTIME=1
-sEXPORTED_FUNCTIONS=_main,_malloc
-sEXPORTED_RUNTIME_METHODS=getValue,addRunDependency,removeRunDependency)
-sEXPORTED_RUNTIME_METHODS=FS,IDBFS,getValue,addRunDependency,removeRunDependency
--emit-tsd=xsystem35.d.ts
)
elseif (ANDROID)
target_link_libraries(xsystem35 PRIVATE ${ndk_log})
+17 -28
View File
@@ -370,15 +370,6 @@ void ags_putRegion(void *region, int x, int y) {
sdl_putRegion(region, x, y);
}
void ags_copyRegion(void *region, int sx, int sy , int w, int h, int dx, int dy) {
if (region == NULL) return;
if (!ags_check_param_xy(&dx, &dy)) return;
if (!ags_check_param(&dx, &dy, &w, &h)) return;
sdl_CopyRegion(region, sx, sy, w, h, dx, dy);
}
void ags_delRegion(void *region) {
if (region == NULL) return;
@@ -552,7 +543,7 @@ void ags_runEffect(int duration_ms, boolean cancelable, ags_EffectStepFunc step,
unsigned wflags = cancelable ? KEYWAIT_CANCELABLE : KEYWAIT_NONCANCELABLE;
int start = sdl_getTicks();
for (int t = 0; t < duration_ms; t = sdl_getTicks() - start) {
step(arg, (double)t / duration_ms);
step(arg, (float)t / duration_ms);
int key = sys_keywait(start + t + 16 - sdl_getTicks(), wflags);
if (cancelable && key) {
nact->waitcancel_key = key;
@@ -575,27 +566,26 @@ static void fade(int duration, boolean cancelable, enum sdl_effect_type type) {
}
void ags_fadeIn(int rate, boolean flag) {
int duration = rate * 16 * 1000 / 60;
if (!need_update)
duration = 0;
fade_outed = FALSE;
if (nact->ags.world_depth == 8)
sdl_setPalette(nact->ags.pal, 0, 256);
if (!need_update)
return;
int duration = rate * 16 * 1000 / 60;
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_FADEIN : EFFECT_DITHERING_FADEIN);
sdl_updateAll(&nact->ags.view_area);
}
void ags_fadeOut(int rate, boolean flag) {
int duration = rate * 16 * 1000 / 60;
if (!need_update || fade_outed)
duration = 0;
if (need_update && !fade_outed) {
int duration = rate * 16 * 1000 / 60;
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_FADEOUT : EFFECT_DITHERING_FADEOUT);
}
fade_outed = TRUE;
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_FADEOUT : EFFECT_DITHERING_FADEOUT);
if (nact->ags.world_depth == 8) {
Color pal[256];
memset(&pal, 0, sizeof(pal));
@@ -604,27 +594,26 @@ void ags_fadeOut(int rate, boolean flag) {
}
void ags_whiteIn(int rate, boolean flag) {
int duration = rate * 16 * 1000 / 60;
if (!need_update)
duration = 0;
fade_outed = FALSE;
if (nact->ags.world_depth == 8)
sdl_setPalette(nact->ags.pal, 0, 256);
if (!need_update)
return;
int duration = rate * 16 * 1000 / 60;
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_WHITEIN : EFFECT_DITHERING_WHITEIN);
sdl_updateAll(&nact->ags.view_area);
}
void ags_whiteOut(int rate, boolean flag) {
int duration = rate * 16 * 1000 / 60;
if (!need_update || fade_outed)
duration = 0;
if (need_update && !fade_outed) {
int duration = rate * 16 * 1000 / 60;
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_WHITEIN : EFFECT_DITHERING_WHITEOUT);
}
fade_outed = TRUE;
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_WHITEIN : EFFECT_DITHERING_WHITEOUT);
if (nact->ags.world_depth == 8) {
Color pal[256];
memset(&pal, 255, sizeof(pal));
+3 -3
View File
@@ -167,7 +167,6 @@ extern void ags_changeColorArea(int x, int y, int w, int h, int dst, int src, in
extern void* ags_saveRegion(int x, int y, int w, int h);
extern void ags_restoreRegion(void *region, int x, int y);
extern void ags_putRegion(void *region, int x, int y);
extern void ags_copyRegion(void *region, int sx, int sy, int w,int h,int dx,int dy);
extern void ags_delRegion(void *region);
extern MyRectangle ags_drawString(int x, int y, const char *src, int col);
@@ -178,7 +177,8 @@ extern void ags_copyArea_transparent(int sx, int sy, int w, int h, int dx, int d
extern void ags_copyArea_alphaLevel(int sx, int sy, int w, int h, int dx, int dy, int lv);
extern void ags_copyArea_alphaBlend(int sx, int sy, int w, int h, int dx, int dy, int lv);
extern MyRectangle ags_floodFill(int x, int y, int col);
extern void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int type, int opt, boolean flg, int spCol);
extern void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt, bool cancel);
extern void ags_eSpriteCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt, bool cancel, int spCol);
/* alpha channel 操作 */
extern void ags_copyFromAlpha(int sx, int sy, int w, int h, int dx, int dy, ALPHA_DIB_COPY_TYPE flg);
@@ -217,7 +217,7 @@ extern void ags_setAntialiasedStringMode(boolean mode);
extern boolean ags_getAntialiasedStringMode();
extern void ags_autorepeat(boolean enable);
typedef void (*ags_EffectStepFunc)(void *, double);
typedef void (*ags_EffectStepFunc)(void *, float);
void ags_runEffect(int duration_ms, boolean cancelable, ags_EffectStepFunc step, void *arg);
#define RMASK16 0xf800
+1 -1
View File
@@ -969,7 +969,7 @@ struct grEffectMoveView_data {
int target_y;
};
static void grEffectMoveView_step(void *data, double progress) {
static void grEffectMoveView_step(void *data, float progress) {
struct grEffectMoveView_data *d = data;
int x = d->origin_x + (d->target_x - d->origin_x) * progress;
int y = d->origin_y + (d->target_y - d->origin_y) * progress;
+2 -2
View File
@@ -137,7 +137,7 @@ void commandCE() {
int option = getCaliValue();
int wait_flag = getCaliValue();
ags_eCopyArea(src_x, src_y, width, height, dst_x, dst_y, effect_sw, option, wait_flag, -1);
ags_eCopyArea(src_x, src_y, width, height, dst_x, dst_y, effect_sw, option, wait_flag);
if (wait_flag == 1) {
sysVar[0] = nact->waitcancel_key;
@@ -167,7 +167,7 @@ void commandCD() {
int wait_flag = getCaliValue();
int color = getCaliValue();
ags_eCopyArea(src_x, src_y, width, height, dst_x, dst_y, effect_sw, option, wait_flag, color);
ags_eSpriteCopyArea(src_x, src_y, width, height, dst_x, dst_y, effect_sw, option, wait_flag, color);
if (wait_flag == 1) {
sysVar[0] = nact->waitcancel_key;
+1 -1
View File
@@ -75,7 +75,7 @@ void commandNR() {
int var1 = getCaliValue();
int *var2 = getCaliVariable();
*var2 = (int)sqrt(var1);
*var2 = (int)sqrtf(var1);
DEBUG_COMMAND("NR %d,%d:", var1, *var2);
}
+54 -149
View File
@@ -54,84 +54,6 @@ static void eCopyUpdateArea(int sx, int sy, int w, int h, int dx, int dy) {
sdl_updateArea(&src, &dst);
}
static int eCopyArea1(int dx, int dy, int w, int h, int opt) {
int y, key = 0, cnt;
int waitcnt = opt == 0 ? 20 : opt;
cnt = sdl_getTicks();
for (y = 0; y < h - 24; y += 24) {
cnt += waitcnt;
eCopyUpdateArea(dx, dy + h - y, w, y, dx, dy);
EC_WAIT;
}
eCopyUpdateArea(dx, dy, w, h, dx, dy);
return key;
}
static int eCopyArea2(int dx, int dy, int w, int h, int opt) {
int y, key = 0, cnt;
int waitcnt = opt == 0 ? 20 : opt;
cnt = sdl_getTicks();
for (y = 0; y < h - 24; y += 24) {
cnt += waitcnt;
eCopyUpdateArea(dx, dy , w, y, dx, dy + h - y);
EC_WAIT;
}
eCopyUpdateArea(dx, dy, w, h, dx, dy);
return key;
}
static int eCopyArea3(int dx, int dy, int w, int h, int opt) {
int y1, y2, key = 0, cnt;
int waitcnt = opt == 0 ? 3 : opt;
if (h % 2) {
h--;
eCopyUpdateArea(dx , dy + h, w, 1, dx, dy + h);
}
y1 = dy;
y2 = dy + h - 1;
cnt = sdl_getTicks();
while (h > 0) {
cnt += waitcnt;
eCopyUpdateArea(dx, y1, w, 1, dx, y1);
eCopyUpdateArea(dx, y2, w, 1, dx, y2);
y1 += 2;
y2 -= 2;
h -= 2;
EC_WAIT;
}
eCopyUpdateArea(dx, dy, w, h, dx, dy);
return key;
}
static int eCopyArea4(int dx, int dy, int w, int h, int opt) {
int x1,x2, key = 0, cnt;
int waitcnt = opt == 0 ? 3 : opt;
if (w % 2) {
w--;
eCopyUpdateArea(dx + w , dy, 1, h, dx + w, dy);
}
x1 = dx;
x2 = dx + w - 1;
cnt = sdl_getTicks();
while (w > 0) {
cnt += waitcnt;
eCopyUpdateArea(x1, dy, 1, h, x1, dy);
eCopyUpdateArea(x2, dy, 1, h, x2, dy);
x1 += 2;
x2 -= 2;
w -= 2;
EC_WAIT;
}
eCopyUpdateArea(dx, dy, w, h, dx, dy);
return key;
}
static int eCopyArea5(int sx, int sy, int w, int h, int dx, int dy, int opt) {
int i, x, y, key = 0, cnt;
int waitcnt = opt == 0 ? 20 : opt;
@@ -279,7 +201,7 @@ static int eCopyArea23(int sx, int sy, int w, int h, int dx, int dy, int opt) {
return key;
}
static int eCopyArea1000(int sx, int sy, int w, int h, int dx, int dy, int opt, int spCol) {
static int eCopyArea1000(int sx, int sy, int w, int h, int dx, int dy, int opt) {
/* XOR */
return sys_getInputInfo();
}
@@ -297,40 +219,17 @@ static int eCopyArea2001(int sx, int sy, int w, int h, int dx, int dy, int opt)
return sys_getInputInfo();
}
static int eCopyArea5sp(int sx, int sy, int w, int h, int dx, int dy, int opt) {
int i, j, k, key = 0, cnt;
int st_i, ed_i;
int waitcnt = opt == 0 ? 50 : opt * 10;
int step[200];
void *save = ags_saveRegion(dx - 50, dy, w + 100, h);
for (i = 0; i < 200; i++) {
step[i] = 50 * sin((2 * M_PI * i) / 50);
}
cnt = sdl_getTicks();
for (i = 150; i < h + 200; i++) {
cnt += waitcnt;
st_i = max(0, i - 200);
ed_i = h;
ags_copyRegion(save, 0, st_i, w + 100, ed_i - st_i, dx - 50, dy + st_i);
for (j = st_i, k = 0; j < ed_i; j++, k++) {
ags_copyArea_shadow(sx , sy + j, w, 1,
dx + step[(k + max(0, 200 - i)) % 200],
dy + j);
}
ags_updateArea(dx - 50, dy + st_i, w + 100, ed_i - st_i);
EC_WAIT;
}
ags_delRegion(save);
return key;
}
static int duration(enum nact_effect effect, int opt, SDL_Rect *rect) {
switch (effect) {
case NACT_EFFECT_PAN_IN_DOWN:
case NACT_EFFECT_PAN_IN_UP:
return (opt ? opt : 20) * (rect->h / 24);
case NACT_EFFECT_SKIP_LINE_UP_DOWN:
return (opt ? opt : 3) * (rect->h / 2);
case NACT_EFFECT_SKIP_LINE_LR_RL:
return (opt ? opt : 3) * (rect->w / 2);
case NACT_SP_EFFECT_RASTER_BLEND:
return (opt ? opt : 25) * rect->h;
case NACT_EFFECT_ZOOM_IN:
return opt ? opt * 64 : 500;
case NACT_EFFECT_BLIND_DOWN:
@@ -360,7 +259,7 @@ static int duration(enum nact_effect effect, int opt, SDL_Rect *rect) {
return (opt ? opt : 100) * 8;
case NACT_EFFECT_CIRCLE_WIPE_OUT:
case NACT_EFFECT_CIRCLE_WIPE_IN:
return (opt ? opt : 20) * sqrt(rect->w * rect->w + rect->h * rect->h) / 40;
return (opt ? opt : 20) * sqrtf(rect->w * rect->w + rect->h * rect->h) / 40;
case NACT_EFFECT_FADEIN:
case NACT_EFFECT_WHITEIN:
case NACT_EFFECT_FADEOUT:
@@ -402,12 +301,12 @@ static int duration(enum nact_effect effect, int opt, SDL_Rect *rect) {
return 1000;
}
void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt, boolean cancel, int spCol) {
void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt, bool cancel) {
int ret = 0;
#if 0
NOTICE("ec_area sx %d sy %d w %d h %d dx %d dy %d sw %d opt %d spc %d cancel %s",
sx, sy, w, h, dx, dy, sw, opt, spCol, cancel ? "True" : "False");
NOTICE("ags_eCopyArea sx %d sy %d w %d h %d dx %d dy %d sw %d opt %d cancel %s",
sx, sy, w, h, dx, dy, sw, opt, cancel ? "True" : "False");
#endif
if (!ags_check_param(&sx, &sy, &w, &h)) return;
if (!ags_check_param(&dx, &dy, &w, &h)) return;
@@ -430,7 +329,7 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt
enum sdl_effect_type sdl_effect = from_nact_effect(sw);
if (sdl_effect != EFFECT_INVALID) {
SDL_Rect rect = { dx - nact->ags.view_area.x, dy - nact->ags.view_area.y, w, h };
struct sdl_effect *eff = sdl_effect_init(&rect, sdl_getDIB(), dx, dy, sdl_getDIB(), sx, sy, from_nact_effect(sw));
struct sdl_effect *eff = sdl_effect_init(&rect, sdl_getDIB(), dx, dy, sdl_getDIB(), sx, sy, sdl_effect);
ags_runEffect(duration(sw, opt, &rect), cancel, (ags_EffectStepFunc)sdl_effect_step, eff);
sdl_effect_finish(eff);
@@ -455,19 +354,11 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt
ecp_cancel = cancel;
switch(sw) {
case 1:
case 2:
case 3:
case 4:
case 6:
case 16:
case 17:
case 54:
if (spCol == -1) {
ags_copyArea(sx, sy, w, h, dx, dy);
} else {
ags_copyAreaSP(sx, sy, w, h, dx, dy, spCol);
}
ags_copyArea(sx, sy, w, h, dx, dy);
{
MyRectangle r = {dx, dy, w, h}, update;
SDL_IntersectRect(&nact->ags.view_area, &r, &update);
@@ -477,24 +368,8 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt
}
switch(sw) {
case 1:
ret = eCopyArea1(dx, dy, w, h, opt);
break;
case 2:
ret = eCopyArea2(dx, dy, w, h, opt);
break;
case 3:
ret = eCopyArea3(dx, dy, w, h, opt);
break;
case 4:
ret = eCopyArea4(dx, dy, w, h, opt);
break;
case 5:
if (spCol == -1) {
ret = eCopyArea5(sx, sy, w, h, dx, dy, opt);
} else {
ret = eCopyArea5sp(sx, sy, w, h, dx, dy, opt);
}
ret = eCopyArea5(sx, sy, w, h, dx, dy, opt);
break;
case 6:
ret = eCopyArea6(dx, dy, w, h, opt);
@@ -517,13 +392,7 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt
case 1000:
if (nact->ags.world_depth != 8) return;
ret = eCopyArea1000(sx, sy, w, h, dx, dy, opt, spCol);
break;
case NACT_EFFECT_PALETTE_SHIFT:
if (nact->ags.world_depth != 8 || spCol == -1) return;
ags_copyPaletteShift(sx, sy, w, h, dx, dy, spCol);
ags_updateArea(dx, dy, w, h);
ret = sys_getInputInfo();
ret = eCopyArea1000(sx, sy, w, h, dx, dy, opt);
break;
case 2000:
if (nact->ags.world_depth == 8) return;
@@ -540,3 +409,39 @@ void ags_eCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt
}
nact->waitcancel_key = ret;
}
void ags_eSpriteCopyArea(int sx, int sy, int w, int h, int dx, int dy, int sw, int opt, bool cancel, int spCol) {
#if 0
NOTICE("ags_eSpriteCopyArea sx %d sy %d w %d h %d dx %d dy %d sw %d opt %d spc %d cancel %s",
sx, sy, w, h, dx, dy, sw, opt, spCol, cancel ? "True" : "False");
#endif
if (!ags_check_param(&sx, &sy, &w, &h)) return;
if (!ags_check_param(&dx, &dy, &w, &h)) return;
nact->waitcancel_key = 0;
if (sw == NACT_EFFECT_PALETTE_SHIFT) {
if (nact->ags.world_depth != 8) return;
ags_copyPaletteShift(sx, sy, w, h, dx, dy, spCol);
ags_updateArea(dx, dy, w, h);
nact->waitcancel_key = sys_getInputInfo();
return;
}
enum sdl_effect_type type = from_nact_sprite_effect(sw);
if (type == EFFECT_INVALID) {
WARNING("Invalid effect: %d", sw);
return;
}
SDL_Rect rect = { dx - nact->ags.view_area.x, dy - nact->ags.view_area.y, w, h };
struct sdl_effect *eff = sdl_sprite_effect_init(&rect, dx, dy, sx, sy, spCol, type);
ags_runEffect(duration(sw, opt, &rect), cancel, (ags_EffectStepFunc)sdl_effect_step, eff);
sdl_effect_finish(eff);
// Actual copy.
if (sw == 5) {
ags_copyArea_shadow(sx, sy, w, h, dx, dy);
} else {
ags_copyAreaSP(sx, sy, w, h, dx, dy, spCol);
}
ags_updateArea(dx, dy, w, h);
}
+11
View File
@@ -22,6 +22,11 @@
// Effect types of the CE/CD command.
enum nact_effect {
NACT_EFFECT_PAN_IN_DOWN = 1,
NACT_EFFECT_PAN_IN_UP = 2,
NACT_EFFECT_SKIP_LINE_UP_DOWN = 3,
NACT_EFFECT_SKIP_LINE_LR_RL = 4,
NACT_SP_EFFECT_RASTER_BLEND = 5, // CD 5
NACT_EFFECT_WIPE_IN = 7,
NACT_EFFECT_WIPE_OUT = 8,
NACT_EFFECT_ZOOM_IN = 10,
@@ -124,6 +129,10 @@ enum sdl_effect_type {
EFFECT_DITHERING_FADEIN,
EFFECT_DITHERING_WHITEOUT,
EFFECT_DITHERING_WHITEIN,
EFFECT_PAN_IN_DOWN,
EFFECT_PAN_IN_UP,
EFFECT_SKIP_LINE_UP_DOWN,
EFFECT_SKIP_LINE_LR_RL,
EFFECT_WIPE_IN,
EFFECT_WIPE_OUT,
EFFECT_WIPE_LR,
@@ -173,9 +182,11 @@ enum sdl_effect_type {
EFFECT_POLYGON_ROTATE_X_CW,
EFFECT_ZIGZAG_CROSSFADE,
EFFECT_MAGNIFY,
EFFECT_RASTER_BLEND,
};
enum sdl_effect_type from_nact_effect(enum nact_effect effect);
enum sdl_effect_type from_nact_sprite_effect(enum nact_effect effect);
enum sdl_effect_type from_sact_effect(enum sact_effect effect);
#endif /* __EFFECT_H__ */
+2 -4
View File
@@ -235,9 +235,7 @@ boolean font_get_antialias(void) {
}
#ifdef __EMSCRIPTEN__
EM_JS(int, load_mincho_font, (void), {
return Asyncify.handleSleep(function(wakeUp) {
xsystem35.load_mincho_font().then(wakeUp);
});
EM_ASYNC_JS(int, load_mincho_font, (void), {
await xsystem35.load_mincho_font();
});
#endif
+3 -3
View File
@@ -23,7 +23,7 @@
#include "portab.h"
#include "midi.h"
static int midi_initilize(char *pname, int subdev);
static int midi_initialize(int subdev);
static int midi_exit(void);
static int midi_reset(void);
static int midi_start(int no, int loop, char *data, int datalen);
@@ -40,7 +40,7 @@ static boolean midi_fading();
#define midi midi_android
mididevice_t midi = {
midi_initilize,
midi_initialize,
midi_exit,
midi_reset,
midi_start,
@@ -56,7 +56,7 @@ mididevice_t midi = {
midi_fading
};
static int midi_initilize(char *pname, int subdev) {
static int midi_initialize(int subdev) {
return OK;
}
+4 -32
View File
@@ -23,13 +23,11 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portab.h"
#include "midi.h"
static char *dev;
static char default_mode = 'e';
static int subdev = -1;
@@ -45,10 +43,6 @@ extern mididevice_t midi_android;
extern mididevice_t midi_sdlmixer;
#endif
#if defined(ENABLE_MIDI_RAWMIDI) || defined(ENABLE_MIDI_SEQMIDI)
extern mididevice_t midi_rawmidi;
#endif
#ifdef ENABLE_MIDI_PORTMIDI
extern mididevice_t midi_portmidi;
#endif
@@ -57,30 +51,23 @@ int midi_init(mididevice_t *midi) {
int ret = NG;
switch(default_mode) {
case 'r':
case 's':
#if defined(ENABLE_MIDI_RAWMIDI) || defined(ENABLE_MIDI_SEQMIDI)
memcpy(midi, &midi_rawmidi, sizeof(mididevice_t));
ret = midi->init(dev, subdev);
#endif
break;
case 'e':
#ifdef __EMSCRIPTEN__
ret = midi_emscripten.init(NULL, 0);
ret = midi_emscripten.init(0);
memcpy(midi, &midi_emscripten, sizeof(mididevice_t));
#endif
#ifdef __ANDROID__
ret = midi_android.init(NULL, 0);
ret = midi_android.init(0);
memcpy(midi, &midi_android, sizeof(mididevice_t));
#endif
#ifdef ENABLE_MIDI_SDLMIXER
ret = midi_sdlmixer.init(NULL, 0);
ret = midi_sdlmixer.init(0);
memcpy(midi, &midi_sdlmixer, sizeof(mididevice_t));
#endif
break;
case 'p':
#ifdef ENABLE_MIDI_PORTMIDI
ret = midi_portmidi.init(NULL, subdev);
ret = midi_portmidi.init(subdev);
memcpy(midi, &midi_portmidi, sizeof(mididevice_t));
#endif
case '0':
@@ -90,27 +77,12 @@ int midi_init(mididevice_t *midi) {
return ret;
}
void midi_set_devicename(const char *name) {
if (dev) free(dev);
if (0 == strcmp("none", name)) dev = NULL;
else dev = strdup(name);
}
void midi_set_output_device(int mode) {
switch(mode & 0x7f) {
case 'e':
/* external player */
default_mode = 'e';
break;
case 'r':
/* raw midi mode */
default_mode = 'r';
break;
case 's':
/* sequencer midi mode */
default_mode = 's';
subdev = mode >> 8;
break;
case 'p':
/* portmidi midi mode */
default_mode = 'p';
+2 -2
View File
@@ -24,7 +24,7 @@
#include "portab.h"
#include "midi.h"
static int midi_initilize(char *pname, int subdev) {
static int midi_initialize(int subdev) {
return OK;
}
@@ -96,7 +96,7 @@ EM_JS(boolean, midi_fading, (), {
});
mididevice_t midi_emscripten = {
midi_initilize,
midi_initialize,
midi_exit,
midi_reset,
midi_start,
+1 -2
View File
@@ -34,7 +34,7 @@ typedef struct {
typedef struct mididevice mididevice_t;
struct mididevice {
int (* init)(char *, int);
int (* init)(int);
int (* exit)(void);
int (* reset)(void);
// Play through the music loop times. If loop == 0, loops forever.
@@ -52,7 +52,6 @@ struct mididevice {
};
extern int midi_init(mididevice_t *);
extern void midi_set_devicename(const char *);
extern void midi_set_output_device(int mode);
#endif /* __MIDI_H__ */
+217 -289
View File
@@ -1,5 +1,10 @@
/*
* Copyright (C) 2021 bsdf <EMAILBEN145@gmail.com>
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
* 2021 bsdf <EMAILBEN145@gmail.com>
* 2024 kichikuou <KichikuouChrome@gmail.com>
*
* Based on midiplay+ by Daisuke NAGANO <breeze.nagano@nifty.ne.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,43 +22,36 @@
*
*/
#include <stdio.h>
#include <unistd.h>
#include "config.h"
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <portmidi.h>
#include <SDL_thread.h>
#include <SDL_timer.h>
#include <portmidi.h>
#include "portab.h"
#include "system.h"
#include "midi.h"
#include "midifile.h"
#include "msgqueue.h"
#define MIDI_LATENCY 20
static struct {
char midi_variable[128];
char midi_flag[128];
} flags;
typedef struct midievent midievent_t;
static int midi_thread(void *);
static int midi_initialize(char *devnm, int subdev);
static int midi_initialize(int subdev);
static int midi_exit(void);
static int midi_reset(void);
static int midi_start(int no, int loop, char *data, int datalen);
static int midi_stop();
static int midi_pause();
static int midi_unpause();
static int midi_stop(void);
static int midi_pause(void);
static int midi_unpause(void);
static int midi_getpos(midiplaystate *st);
static int midi_getflag(int mode, int idx);
static int midi_setflag(int mode, int idx, int val);
static void midi_allnotesoff();
static void midi_send_reset();
static void midi_settempo(midievent_t event);
static void midi_sync(midievent_t event);
static int midi_getflag(int mode, int index);
static int midi_setflag(int mode, int index, int val);
mididevice_t midi_portmidi = {
midi_initialize,
@@ -72,115 +70,252 @@ mididevice_t midi_portmidi = {
NULL
};
static boolean enabled = FALSE;
static PortMidiStream *stream;
static struct midiinfo *midi;
static PmDeviceID device_id;
static SDL_Thread *thread;
static struct msgq *queue;
static int start_time;
static SDL_Thread *thread;
static boolean thread_running = FALSE;
static boolean should_stop = FALSE;
static boolean should_pause = FALSE;
static boolean should_unpause = FALSE;
static boolean should_loop = FALSE;
static char cmd_pause[] = "pause";
static char cmd_unpause[] = "unpause";
static char cmd_stop[] = "stop";
static int midi_initialize(char *devnm, int subdev) {
NOTICE("midi_initialize: devnm = [%s] subdev = [%i]", devnm, subdev);
PmError err;
static void allnotesoff() {
for (int i = 0; i < 16; i++) {
Pm_WriteShort(stream, 0, Pm_Message(0xb0 + i, 0x7b, 0x00));
}
}
if ((err = Pm_Initialize()) != pmNoError) {
static void send_reset() {
for (int i = 0; i < 16; i++) {
Pm_WriteShort(stream, 0, Pm_Message(0xb0 + i, 0x78, 0x00));
Pm_WriteShort(stream, 0, Pm_Message(0xb0 + i, 0x79, 0x00));
}
return;
}
static void midi_write(struct midievent *event, uint32_t timestamp) {
Pm_WriteShort(stream, timestamp, event->data);
}
static PmTimestamp midi_time_proc(void *time_info) {
return SDL_GetTicks();
}
static uint32_t ticks2ms(int ticks, int division, unsigned int tempo) {
return ticks * tempo / (division * 1000);
}
static void *midi_mainloop(struct midiinfo *midi) {
int i = 0;
int ctick = 0;
int tempo = 500000;
uint32_t last_time = SDL_GetTicks();
void *cmd;
while (i < midi->nr_events) {
if (ctick < midi->event[i].ctime) {
int delta = midi->event[i].ctime - ctick;
uint32_t target_time = last_time + ticks2ms(delta, midi->division, tempo);
uint32_t current_time = SDL_GetTicks();
while (current_time < target_time) {
cmd = msgq_dequeue_timeout(queue, target_time - current_time);
if (cmd == cmd_stop)
return cmd;
if (cmd == cmd_pause) {
while (TRUE) {
cmd = msgq_dequeue(queue);
if (cmd == cmd_stop)
return cmd;
if (cmd == cmd_unpause)
break;
}
target_time += SDL_GetTicks() - current_time;
}
current_time = SDL_GetTicks();
}
last_time = target_time;
ctick = midi->event[i].ctime;
}
if (midi->event[i].type == MIDI_EVENT_NORMAL) {
midi_write(&midi->event[i], last_time);
i++;
} else if (midi->event[i].type == MIDI_EVENT_TEMPO) {
tempo = midi->event[i].data;
i++;
} else if (midi->event[i].type == MIDI_EVENT_SYS35) {
int vn1 = Pm_MessageData2(midi->event[i+1].data);
int vn2 = Pm_MessageData2(midi->event[i+2].data);
int vn3 = Pm_MessageData2(midi->event[i+3].data);
switch (vn1) {
case MIDI_SYS35_LABEL_DEFINITION:
i += MIDI_SYS35_EVENT_SIZE;
break;
case MIDI_SYS35_LABEL_JUMP:
allnotesoff();
i = midi->sys35_label[vn2];
ctick = midi->event[i].ctime;
break;
case MIDI_SYS35_FLAG_SET:
flags.midi_flag[vn2] = vn3;
i += MIDI_SYS35_EVENT_SIZE;
break;
case MIDI_SYS35_FLAG_JUMP:
if (flags.midi_flag[vn2] == 1) {
i = midi->sys35_label[vn3];
ctick = midi->event[i].ctime;
allnotesoff();
} else {
i += MIDI_SYS35_EVENT_SIZE;
}
break;
case MIDI_SYS35_VARIABLE_SET:
flags.midi_variable[vn2] = vn3;
i += MIDI_SYS35_EVENT_SIZE;
break;
case MIDI_SYS35_VARIABLE_JUMP:
if (--(flags.midi_variable[vn2]) == 0) {
i = midi->sys35_label[vn3];
ctick = midi->event[i].ctime;
allnotesoff();
} else {
i += MIDI_SYS35_EVENT_SIZE;
}
break;
}
} else {
WARNING("Unknown type of event %x (NEVER!).", midi->event[i].type);
}
}
return NULL;
}
static int midi_initialize(int subdev) {
enabled = FALSE;
PmError err = Pm_Initialize();
if (err != pmNoError) {
WARNING("%s", Pm_GetErrorText(err));
return NG;
}
int ndevices = Pm_CountDevices();
if (ndevices == 0 || subdev >= ndevices) {
for (int i = 0; i < ndevices; i++) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
NOTICE("MIDI #%d: interf=\"%s\", name=\"%s\", input=%d, output=%d",
i, info->interf, info->name, info->input, info->output);
}
if (subdev < 0 || subdev >= ndevices) {
WARNING("invalid midi device number");
return NG;
}
if ((err = Pm_OpenOutput(&stream, subdev, NULL, 0, NULL, NULL, 10)) != pmNoError) {
WARNING("%s", Pm_GetErrorText(err));
return NG;
}
device_id = subdev;
enabled = TRUE;
return OK;
}
static int midi_exit(void) {
NOTICE("midi_exit");
if (thread_running) {
if (enabled) {
midi_stop();
}
NOTICE("midi stopped");
Pm_Close(stream);
stream = NULL;
Pm_Terminate();
return OK;
}
static int midi_reset(void) {
if (thread_running) {
if (enabled) {
midi_stop();
}
return OK;
}
static int midi_thread(void *data) {
send_reset();
void *cmd = midi_mainloop(data);
send_reset();
SDL_Delay(MIDI_LATENCY);
mf_remove_midifile(data);
Pm_Close(stream);
stream = NULL;
while (cmd != cmd_stop)
cmd = msgq_dequeue(queue);
return 0;
}
/* no = 0~ */
static int midi_start(int no, int loop, char *data, int datalen) {
NOTICE("midi_start: no = %i loop = %i datalen = %i", no, loop, datalen);
should_stop = FALSE;
should_pause = FALSE;
should_unpause = FALSE;
should_loop = loop;
if (queue)
midi_stop();
if (thread_running) {
if (midi_stop() == NG) {
WARNING("error stopping midi thread");
return NG;
}
}
midi = mf_read_midifile(data, datalen);
if (midi == NULL) {
struct midiinfo *midi = mf_read_midifile(data, datalen);
if (!midi) {
WARNING("error reading midi file");
return NG;
}
thread = SDL_CreateThread(midi_thread, "PortMIDI", NULL);
if (!thread) {
WARNING("could not create midi thread");
PmError err = Pm_OpenOutput(&stream, device_id, NULL, 0, midi_time_proc, NULL, MIDI_LATENCY);
if (err != pmNoError) {
WARNING("Pm_OpenOutput failed: %s", Pm_GetErrorText(err));
mf_remove_midifile(midi);
return NG;
}
queue = msgq_new();
thread = SDL_CreateThread(midi_thread, "MIDI", midi);
start_time = SDL_GetTicks();
return OK;
}
static int midi_stop() {
NOTICE("midi_stop");
should_stop = TRUE;
static int midi_stop(void) {
if (!enabled || !queue) {
return OK;
}
msgq_enqueue(queue, cmd_stop);
SDL_WaitThread(thread, NULL);
thread = NULL;
msgq_free(queue);
queue = NULL;
return OK;
}
static int midi_pause() {
NOTICE("midi_pause");
should_pause = TRUE;
static int midi_pause(void) {
if (!enabled || !queue) return OK;
msgq_enqueue(queue, cmd_pause);
return OK;
}
static int midi_unpause() {
NOTICE("midi_unpause");
should_unpause = TRUE;
static int midi_unpause(void) {
if (!enabled || !queue) return OK;
msgq_enqueue(queue, cmd_unpause);
return OK;
}
static int midi_getpos(midiplaystate *st) {
NOTICE("midi_getpos");
if (!thread_running) {
if (!enabled || !queue) {
st->in_play = FALSE;
st->loc_ms = 0;
st->loc_ms = 0;
return OK;
}
if (!stream) {
midi_stop();
st->in_play = FALSE;
st->loc_ms = 0;
return OK;
}
@@ -190,230 +325,23 @@ static int midi_getpos(midiplaystate *st) {
return OK;
}
static int midi_getflag(int mode, int idx) {
NOTICE("midi_getflag: %i = %i", mode, idx);
static int midi_getflag(int mode, int index) {
if (mode == 0) {
/* flag */
return flags.midi_flag[idx];
}
else {
return flags.midi_flag[index];
} else {
/* variable */
return flags.midi_variable[idx];
return flags.midi_variable[index];
}
}
static int midi_setflag(int mode, int idx, int val) {
NOTICE("midi_setflag: %i %i = %i", mode, idx, val);
static int midi_setflag(int mode, int index, int val) {
if (mode == 0) {
/* flag */
return flags.midi_flag[idx] = val;
}
else {
flags.midi_flag[index] = val;
} else {
/* variable */
flags.midi_variable[idx] = val;
flags.midi_variable[index] = val;
}
return OK;
}
static uint64_t pc, tick, ctick, tempo, ppqn;
static void midi_write(midievent_t event) {
uint64_t ts = (event.ctime * ppqn) / 1000;
Pm_WriteShort(stream, ts, Pm_Message(event.data[0], event.data[1], event.data[2]));
pc++;
}
static void midi_allnotesoff() {
NOTICE("midi_allnotesoff");
for (int i = 0; i < 16; i++) {
Pm_WriteShort(stream, 0, Pm_Message(0xb0 + i, 0x7b, 0x00));
}
}
static void midi_send_reset() {
NOTICE("midi_send_reset");
for (int i = 0; i < 16; i++) {
Pm_WriteShort(stream, 0, Pm_Message(0xb0 + i, 0x78, 0x00));
Pm_WriteShort(stream, 0, Pm_Message(0xb0 + i, 0x79, 0x00));
}
}
static void midi_settempo(midievent_t event) {
int *p;
p = (int*)event.data;
tempo = (unsigned int)*p;
NOTICE("midi_settempo(%i)", tempo);
ppqn = tempo / midi->division;
pc++;
}
// the timing here feels a little ...off. it could just be that i've
// been listening way too hard and overanalyzing but there are a few
// things that don't feel right. i've tweaked this every way i can think of
// so any new ideas welcome.
static void midi_sync(midievent_t event) {
int delta = event.ctime - ctick;
// (delta * ppqn) SHOULD return the clock time in microseconds.
// the 1000 is subtracted to give portmidi some time to queue the events
uint64_t stime = (uint64_t) (delta * ppqn) - 1000;
if (stime > 0) {
struct timespec req;
// since stime should be in microseconds, we should be dividing by 10^6
// but here we are dividing by 10^7 instead. i can't figure out why
// the numbers are off.
req.tv_sec = (time_t) stime / 10000000;
req.tv_nsec = (uint64_t)(stime % 10000000) * 1000;
nanosleep(&req, NULL);
}
ctick = event.ctime;
}
static void midi_handlesys35(midievent_t event) {
NOTICE("midi_handlesys35: ");
int vn1 = midi->event[pc+1].data[2];
int vn2 = midi->event[pc+2].data[2];
int vn3 = midi->event[pc+3].data[2];
switch (vn1) {
case 0:
/* set label */
NOTICE("set label");
pc += 6;
break;
case 1:
/* jump */
midi_allnotesoff();
pc = midi->sys35_label[vn2];
NOTICE("jump to tick [%i]", pc);
break;
case 2:
/* set flag */
NOTICE("set flag %i = %i", vn2, vn3);
flags.midi_flag[vn2] = vn3;
pc += 6;
break;
case 3:
/* flag jump */
if (flags.midi_flag[vn2] == 1) {
pc = midi->sys35_label[vn3];
tick = ctick = event.ctime;
midi_allnotesoff();
NOTICE("jump to tick [%i] ctime = [%i]", pc, tick);
} else {
NOTICE("flag [%i] not set, not jumping", vn2);
pc += 6;
}
break;
case 4:
/* set variable */
NOTICE("set var %i = %i", vn2, vn3);
flags.midi_variable[vn2] = vn3;
pc += 6;
break;
case 5:
/* variable jump */
if (--(flags.midi_variable[vn2]) == 0) {
pc = midi->sys35_label[vn3];
tick = ctick = event.ctime;
midi_allnotesoff();
NOTICE("jump to tick [%i] ctime = [%i]", pc, tick);
} else {
NOTICE("var [%i] not set, not jumping", vn2);
pc += 6;
}
break;
default:
NOTICE("unknown [%i]", vn2);
break;
}
}
static int midi_thread(void *args) {
thread_running = TRUE;
NOTICE("midi_thread started");
start:
midi_allnotesoff();
midi_send_reset();
boolean pausing = FALSE;
int nevents = midi->eventsize;
pc = tick = ctick = 0;
tempo = 500000;
ppqn = tempo / midi->division;
while (TRUE) {
if (pc >= nevents) {
NOTICE("midi_thread finished midi file");
break;
}
if (should_stop) {
NOTICE("midi_thread received stop command");
break;
}
if (should_pause) {
NOTICE("midi_thread pausing");
midi_allnotesoff();
should_pause = FALSE;
pausing = TRUE;
}
if (should_unpause) {
NOTICE("midi_thread unpausing");
should_unpause = FALSE;
pausing = FALSE;
}
if (pausing) {
usleep(50*1000);
continue;
}
while (tick == midi->event[pc].ctime) {
midievent_t event = midi->event[pc];
midi_sync(event);
switch (midi->event[pc].type) {
case MIDI_EVENT_NORMAL:
midi_write(event);
break;
case MIDI_EVENT_TEMPO:
midi_settempo(event);
break;
case MIDI_EVENT_SYS35:
midi_handlesys35(event);
break;
default:
NOTICE("unknown type of event [%x]", event.type);
break;
}
}
tick++;
}
if (should_loop && !should_stop)
goto start;
if (midi != NULL) {
NOTICE("freeing midi file");
mf_remove_midifile(midi);
midi = NULL;
}
midi_allnotesoff();
usleep(10000);
midi_send_reset();
usleep(10000);
should_stop = FALSE;
thread_running = FALSE;
NOTICE("midi_thread done.");
return 0;
}
-493
View File
@@ -1,493 +0,0 @@
/*
* midi.rawmidi.c midi play with rawmidi device
*
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
*
* Based on midiplay+ by Daisuke NAGANO <breeze.nagano@nifty.ne.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* $Id: midi.rawmidi.c,v 1.7 2003/01/31 12:58:28 chikama Exp $ */
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#ifdef ENABLE_MIDI_SEQMIDI
#if defined(__FreeBSD__)
#include <machine/soundcard.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__)
#include <soundcard.h>
#else
#include <sys/soundcard.h>
#endif
#include <sys/ioctl.h>
#endif
#include <SDL_thread.h>
#include <SDL_timer.h>
#include "portab.h"
#include "system.h"
#include "midi.h"
#include "music_private.h"
#include "midifile.h"
#include "msgqueue.h"
static struct {
char midi_variable[128];
char midi_flag[128];
} flags;
static void send_reset();
static int midi_initilize(char *devnm, int subdev);
static int midi_exit(void);
static int midi_reset(void);
static int midi_start(int no, int loop, char *data, int datalen);
static int midi_stop();
static int midi_pause(void);
static int midi_unpause(void);
static int midi_get_playing_info(midiplaystate *st);
static int midi_getflag(int mode, int index);
static int midi_setflag(int mode, int index, int val);
static void (*myflush)(void);
static void (*mywrite)(unsigned char *d, int n, int p);
#ifdef ENABLE_MIDI_RAWMIDI
static void raw_myflush();
static void raw_mywrite(unsigned char *d, int n, int p);
#endif
#ifdef ENABLE_MIDI_SEQMIDI
static void seq_myflush();
static void seq_mywrite(unsigned char *d, int n, int p);
#endif
mididevice_t midi_rawmidi = {
midi_initilize,
midi_exit,
midi_reset,
midi_start,
midi_stop,
midi_pause,
midi_unpause,
midi_get_playing_info,
midi_getflag,
midi_setflag,
NULL,
NULL,
NULL,
NULL
};
#ifndef MIDI_DEVICE
#define MIDI_DEVICE "/dev/midi"
#endif
#ifndef SEQ_DEVICE
#define SEQ_DEVICE "/dev/sequencer"
#endif
static boolean enabled = FALSE;
static int midifd = -1;
static char *mididevname;
static SDL_Thread *thread;
static struct msgq *queue;
static int start_time;
static char cmd_pause[] = "pause";
static char cmd_unpause[] = "unpause";
static char cmd_stop[] = "stop";
#define ALL_NOTEOFF_SZ 48
static char all_noteoff[] = { 0xb0, 0x7b, 0x00,
0xb1, 0x7b, 0x00,
0xb2, 0x7b, 0x00,
0xb3, 0x7b, 0x00,
0xb4, 0x7b, 0x00,
0xb5, 0x7b, 0x00,
0xb6, 0x7b, 0x00,
0xb7, 0x7b, 0x00,
0xb8, 0x7b, 0x00,
0xb9, 0x7b, 0x00,
0xba, 0x7b, 0x00,
0xbb, 0x7b, 0x00,
0xbc, 0x7b, 0x00,
0xbd, 0x7b, 0x00,
0xbe, 0x7b, 0x00,
0xbf, 0x7b, 0x00 };
#define ALL_RESET_SZ 96
static char all_reset[] = { 0xb0, 0x78, 0x00, 0xb0, 0x79, 0x00,
0xb1, 0x78, 0x00, 0xb1, 0x79, 0x00,
0xb2, 0x78, 0x00, 0xb2, 0x79, 0x00,
0xb3, 0x78, 0x00, 0xb3, 0x79, 0x00,
0xb4, 0x78, 0x00, 0xb4, 0x79, 0x00,
0xb5, 0x78, 0x00, 0xb5, 0x79, 0x00,
0xb6, 0x78, 0x00, 0xb6, 0x79, 0x00,
0xb7, 0x78, 0x00, 0xb7, 0x79, 0x00,
0xb8, 0x78, 0x00, 0xb8, 0x79, 0x00,
0xb9, 0x78, 0x00, 0xb9, 0x79, 0x00,
0xba, 0x78, 0x00, 0xba, 0x79, 0x00,
0xbb, 0x78, 0x00, 0xbb, 0x79, 0x00,
0xbc, 0x78, 0x00, 0xbc, 0x79, 0x00,
0xbd, 0x78, 0x00, 0xbd, 0x79, 0x00,
0xbe, 0x78, 0x00, 0xbe, 0x79, 0x00,
0xbf, 0x78, 0x00, 0xbf, 0x79, 0x00 };
static void send_reset() {
mywrite(all_reset, ALL_RESET_SZ, 0);
usleep(60000);
myflush();
usleep(70000);
return;
}
#ifdef ENABLE_MIDI_RAWMIDI
#define WRBFSIZE 16384
static unsigned char wrbuff[WRBFSIZE];
static int nwr = 0; /* wrbuff の index */
static void raw_myflush() {
for (int i = 0; i < nwr; i++) {
while (write(midifd, wrbuff+i, 1) != 1);
}
nwr = 0;
}
/*
* write the code to the buffer
*/
static void raw_mywrite(unsigned char *d, int n, int p) {
if ((nwr + n + 2) >= WRBFSIZE) {
myflush();
}
while (n--) {
wrbuff[nwr++] = *(d++);
}
return;
}
#endif
#ifdef ENABLE_MIDI_SEQMIDI
SEQ_DEFINEBUF(2048);
SEQ_USE_EXTBUF();
static int midi_subdev;
void seqbuf_dump(void) {
if (_seqbufptr) {
if (write(midifd, _seqbuf, _seqbufptr) == -1)
WARNING("write: %s", strerror(errno));
}
_seqbufptr = 0;
}
static void seq_myflush() {
seqbuf_dump();
}
/*
* write the code to the buffer
*/
static void seq_mywrite(unsigned char *d, int n, int p) {
while(n--) {
SEQ_MIDIOUT(midi_subdev, *(d++));
}
return;
}
#endif
static uint32_t ticks2ms(int ticks, int division, unsigned int tempo) {
return ticks * tempo / (division * 1000);
}
static void *midi_mainloop(struct midiinfo *midi) {
int i = 0;
int ctick = 0;
int tempo = 500000;
uint32_t last_time = SDL_GetTicks();
void *cmd;
while (i < midi->eventsize) {
if (ctick < midi->event[i].ctime) {
myflush();
int delta = midi->event[i].ctime - ctick;
uint32_t target_time = last_time + ticks2ms(delta, midi->division, tempo);
uint32_t current_time = SDL_GetTicks();
while (current_time < target_time) {
cmd = msgq_dequeue_timeout(queue, target_time - current_time);
if (cmd == cmd_stop)
return cmd;
if (cmd == cmd_pause) {
while (TRUE) {
cmd = msgq_dequeue(queue);
if (cmd == cmd_stop)
return cmd;
if (cmd == cmd_unpause)
break;
}
target_time += SDL_GetTicks() - current_time;
}
current_time = SDL_GetTicks();
}
last_time = target_time;
ctick = midi->event[i].ctime;
}
if (midi->event[i].type == 0) {
/* ordinary data */
mywrite(midi->event[i].data, midi->event[i].n, midi->event[i].port);
i++;
} else if (midi->event[i].type == 2) {
/* tempo change */
int *p = (int*)midi->event[i].data;
tempo = (unsigned int)*p;
i++;
} else if (midi->event[i].type == 3) {
/* system35 maker */
int vn1 = midi->event[i+1].data[2];
int vn2 = midi->event[i+2].data[2];
int vn3 = midi->event[i+3].data[2];
switch (vn1) {
case 0:
/* set label */
i += 6;
break;
case 1:
/* jump */
mywrite(all_noteoff, ALL_NOTEOFF_SZ, 0);
i = midi->sys35_label[vn2];
ctick = midi->event[i].ctime;
break;
case 2:
/* set flag */
flags.midi_flag[vn2] = vn3;
i += 6;
break;
case 3:
/* flag jump */
if (flags.midi_flag[vn2] == 1) {
i = midi->sys35_label[vn3];
ctick = midi->event[i].ctime;
mywrite(all_noteoff, ALL_NOTEOFF_SZ, 0);
} else {
i += 6;
}
break;
case 4:
/* set variable */
flags.midi_variable[vn2] = vn3;
i += 6;
break;
case 5:
/* variable jump */
if (--(flags.midi_variable[vn2]) == 0) {
i = midi->sys35_label[vn3];
ctick = midi->event[i].ctime;
mywrite(all_noteoff, ALL_NOTEOFF_SZ, 0);
} else {
i += 6;
}
break;
}
} else {
WARNING("Unknown type of event %x (NEVER!).", midi->event[i].type);
}
}
return NULL;
}
static int midi_initilize(char *devnm, int subdev) {
enabled = FALSE;
if (devnm == NULL) {
if (subdev == -1) {
mididevname = MIDI_DEVICE;
} else {
mididevname = SEQ_DEVICE;
}
} else {
mididevname = devnm;
}
if (subdev == -1) {
#ifdef ENABLE_MIDI_RAWMIDI
myflush = raw_myflush;
mywrite = raw_mywrite;
NOTICE("RAWMIDI Initilize OK");
#endif
} else {
#ifdef ENABLE_MIDI_SEQMIDI
myflush = seq_myflush;
mywrite = seq_mywrite;
midi_subdev = subdev;
NOTICE("SEQMIDI Initilize OK");
#endif
}
enabled = TRUE;
return OK;
}
static int midi_exit(void) {
if (enabled) {
midi_stop();
}
return OK;
}
static int midi_reset(void) {
if (enabled) {
midi_stop();
}
return OK;
}
static int midi_thread(void *data) {
send_reset();
void *cmd = midi_mainloop(data);
send_reset();
mf_remove_midifile(data);
close(midifd);
midifd = -1;
while (cmd != cmd_stop)
cmd = msgq_dequeue(queue);
return 0;
}
/* no = 0~ */
static int midi_start(int no, int loop, char *data, int datalen) {
if (queue)
midi_stop();
struct midiinfo *midi = mf_read_midifile(data, datalen);
if (!midi) {
WARNING("error reading midi file");
return NG;
}
if (0 > (midifd = open(mididevname, O_RDWR))) {
WARNING("error opening %s: %s", mididevname, strerror(errno));
mf_remove_midifile(midi);
return NG;
}
#ifdef ENABLE_SEQMIDI
{
int nrsynths;
if (-1 == ioctl(mididev, SNDCTL_SEQ_NRSYNTHS, &nrsynths)) {
WARNING("SNDCTL_SEQ_NRSYNTHS: %s", strerror(errno));
mf_remove_midifile(midi);
close(midifd);
midifid = -1;
return NG;
}
}
#endif
queue = msgq_new();
thread = SDL_CreateThread(midi_thread, "MIDI", midi);
start_time = SDL_GetTicks();
return OK;
}
static int midi_stop() {
if (!enabled || !queue) {
return OK;
}
msgq_enqueue(queue, cmd_stop);
SDL_WaitThread(thread, NULL);
thread = NULL;
msgq_free(queue);
queue = NULL;
return OK;
}
static int midi_pause(void) {
if (!enabled || !queue) return OK;
msgq_enqueue(queue, cmd_pause);
return OK;
}
static int midi_unpause(void) {
if (!enabled || !queue) return OK;
msgq_enqueue(queue, cmd_unpause);
return OK;
}
static int midi_get_playing_info(midiplaystate *st) {
if (!enabled || !queue) {
st->in_play = FALSE;
st->loc_ms = 0;
return OK;
}
if (midifd < 0) {
midi_stop();
st->in_play = FALSE;
st->loc_ms = 0;
return OK;
}
st->in_play = TRUE;
st->loc_ms = SDL_GetTicks() - start_time;
return OK;
}
static int midi_getflag(int mode, int index) {
if (mode == 0) {
/* flag */
return flags.midi_flag[index];
} else {
/* variable */
return flags.midi_variable[index];
}
}
static int midi_setflag(int mode, int index, int val) {
if (mode == 0) {
/* flag */
flags.midi_flag[index] = val;
} else {
/* variable */
flags.midi_variable[index] = val;
}
return OK;
}
+3 -3
View File
@@ -31,7 +31,7 @@
#define MIX_INIT_MID MIX_INIT_FLUIDSYNTH
#endif
static int midi_initilize(char *pname, int subdev);
static int midi_initialize(int subdev);
static int midi_exit(void);
static int midi_reset(void);
static int midi_start(int no, int loop, char *data, int datalen);
@@ -48,7 +48,7 @@ static boolean midi_fading();
#define midi midi_sdlmixer
mididevice_t midi = {
midi_initilize,
midi_initialize,
midi_exit,
midi_reset,
midi_start,
@@ -68,7 +68,7 @@ static Mix_Music *mix_music;
static int start_time;
static uint32_t fade_tick;
static int midi_initilize(char *pname, int subdev) {
static int midi_initialize(int subdev) {
if (Mix_Init(MIX_INIT_MID) != MIX_INIT_MID)
return NG;
return OK;
+190 -485
View File
@@ -3,6 +3,7 @@
*
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
* 2024 kichikuou <KichikuouChrome@gmail.com>
*
* Based on midiplay+ by Daisuke NAGANO <breeze.nagano@nifty.ne.jp>
*
@@ -28,557 +29,261 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <portmidi.h>
#include "portab.h"
#include "system.h"
#include "midifile.h"
static long to32bit(int c1, int c2, int c3, int c4);
static void midi_inc();
static void make_chunk(struct midievent *ev, int n);
static void midi_noteoff(int chan, int note, int vol);
static void midi_noteon(int chan, int note, int vol);
static void midi_pressure(int chan, int note, int press);
static void midi_controlparameter(int chan, int cnt, int val);
static void midi_pitchbend(int chan, int lsb, int msg);
static void midi_program(int chan, int prog);
static void midi_chanpressure(int chan, int press);
static void midi_tempo(int tempo);
static void chanmessage(int status, int c1, int c2);
static void metaevent(int type);
static void msginit();
static void msgadd(int c);
// static int msglen();
static char *msg();
static int midigetc();
static long readvarinum();
static void read_playevent();
static int read_header(uint8_t *stream, off_t len);
// magic bytes
#define RIFF 0x52494646
#define MThd 0x4d546864
#define MTrk 0x4d54726b
static struct midiinfo *midi;
// MIDI commands
#define MIDI_CONTROL 0xb0
#define Read16() \
(*stream << 8) | (*(stream + 1)), stream+=2
#define META_END_OF_TRACK 0x2f
#define META_SET_TEMPO 0x51
#define Read32() \
(*stream << 24) | (*(stream + 1) << 16) | (*(stream + 2) << 8) | (*(stream + 3)), stream+=4
struct stream {
uint8_t *p;
uint8_t *end;
};
static long to32bit(int c1, int c2, int c3, int c4) {
long value = 0L;
value = (c1 & 0xff);
value = (value << 8) + (c2 & 0xff);
value = (value << 8) + (c3 & 0xff);
value = (value << 8) + (c4 & 0xff);
static inline uint8_t read8(struct stream *input) {
return *input->p++;
}
static inline uint16_t read16_be(struct stream *s) {
uint16_t val = s->p[0] << 8 | s->p[1];
s->p += 2;
return val;
}
static inline uint32_t read32_be(struct stream *s) {
uint32_t val = s->p[0] << 24 | s->p[1] << 16 | s->p[2] << 8 | s->p[3];
s->p += 4;
return val;
}
static int read_vlq(struct stream *input) {
int c, value = 0;
do {
c = read8(input);
value = (value << 7) | (c & 0x7f);
} while (c & 0x80);
return value;
}
static void midi_inc() {
midi->ceptr++;
if (midi->ceptr > MAXMIDIEVENT) {
NOTICE("too much event");
sys_exit(0);
/*
* System 3.x defines custom (non-standard) MIDI commands using Registered
* Parameter Numbers (RPN). A custom command is represented by the following
* sequence of MIDI events:
*
* b0 65 64 ; set RPN MSB to 100
* b0 64 XX ; set RPN LSB to XX
* b0 06 YY ; set data MSB to YY
* b0 26 ZZ ; set data LSB to ZZ
* b0 65 7f ; unset RPN MSB
* b0 64 7f ; unset RPN LSB
*
* XX represents the command number, and YY and ZZ are data values. The
* following commands are defined:
*
* 00: Label definition. Defines a label #YY at the location of this event.
* 01: Label jump. Jumps to the label #YY.
* 02: Flag set. Sets the flag #YY to the value ZZ.
* 03: Flag jump. If the flag #YY is set to 1, jumps to the label #YY.
* 04: Variable set. Sets the variable #YY to the value ZZ.
* 05: Variable jump. Decrements the variable #YY by 1. If it reaches 0, jumps
* to the label #ZZ.
*
* Flags and variables can be retrieved or set from scenario scripts, using the
* SG command.
*/
#define CC_DATA_ENTRY_MSB 0x06
#define CC_DATA_ENTRY_LSB 0x26
#define CC_RPN_LSB 0x64
#define CC_RPN_MSB 0x65
#define SYS35_RPN_MSB 0x64
#define RPN_NULL 0x7f
static bool check_sys35cmd(int32_t msg, int *state) {
if ((Pm_MessageStatus(msg) & 0xf0) != MIDI_CONTROL) {
*state = 0;
return false;
}
}
static void make_chunk(struct midievent *ev, int n) {
ev->type = 0;
ev->ctime = midi->curtime;
ev->n = n;
ev->port = 0;
if (n != 0) {
ev->data = malloc(sizeof(unsigned char) * (n + 1));
}
}
int data1 = Pm_MessageData1(msg);
int data2 = Pm_MessageData2(msg);
(*state)++;
static void midi_noteoff(int chan, int note, int vol) {
make_chunk(&midi->event[midi->ceptr], 3);
midi->event[midi->ceptr].data[0] = MIDI_NOTEOFF + chan;
midi->event[midi->ceptr].data[1] = note;
midi->event[midi->ceptr].data[2] = vol;
midi_inc();
}
static void midi_noteon(int chan, int note, int vol) {
make_chunk(&midi->event[midi->ceptr], 3);
midi->event[midi->ceptr].data[0] = MIDI_NOTEON + chan;
midi->event[midi->ceptr].data[1] = note;
midi->event[midi->ceptr].data[2] = vol;
midi_inc();
}
static void midi_pressure(int chan, int note, int press) {
make_chunk(&midi->event[midi->ceptr], 3);
midi->event[midi->ceptr].data[0] = MIDI_PRESSURE + chan;
midi->event[midi->ceptr].data[1] = note;
midi->event[midi->ceptr].data[2] = press;
midi_inc();
}
static int check_sys35mark(int *fnc, int *val1, int *val2) {
midi->marker++;
switch(midi->marker) {
switch (*state) {
case 1:
if (midi->event[midi->ceptr].data[1] != 101 ||
midi->event[midi->ceptr].data[2] != 100) {
midi->marker = 0;
}
if (data1 == CC_RPN_MSB && data2 == SYS35_RPN_MSB)
return false;
break;
case 2:
if (midi->event[midi->ceptr].data[1] != 100) {
midi->marker = 0;
}
if (data1 == CC_RPN_LSB)
return false;
break;
case 3:
if (midi->event[midi->ceptr].data[1] != 6) {
midi->marker = 0;
}
if (data1 == CC_DATA_ENTRY_MSB)
return false;
break;
case 4:
if (midi->event[midi->ceptr].data[1] != 38) {
midi->marker = 0;
}
if (data1 == CC_DATA_ENTRY_LSB)
return false;
break;
case 5:
if (midi->event[midi->ceptr].data[1] != 101 ||
midi->event[midi->ceptr].data[2] != 127) {
midi->marker = 0;
}
if (data1 == CC_RPN_MSB && data2 == RPN_NULL)
return false;
break;
case 6:
if (midi->event[midi->ceptr].data[1] != 100 ||
midi->event[midi->ceptr].data[2] != 127) {
midi->marker = 0;
} else {
midi->marker = 0;
*fnc = midi->event[midi->ceptr-4].data[2];
*val1 = midi->event[midi->ceptr-3].data[2];
*val2 = midi->event[midi->ceptr-2].data[2];
return 1;
if (data1 == CC_RPN_LSB && data2 == RPN_NULL) {
*state = 0;
return true;
}
break;
}
return 0;
*state = 0;
return false;
}
static void midi_controlparameter(int chan, int cnt, int val) {
int fnc, val1, val2;
make_chunk(&midi->event[midi->ceptr], 3);
midi->event[midi->ceptr].data[0] = MIDI_CONTROL + chan;
midi->event[midi->ceptr].data[1] = cnt;
midi->event[midi->ceptr].data[2] = val;
if (check_sys35mark(&fnc, &val1, &val2) > 0) {
midi->event[midi->ceptr - 5].type = 3;
/* ラベル登録 */
if (fnc == 0) {
midi->sys35_label[val1] = midi->ceptr -5;
}
static void add_event(struct midiinfo *midi, int *event_buffer_size, enum midi_event_type type, int curtime, int32_t data) {
if (midi->nr_events >= *event_buffer_size) {
*event_buffer_size = *event_buffer_size ? *event_buffer_size * 3 / 2 : 4096;
midi->event = realloc(midi->event, *event_buffer_size * sizeof(struct midievent));
}
midi_inc();
midi->event[midi->nr_events].type = type;
midi->event[midi->nr_events].ctime = curtime;
midi->event[midi->nr_events].data = data;
midi->nr_events++;
}
static void midi_pitchbend(int chan, int lsb, int msg) {
make_chunk(&midi->event[midi->ceptr], 3);
midi->event[midi->ceptr].data[0] = MIDI_PITCHB + chan;
midi->event[midi->ceptr].data[1] = lsb;
midi->event[midi->ceptr].data[2] = msg;
midi_inc();
}
static void midi_program(int chan, int prog) {
make_chunk(&midi->event[midi->ceptr], 2);
midi->event[midi->ceptr].data[0] = MIDI_PROGRAM + chan;
midi->event[midi->ceptr].data[1] = prog;
midi_inc();
}
static void midi_chanpressure(int chan, int press) {
make_chunk(&midi->event[midi->ceptr], 2);
midi->event[midi->ceptr].data[0] = MIDI_CHANPRES + chan;
midi->event[midi->ceptr].data[1] = press;
midi_inc();
}
static void midi_tempo(int tempo) {
unsigned char x[4];
unsigned int *p;
p = (unsigned int*)x;
*p = (unsigned int)tempo;
make_chunk(&midi->event[midi->ceptr], sizeof(unsigned long));
midi->event[midi->ceptr].type = 2; /* tempo change (msec/midi-qnote) */
midi->event[midi->ceptr].data[0] = x[0];
midi->event[midi->ceptr].data[1] = x[1];
midi->event[midi->ceptr].data[2] = x[2];
midi->event[midi->ceptr].data[3] = x[3];
midi_inc();
}
static void chanmessage(int status, int c1, int c2) {
int chan = status & 0xf;
switch (status & 0xf0) {
case 0x80:
midi_noteoff(chan, c1, c2);
break;
case 0x90:
midi_noteon(chan, c1, c2);
break;
case 0xa0:
midi_pressure(chan, c1, c2);
break;
case 0xb0:
midi_controlparameter(chan, c1, c2);
break;
case 0xe0:
midi_pitchbend(chan, c1, c2);
break;
case 0xc0:
midi_program(chan, c1);
break;
case 0xd0:
midi_chanpressure(chan, c1);
break;
default:
NOTICE("Unknown Message");
}
}
static void metaevent(int type) {
// int len = msglen();
char *m = msg();
switch(type) {
case 0x00:
NOTICE("seqnum");
break;
case 0x01:
NOTICE("text event (Text Event, Ignored)");
break;
case 0x02:
NOTICE("copyright notice (Text Event, Ignored)");
break;
case 0x03:
NOTICE("sequence / track name (Text Event, Ignored)");
break;
case 0x04:
NOTICE("instrument name (Text Event, Ignored)");
break;
case 0x05:
NOTICE("lyric (Text Event, Ignored)");
break;
case 0x06:
NOTICE("marker (Text Event, Ignored)");
break;
case 0x07:
NOTICE("cue point (Text Event, Ignored)");
break;
case 0x08:
NOTICE("meta event 0x08 (Text Event, Ignored)");
break;
case 0x09:
NOTICE("meta event 0x09 (Text Event, Ignored)");
break;
case 0x0a:
NOTICE("meta event 0x0a (Text Event, Ignored)");
break;
case 0x0b:
NOTICE("meta event 0x0b (Text Event, Ignored)");
break;
case 0x0c:
NOTICE("meta event 0x0c (Text Event, Ignored)");
break;
case 0x0d:
NOTICE("meta event 0x0d (Text Event, Ignored)");
break;
case 0x0e:
NOTICE("meta event 0x0e (Text Event, Ignored)");
break;
case 0x0f:
NOTICE("meta event 0x0f (Text Event, Ignored)");
break;
case 0x2f:
/* EOF */
midi->length_left = 0;
midi->eventsize = midi->ceptr;
break;
case 0x51:
midi_tempo(to32bit(0, m[0], m[1], m[2]));
break;
case 0x54:
NOTICE("set smpte");
break;
case 0x58:
NOTICE("time sig (Ignore)");
break;
case 0x59:
NOTICE("keysig (Ignore)");
break;
case 0x7f:
NOTICE("seq specific");
break;
default:
NOTICE("meta misc");
break;
}
}
static void msginit() {
midi->msgindex = 0;
}
static void msgadd(int c) {
if (midi->msgindex >= midi->msgsize) {
midi->msgsize *= 2;
midi->msgbuffer = (unsigned char *)realloc(midi->msgbuffer, midi->msgsize);
}
midi->msgbuffer[midi->msgindex++] = (unsigned char)c;
}
#if 0
static int msglen() {
return midi->msgindex;
}
#endif
static char *msg() {
return midi->msgbuffer;
}
static int midigetc() {
midi->length_left--;
return *midi->cdata++;
}
/* readvarinum - read a varying-length number, and return the */
/* number of characters it took. */
static long readvarinum() {
long value;
int c;
value = c = midigetc();
if (c & 0x80) {
value &= 0x7f;
do {
c = midigetc();
value = (value << 7) + (c & 0x7f);
} while (c & 0x80);
}
return value;
}
static void read_playevent() {
int c, c1, type;
int running = 0; /* 1 when running status used */
int status = 0; /* status value (e.g. 0x90==note-on) */
int delta, needed, lookfor, len;
static void read_events(struct midiinfo *midi, struct stream *input) {
/* This array is indexed by the high half of a status byte. It's */
/* value is either the number of bytes needed (1 or 2) for a channel */
/* message, or 0 (meaning it's not a channel message). */
static int chantype[] = {
const int chantype[] = {
0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */
2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */
};
midi->cdata = midi->data;
midi->length_left = midi->length;
midi->curtime = 0;
midi->ceptr = 0;
while(midi->length_left > 0) {
midi->curtime += (delta = readvarinum()); /* delta time for midi event */
c = midigetc();
if ((c & 0x80) == 0) {
running = 1;
int curtime = 0;
int event_buffer_size = 0;
int status = 0; /* status value (e.g. 0x90==note-on) */
bool running = false;
int sys35cmd_state = 0;
while (input->p < input->end) {
int delta = read_vlq(input);
curtime += delta; /* delta time for midi event */
int c = read8(input);
if (!(c & 0x80)) {
running = true;
} else {
status = c;
running = 0;
}
needed = chantype[(status >> 4) & 0x0f];
if (needed) { /* ie. is it a channel message? */
if (running) {
c1 = c;
} else {
c1 = midigetc();
}
chanmessage(status, c1, (needed > 1) ? midigetc() : 0);
if ((status & 0xf0) != 0xb0) {
midi->marker = 0; /* maker flag clear */
}
continue;;
running = false;
}
midi->marker = 0; /* maker flag clear */
int needed = chantype[(status >> 4) & 0x0f];
if (needed) { /* ie. is it a channel message? */
int c1 = running ? c : read8(input);
int c2 = needed > 1 ? read8(input) : 0;
int32_t msg = Pm_Message(status, c1, c2);
add_event(midi, &event_buffer_size, MIDI_EVENT_NORMAL, curtime, msg);
if (check_sys35cmd(msg, &sys35cmd_state)) {
int command_top = midi->nr_events - MIDI_SYS35_EVENT_SIZE;
midi->event[command_top].type = MIDI_EVENT_SYS35;
int cmd = Pm_MessageData2(midi->event[command_top + 1].data);
int val1 = Pm_MessageData2(midi->event[command_top + 2].data);
if (cmd == MIDI_SYS35_LABEL_DEFINITION)
midi->sys35_label[val1] = command_top;
}
continue;
}
sys35cmd_state = 0;
int type, len;
switch (c) {
case 0xFF: /* meta event */
type = midigetc();
len = readvarinum();
lookfor = midi->length_left - len;
msginit();
while(midi->length_left > lookfor) {
msgadd(midigetc());
type = read8(input);
len = read_vlq(input);
switch(type) {
case META_END_OF_TRACK:
return;
case META_SET_TEMPO:
add_event(midi, &event_buffer_size, MIDI_EVENT_TEMPO, curtime, input->p[0] << 16 | input->p[1] << 8 | input->p[2]);
break;
}
metaevent(type);
input->p += len;
break;
case 0xF0: /* system exclusive */
len = readvarinum();
lookfor = midi->length_left - len;
msginit();
msgadd(0xF0);
while(midi->length_left > lookfor) {
msgadd(midigetc());
}
NOTICE("system exculsive ( not supported )");
input->p += read_vlq(input);
break;
case 0xF7: /* system exclusive continuation or arbitrary stuff */
len = readvarinum();
lookfor = midi->length_left - len;
msginit();
while(midi->length_left > lookfor) {
msgadd(c = midigetc());
}
NOTICE("system exclusive cont. ( not supporte d)");
input->p += read_vlq(input);
break;
default:
NOTICE("Unknow Event ( not supported )");
WARNING("SMF: Unknown Event 0x%x", c);
}
}
}
static int read_header(uint8_t *stream, off_t len) {
int tracklen, i = 0;
uint8_t *stream_top = stream;
while(i == 0 && stream < (stream_top + len)) {
if (0 == strncmp(stream, "MThd", 4)) {
stream += 4;
i++;
} else {
stream++;
}
static bool read_header(struct midiinfo *midi, struct stream *input) {
int magic = read32_be(input);
if (magic == RIFF) {
input->p += 16;
magic = read32_be(input);
}
if (stream != stream_top) {
stream -= 4;
}
i = Read32();
if (i == RIFF) {
stream += 16;
i = Read32();
}
if (i == MThd) {
tracklen = Read32();
midi->format = Read16();
midi->ntrks = Read16();
midi->division = Read16();
} else {
boolean found = FALSE;
while (!found && stream < (stream_top + len - 8)) {
if (0 == strncmp(stream, "MThd", 4)) {
found = TRUE;
} else {
stream++;
}
}
if (found) {
stream += 4;
tracklen = Read32();
midi->format = Read16();
midi->ntrks = Read16();
midi->division = Read16();
} else {
WARNING("unknow format");
return NG;
}
}
if (midi->ntrks != 1) {
WARNING("multiple track (format 1) is not supported");
return NG;
}
NOTICE("tracklen = %d, format = %d, ntrks = %d, division = %d",
tracklen, midi->format, midi->ntrks, midi->division);
i = Read32();
if (i != MTrk) {
WARNING("Unknow format");
}
tracklen = Read32();
if (stream + tracklen > stream_top + len) {
tracklen = stream + len - stream_top;
}
midi->length = tracklen;
midi->data = stream;
return OK;
if (magic != MThd)
return false;
if (read32_be(input) != 6) // header size
return false;
if (read16_be(input) != 0) // format
return false;
if (read16_be(input) != 1) // number of tracks
return false;
midi->division = read16_be(input);
magic = read32_be(input);
if (magic != MTrk)
return false;
int tracklen = read32_be(input);
if (input->p + tracklen < input->end)
input->end = input->p + tracklen;
return true;
}
struct midiinfo *mf_read_midifile(uint8_t *stream, off_t len) {
midi = malloc(sizeof(struct midiinfo));
midi->msgsize = 128; /* Initial msg buffer size */
midi->msgbuffer = calloc(midi->msgsize, sizeof(unsigned char));
if (0 > read_header(stream, len)) {
struct midiinfo *mf_read_midifile(uint8_t *data, size_t len) {
struct stream input = { .p = data, .end = data + len };
struct midiinfo *midi = calloc(1, sizeof(struct midiinfo));
if (!read_header(midi, &input)) {
free(midi);
return NULL;
}
read_playevent();
read_events(midi, &input);
return midi;
}
void mf_remove_midifile(struct midiinfo *m) {
int i;
free(m->msgbuffer);
for (i = 0; i < m->eventsize; i ++) {
free(m->event[i].data);
}
free(m->event);
free(m);
}
+23 -56
View File
@@ -26,74 +26,41 @@
#ifndef __MIDIFILE_H__
#define __MIDIFILE_H__
#include <stdio.h>
#include <sys/types.h>
#include "portab.h"
/* Non-standard MIDI file formats */
#define RIFF 0x52494646
#define CTMF 0x43544d46
/* Standard MIDI file format definitions */
#define MThd 0x4d546864
#define MTrk 0x4d54726b
enum midi_event_type {
MIDI_EVENT_NORMAL,
MIDI_EVENT_TEMPO, /* tempo change (msec/midi-qnote) */
MIDI_EVENT_SYS35
};
/* MIDI COMMANDS */
#define MIDI_NOTEOFF 0x80 /* Note off */
#define MIDI_NOTEON 0x90 /* Note on */
#define MIDI_PRESSURE 0xa0 /* Polyphonic key pressure */
#define MIDI_CONTROL 0xb0 /* Control change */
#define MIDI_PROGRAM 0xc0 /* Program change */
#define MIDI_CHANPRES 0xd0 /* Channel pressure */
#define MIDI_PITCHB 0xe0 /* Pitch wheel change */
#define MIDI_SYSEX 0xf0 /* System exclusive data */
#define MIDI_SYS35_EVENT_SIZE 6
#define MIDI_EVENT_NORMAL 0
#define MIDI_EVENT_TEXT 1
#define MIDI_EVENT_TEMPO 2
#define MIDI_EVENT_SYS35 3
#define MAXMIDIEVENT 65536 /* maxium event sequence number */
enum midi_sys35_event_type {
MIDI_SYS35_LABEL_DEFINITION = 0,
MIDI_SYS35_LABEL_JUMP = 1,
MIDI_SYS35_FLAG_SET = 2,
MIDI_SYS35_FLAG_JUMP = 3,
MIDI_SYS35_VARIABLE_SET = 4,
MIDI_SYS35_VARIABLE_JUMP = 5,
};
struct midievent {
int type; /* Data type
0: normal
1: text
2: tempo change
3: system35 message
*/
unsigned long ctime; /* steptime */
int n; /* data length */
int port; /* midi port */
unsigned char *data; /* midi data */
enum midi_event_type type;
int ctime; /* steptime */
int32_t data;
};
struct midiinfo {
int format; /* MIDI format version ( only 0 is supported) */
int division; /* division for delta time*/
int ntrks; /* number of track */
uint8_t *data;
uint8_t *cdata;
int length;
int length_left;
struct midievent event[MAXMIDIEVENT]; /* event data */
int eventsize; /* total event size */
int ceptr; /* current event pointer */
/* work info */
long curtime; /* current time */
size_t msgindex; /* midi message buffer index */
size_t msgsize; /* size of current allocaed msg */
unsigned char *msgbuffer; /* message buffer */
/* system35 jump info */
int sys35_label[127];
int marker;
struct midievent *event;
int nr_events;
int sys35_label[128]; /* system35 jump info */
};
extern struct midiinfo *mf_read_midifile(uint8_t *stream, off_t len);
extern struct midiinfo *mf_read_midifile(uint8_t *stream, size_t len);
extern void mf_remove_midifile(struct midiinfo *m);
#endif /* __MIDIFILE_H__ */
+8 -8
View File
@@ -36,16 +36,16 @@ EM_JS(int, muspcm_reset, (void), {
return xsystem35.audio.pcm_reset();;
});
EM_JS(int, muspcm_load_no, (int slot, int no), { // async
return xsystem35.audio.pcm_load(slot, no);
EM_ASYNC_JS(int, muspcm_load_no, (int slot, int no), {
return await xsystem35.audio.pcm_load(slot, no);
});
EM_JS(int, muspcm_load_data, (int slot, uint8_t *buf, uint32_t len), { // async
return xsystem35.audio.pcm_load_data(slot, buf, len);
EM_ASYNC_JS(int, muspcm_load_data, (int slot, uint8_t *buf, uint32_t len), {
return await xsystem35.audio.pcm_load_data(slot, buf, len);
});
EM_JS(int, muspcm_load_mixlr, (int slot, int noL, int noR), { // async
return xsystem35.audio.pcm_load_mixlr(slot, noL, noR);
EM_ASYNC_JS(int, muspcm_load_mixlr, (int slot, int noL, int noR), {
return await xsystem35.audio.pcm_load_mixlr(slot, noL, noR);
});
EM_JS(int, muspcm_unload, (int slot), {
@@ -91,6 +91,6 @@ EM_JS(boolean, muspcm_isplaying, (int slot), {
return xsystem35.audio.pcm_isplaying(slot);
});
EM_JS(int, muspcm_waitend, (int slot), { // async
return xsystem35.audio.pcm_waitend(slot);
EM_ASYNC_JS(int, muspcm_waitend, (int slot), {
return await xsystem35.audio.pcm_waitend(slot);
});
+2 -2
View File
@@ -79,7 +79,6 @@ extern void sdl_copy_from_alpha(int sx, int sy, int w, int h, int dx, int dy, AL
extern void sdl_copy_to_alpha(int sx, int sy, int w, int h, int dx, int dy, ALPHA_DIB_COPY_TYPE flag);
extern void sdl_getPixel(int x, int y, Palette *cell);
extern void sdl_putRegion(void *src, int x, int y);
extern void sdl_CopyRegion(void *src, int sx, int sy, int w, int h, int dx, int dy);
extern void sdl_restoreRegion(void *src, int x, int y);
extern void* sdl_saveRegion(int x, int y, int w, int h);
extern void sdl_delRegion(void *src);
@@ -88,8 +87,9 @@ extern SDL_Surface *com2surface(agsurface_t *s);
/* Effects */
struct sdl_effect;
struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int oy, agsurface_t *new, int nx, int ny, enum sdl_effect_type effect);
struct sdl_effect *sdl_sprite_effect_init(SDL_Rect *rect, int dx, int dy, int sx, int sy, int col, enum sdl_effect_type type);
struct sdl_effect *sdl_effect_magnify_init(agsurface_t *surface, SDL_Rect *view_rect, SDL_Rect *target_rect);
void sdl_effect_step(struct sdl_effect *eff, double progress);
void sdl_effect_step(struct sdl_effect *eff, float progress);
void sdl_effect_finish(struct sdl_effect *eff);
/* key/pointer 関係 */
+16 -5
View File
@@ -202,10 +202,7 @@ void sdl_copyArea(int sx, int sy, int w, int h, int dx, int dy) {
}
}
/*
* dib に指定のパレット sp を抜いてコピー
*/
void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) {
static void sdl_dib_sprite_copy(SDL_Surface *dst, int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) {
sdl_pal_check();
Uint32 col = palette_color(sp);
@@ -214,10 +211,24 @@ void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) {
SDL_Rect r_src = {sx, sy, w, h};
SDL_Rect r_dst = {dx, dy, w, h};
SDL_BlitSurface(sdl_dib, &r_src, sdl_dib, &r_dst);
SDL_BlitSurface(sdl_dib, &r_src, dst, &r_dst);
SDL_SetColorKey(sdl_dib, SDL_FALSE, 0);
}
/*
* dib に指定のパレット sp を抜いてコピー
*/
void sdl_copyAreaSP(int sx, int sy, int w, int h, int dx, int dy, uint8_t sp) {
sdl_dib_sprite_copy(sdl_dib, sx, sy, w, h, dx, dy, sp);
}
SDL_Surface *sdl_dib_to_surface_colorkey(int x, int y, int w, int h, int sp) {
SDL_Surface *s = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_ARGB8888);
SDL_FillRect(s, NULL, 0);
sdl_dib_sprite_copy(s, x, y, w, h, 0, 0, sp);
return s;
}
void sdl_drawImage8_fromData(cgdata *cg, int dx, int dy, int sprite_color) {
int w = cg->width;
int h = cg->height;
+292 -115
View File
@@ -27,10 +27,15 @@
#include "sdl_core.h"
#include "sdl_private.h"
#define M_PIf ((float)M_PI)
#define HAS_SDL_RenderGeometry SDL_VERSION_ATLEAST(2, 0, 18)
enum sdl_effect_type from_nact_effect(enum nact_effect effect) {
switch (effect) {
case NACT_EFFECT_PAN_IN_DOWN: return EFFECT_PAN_IN_DOWN;
case NACT_EFFECT_PAN_IN_UP: return EFFECT_PAN_IN_UP;
case NACT_EFFECT_SKIP_LINE_UP_DOWN: return EFFECT_SKIP_LINE_UP_DOWN;
case NACT_EFFECT_SKIP_LINE_LR_RL: return EFFECT_SKIP_LINE_LR_RL;
case NACT_EFFECT_WIPE_IN: return EFFECT_WIPE_IN;
case NACT_EFFECT_WIPE_OUT: return EFFECT_WIPE_OUT;
case NACT_EFFECT_ZOOM_IN: return EFFECT_ZOOM_IN;
@@ -77,6 +82,17 @@ enum sdl_effect_type from_nact_effect(enum nact_effect effect) {
}
}
enum sdl_effect_type from_nact_sprite_effect(enum nact_effect effect) {
switch (effect) {
case NACT_EFFECT_PAN_IN_DOWN: return EFFECT_PAN_IN_DOWN;
case NACT_EFFECT_PAN_IN_UP: return EFFECT_PAN_IN_UP;
case NACT_EFFECT_SKIP_LINE_UP_DOWN: return EFFECT_SKIP_LINE_UP_DOWN;
case NACT_EFFECT_SKIP_LINE_LR_RL: return EFFECT_SKIP_LINE_LR_RL;
case NACT_SP_EFFECT_RASTER_BLEND: return EFFECT_RASTER_BLEND;
default: return EFFECT_INVALID;
}
}
enum sdl_effect_type from_sact_effect(enum sact_effect effect) {
switch (effect) {
case SACT_EFFECT_CROSSFADE: return EFFECT_CROSSFADE;
@@ -111,7 +127,7 @@ enum sdl_effect_type from_sact_effect(enum sact_effect effect) {
}
struct sdl_effect {
void (*step)(struct sdl_effect *this, double progress);
void (*step)(struct sdl_effect *this, float progress);
void (*finish)(struct sdl_effect *this);
enum sdl_effect_type type;
SDL_Rect dst_rect;
@@ -175,7 +191,7 @@ static inline void move_rect(SDL_Rect *r, int off_x, int off_y) {
// EFFECT_CROSSFADE
static void crossfade_step(struct sdl_effect *eff, double progress);
static void crossfade_step(struct sdl_effect *eff, float progress);
static void crossfade_free(struct sdl_effect *eff);
static struct sdl_effect *crossfade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new) {
@@ -188,7 +204,7 @@ static struct sdl_effect *crossfade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Su
return eff;
}
static void crossfade_step(struct sdl_effect *eff, double progress) {
static void crossfade_step(struct sdl_effect *eff, float progress) {
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect);
SDL_SetTextureBlendMode(eff->tx_new, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(eff->tx_new, progress * 255);
@@ -209,7 +225,7 @@ static struct sdl_effect *fallback_effect_new(SDL_Rect *rect, SDL_Surface *old,
// EFFECT_CROSSFADE_{UP,DOWN,LR,RL}
static void crossfade_animation_step(struct sdl_effect *eff, double progress);
static void crossfade_animation_step(struct sdl_effect *eff, float progress);
static void crossfade_animation_free(struct sdl_effect *eff);
static struct sdl_effect *crossfade_animation_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -222,7 +238,7 @@ static struct sdl_effect *crossfade_animation_new(SDL_Rect *rect, SDL_Surface *o
return eff;
}
static void crossfade_animation_step_sub(SDL_Rect *rect, SDL_Texture *tx, int tx_x, int tx_y, double progress, int band_width, bool lr, bool flip) {
static void crossfade_animation_step_sub(SDL_Rect *rect, SDL_Texture *tx, int tx_x, int tx_y, float progress, int band_width, bool lr, bool flip) {
int maxstep = (lr ? rect->w : rect->h) + band_width;
int band_top = maxstep * progress - band_width;
if (band_top > 0) {
@@ -267,7 +283,7 @@ static void crossfade_animation_step_sub(SDL_Rect *rect, SDL_Texture *tx, int tx
SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_NONE);
}
static void crossfade_animation_step(struct sdl_effect *eff, double progress) {
static void crossfade_animation_step(struct sdl_effect *eff, float progress) {
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect);
switch (eff->type) {
@@ -324,7 +340,7 @@ struct mosaic_effect {
SDL_Texture *tmp_old, *tmp_new, *tx_mosaic;
};
static void mosaic_step(struct sdl_effect *eff, double progress);
static void mosaic_step(struct sdl_effect *eff, float progress);
static void mosaic_free(struct sdl_effect *eff);
static struct sdl_effect *mosaic_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -343,7 +359,7 @@ static struct sdl_effect *mosaic_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfa
return &eff->eff;
}
static void mosaic(SDL_Texture *src, SDL_Texture *tmp, SDL_Texture *dst, int w, int h, double scale) {
static void mosaic(SDL_Texture *src, SDL_Texture *tmp, SDL_Texture *dst, int w, int h, float scale) {
int cx = w / 2;
int cy = h / 2;
SDL_FRect fr = {
@@ -372,17 +388,17 @@ static void mosaic(SDL_Texture *src, SDL_Texture *tmp, SDL_Texture *dst, int w,
SDL_SetRenderTarget(sdl_renderer, NULL);
}
static void mosaic_step(struct sdl_effect *eff, double progress) {
static void mosaic_step(struct sdl_effect *eff, float progress) {
struct mosaic_effect *this = (struct mosaic_effect *)eff;
if (eff->type == EFFECT_MOSAIC) {
const int max_scale = 80;
int scale = (1.0 - progress) * (max_scale - 1) + 1;
int scale = (1.f - progress) * (max_scale - 1) + 1;
mosaic(eff->tx_new, this->tmp_new, this->tx_mosaic, eff->dst_rect.w, eff->dst_rect.h, scale);
SDL_RenderCopy(sdl_renderer, this->tx_mosaic, NULL, &eff->dst_rect);
} else if (eff->type == EFFECT_CROSSFADE_MOSAIC) {
const int max_scale = 96;
double scale = (progress < 0.5 ? progress : 1.0 - progress) * 2 * (max_scale - 1) + 1;
float scale = (progress < 0.5f ? progress : 1.f - progress) * 2 * (max_scale - 1) + 1;
mosaic(eff->tx_old, this->tmp_old, this->tx_mosaic, eff->dst_rect.w, eff->dst_rect.h, scale);
SDL_RenderCopy(sdl_renderer, this->tx_mosaic, NULL, &eff->dst_rect);
mosaic(eff->tx_new, this->tmp_new, this->tx_mosaic, eff->dst_rect.w, eff->dst_rect.h, scale);
@@ -408,7 +424,7 @@ static void mosaic_free(struct sdl_effect *eff) {
// EFFECT_{FADE,WHITE}{OUT,IN}
static void brightness_step(struct sdl_effect *eff, double progress);
static void brightness_step(struct sdl_effect *eff, float progress);
static void brightness_free(struct sdl_effect *eff);
static struct sdl_effect *brightness_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -421,7 +437,7 @@ static struct sdl_effect *brightness_new(SDL_Rect *rect, SDL_Surface *old, SDL_S
return eff;
}
static void brightness_step(struct sdl_effect *eff, double progress) {
static void brightness_step(struct sdl_effect *eff, float progress) {
SDL_Texture *texture;
int color;
int alpha;
@@ -439,7 +455,7 @@ static void brightness_step(struct sdl_effect *eff, double progress) {
case EFFECT_FADEIN:
texture = eff->tx_new;
color = 0;
alpha = (1.0 - progress) * 255;
alpha = (1.f - progress) * 255;
break;
case EFFECT_WHITEOUT:
texture = eff->tx_old;
@@ -454,7 +470,7 @@ static void brightness_step(struct sdl_effect *eff, double progress) {
case EFFECT_WHITEIN:
texture = eff->tx_new;
color = 255;
alpha = (1.0 - progress) * 255;
alpha = (1.f - progress) * 255;
break;
default:
assert(!"Cannot happen");
@@ -475,7 +491,7 @@ static void brightness_free(struct sdl_effect *eff) {
// EFFECT_DITHERING_{FADE,WHITE}{OUT,IN}
static void dithering_fade_step(struct sdl_effect *eff, double progress);
static void dithering_fade_step(struct sdl_effect *eff, float progress);
static void dithering_fade_free(struct sdl_effect *eff);
static SDL_Texture *create_dither_pattern_texture(int w, int h, int val) {
@@ -532,15 +548,15 @@ static struct sdl_effect *dithering_fade_new(SDL_Rect *rect, SDL_Surface *old, S
return eff;
}
static void dithering_fade_step(struct sdl_effect *eff, double progress) {
static void dithering_fade_step(struct sdl_effect *eff, float progress) {
static const int dither_x[16] = {0,2,2,0,1,3,3,1,1,3,3,1,0,2,2,0};
static const int dither_y[16] = {0,2,0,2,1,3,1,3,0,2,0,2,1,3,1,3};
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect);
if (eff->type == EFFECT_DITHERING_FADEIN || eff->type == EFFECT_DITHERING_WHITEIN)
progress = 1 - progress;
int level = round(progress * 16);
progress = 1.f - progress;
int level = roundf(progress * 16);
assert(eff->is_fullscreen);
SDL_Rect dr = eff->dst_rect;
@@ -562,9 +578,110 @@ static void dithering_fade_free(struct sdl_effect *eff) {
free(eff);
}
// EFFECT_PAN_IN_*
static void pan_in_step(struct sdl_effect *eff, float progress);
static void pan_in_free(struct sdl_effect *eff);
static struct sdl_effect *pan_in_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect));
if (!eff)
NOMEMERR();
effect_init(eff, rect, old, new, type);
eff->step = pan_in_step;
eff->finish = pan_in_free;
return eff;
}
static void pan_in_step(struct sdl_effect *eff, float progress) {
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect);
int h = eff->dst_rect.h * progress;
SDL_Rect sr = { 0, 0, eff->dst_rect.w, h };
SDL_Rect dr = eff->dst_rect;
dr.h = h;
if (eff->type == EFFECT_PAN_IN_DOWN) {
sr.y = eff->dst_rect.h - h;
} else {
dr.y += eff->dst_rect.h - h;
}
SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr);
SDL_RenderPresent(sdl_renderer);
}
static void pan_in_free(struct sdl_effect *eff) {
effect_finish(eff, true);
free(eff);
}
// EFFECT_SKIP_LINE_*
static void skip_line_step(struct sdl_effect *eff, float progress);
static void skip_line_free(struct sdl_effect *eff);
static struct sdl_effect *skip_line_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect));
if (!eff)
NOMEMERR();
effect_init(eff, rect, old, new, type);
eff->step = skip_line_step;
eff->finish = skip_line_free;
return eff;
}
static void skip_line_step(struct sdl_effect *eff, float progress) {
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect);
if (eff->type == EFFECT_SKIP_LINE_UP_DOWN) {
int h = eff->dst_rect.h * progress;
SDL_Rect sr = { 0, 0, eff->dst_rect.w, 1 };
SDL_Rect dr = eff->dst_rect;
dr.h = 1;
int bottom = (eff->dst_rect.h - 1) | 1;
for (int y = 0; y < h; y += 2) {
sr.y = y;
dr.y = eff->dst_rect.y + y;
SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr);
if (y == 0 && eff->dst_rect.h & 1)
continue;
sr.y = bottom - y;
dr.y = eff->dst_rect.y + bottom - y;
SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr);
}
} else {
int w = eff->dst_rect.w * progress;
SDL_Rect sr = { 0, 0, 1, eff->dst_rect.h };
SDL_Rect dr = eff->dst_rect;
dr.w = 1;
int right = (eff->dst_rect.w - 1) | 1;
for (int x = 0; x < w; x += 2) {
sr.x = x;
dr.x = eff->dst_rect.x + x;
SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr);
if (x == 0 && eff->dst_rect.w & 1)
continue;
sr.x = right - x;
dr.x = eff->dst_rect.x + right - x;
SDL_RenderCopy(sdl_renderer, eff->tx_new, &sr, &dr);
}
}
SDL_RenderPresent(sdl_renderer);
}
static void skip_line_free(struct sdl_effect *eff) {
effect_finish(eff, true);
free(eff);
}
// EFFECT_WIPE_*
static void wipe_step(struct sdl_effect *eff, double progress);
static void wipe_step(struct sdl_effect *eff, float progress);
static void wipe_free(struct sdl_effect *eff);
static struct sdl_effect *wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -577,7 +694,7 @@ static struct sdl_effect *wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface
return eff;
}
static void wipe_step(struct sdl_effect *eff, double progress) {
static void wipe_step(struct sdl_effect *eff, float progress) {
SDL_Texture *bg = eff->tx_old;
SDL_Texture *fg = eff->tx_new;
if (eff->type == EFFECT_WIPE_RL ||
@@ -587,7 +704,7 @@ static void wipe_step(struct sdl_effect *eff, double progress) {
eff->type == EFFECT_WIPE_IN_H) {
bg = eff->tx_new;
fg = eff->tx_old;
progress = 1 - progress;
progress = 1.f - progress;
}
SDL_RenderCopy(sdl_renderer, bg, NULL, &eff->dst_rect);
@@ -638,7 +755,7 @@ static void wipe_free(struct sdl_effect *eff) {
// EFFECT_CIRCLE_WIPE_*
static void circle_wipe_step(struct sdl_effect *eff, double progress);
static void circle_wipe_step(struct sdl_effect *eff, float progress);
static void circle_wipe_free(struct sdl_effect *eff);
static struct sdl_effect *circle_wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -651,7 +768,7 @@ static struct sdl_effect *circle_wipe_new(SDL_Rect *rect, SDL_Surface *old, SDL_
return eff;
}
static void circle_wipe_step(struct sdl_effect *eff, double progress) {
static void circle_wipe_step(struct sdl_effect *eff, float progress) {
SDL_Texture *bg = eff->tx_old;
SDL_Texture *fg = eff->tx_new;
if (eff->type == EFFECT_CIRCLE_WIPE_IN) {
@@ -663,7 +780,7 @@ static void circle_wipe_step(struct sdl_effect *eff, double progress) {
int hw = eff->dst_rect.w / 2;
int hh = eff->dst_rect.h / 2;
int r = sqrt(hw*hw + hh*hh) * progress;
int r = sqrtf(hw*hw + hh*hh) * progress;
for (int y = -r; y < r; y++) {
if (y < -hh || y >= hh)
@@ -688,7 +805,7 @@ static void circle_wipe_free(struct sdl_effect *eff) {
// EFFECT_BLIND_*
static void blind_step(struct sdl_effect *eff, double progress);
static void blind_step(struct sdl_effect *eff, float progress);
static void blind_free(struct sdl_effect *eff);
static struct sdl_effect *blind_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -701,7 +818,7 @@ static struct sdl_effect *blind_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfac
return eff;
}
static void blind_vstep(double progress, SDL_Rect *rect, SDL_Texture *tx_new, int offset_y, bool flip) {
static void blind_vstep(float progress, SDL_Rect *rect, SDL_Texture *tx_new, int offset_y, bool flip) {
const int N = 16;
int nr_bands = rect->h / N + N - 1;
@@ -733,7 +850,7 @@ static void blind_vstep(double progress, SDL_Rect *rect, SDL_Texture *tx_new, in
}
}
static void blind_step(struct sdl_effect *eff, double progress) {
static void blind_step(struct sdl_effect *eff, float progress) {
const int N = 16;
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, &eff->dst_rect);
@@ -790,7 +907,7 @@ static void blind_free(struct sdl_effect *eff) {
// EFFECT_BLEND_*
static void blend_animation_step(struct sdl_effect *eff, double progress);
static void blend_animation_step(struct sdl_effect *eff, float progress);
static void blend_animation_free(struct sdl_effect *eff);
static struct sdl_effect *blend_animation_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -803,17 +920,17 @@ static struct sdl_effect *blend_animation_new(SDL_Rect *rect, SDL_Surface *old,
return eff;
}
static void blend_animation_step(struct sdl_effect *eff, double progress) {
static void blend_animation_step(struct sdl_effect *eff, float progress) {
const bool lr = eff->type == EFFECT_BLEND_LR_RL;
SDL_Texture *bg, *fg;
if (progress < 0.5) {
if (progress < 0.5f) {
bg = eff->tx_old;
fg = eff->tx_new;
} else {
bg = eff->tx_new;
fg = eff->tx_old;
progress = 1.0 - progress;
progress = 1.f - progress;
}
SDL_RenderCopy(sdl_renderer, bg, NULL, &eff->dst_rect);
@@ -857,7 +974,7 @@ struct zoom_blend_blur_effect {
int index;
};
static void zoom_blend_blur_step(struct sdl_effect *eff, double progress);
static void zoom_blend_blur_step(struct sdl_effect *eff, float progress);
static void zoom_blend_blur_free(struct sdl_effect *eff);
static struct sdl_effect *zoom_blend_blur_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new) {
@@ -873,14 +990,14 @@ static struct sdl_effect *zoom_blend_blur_new(SDL_Rect *rect, SDL_Surface *old,
return &eff->eff;
}
static void zoom_blend_blur_step(struct sdl_effect *eff, double progress) {
static void zoom_blend_blur_step(struct sdl_effect *eff, float progress) {
struct zoom_blend_blur_effect *this = (struct zoom_blend_blur_effect *)eff;
if (!this->tx[this->index]) {
this->tx[this->index] = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, eff->dst_rect.w, eff->dst_rect.h);
}
double scale = (progress < 0.5 ? 1 - progress * 2 : (progress - 0.5) * 2) * 0.9 + 0.1; // 0.1 - 1.0
float scale = (progress < 0.5f ? 1 - progress * 2 : (progress - 0.5f) * 2) * 0.9f + 0.1f; // 0.1 - 1.0
int w = eff->dst_rect.w * scale;
int h = eff->dst_rect.h * scale;
SDL_Rect r = {
@@ -927,7 +1044,7 @@ struct linear_blur_effect {
SDL_Texture *blurred_new[LINEAR_BLUR_STEPS];
};
static void linear_blur_step(struct sdl_effect *eff, double progress);
static void linear_blur_step(struct sdl_effect *eff, float progress);
static void linear_blur_free(struct sdl_effect *eff);
static struct sdl_effect *linear_blur_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -983,7 +1100,7 @@ static SDL_Texture *blur(struct linear_blur_effect *this, SDL_Texture *src, int
return dst;
}
static void linear_blur_step(struct sdl_effect *eff, double progress) {
static void linear_blur_step(struct sdl_effect *eff, float progress) {
struct linear_blur_effect *this = (struct linear_blur_effect *)eff;
int step = progress * LINEAR_BLUR_STEPS * 2;
@@ -1029,7 +1146,7 @@ struct polygon_mask_effect {
SDL_Texture *tx_tmp;
};
static void polygon_mask_step(struct sdl_effect *eff, double progress);
static void polygon_mask_step(struct sdl_effect *eff, float progress);
static void polygon_mask_free(struct sdl_effect *eff);
static struct sdl_effect *polygon_mask_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -1051,7 +1168,7 @@ static struct sdl_effect *polygon_mask_new(SDL_Rect *rect, SDL_Surface *old, SDL
#if HAS_SDL_RenderGeometry
static void draw_pentagram(int center_x, int center_y, double radius, double rotate) {
static void draw_pentagram(int center_x, int center_y, float radius, float rotate) {
const SDL_FPoint p[10] = {
{ 1.5, 0 },
{ 0.4635, 0.3368},
@@ -1065,8 +1182,8 @@ static void draw_pentagram(int center_x, int center_y, double radius, double rot
{ 0.4635, -0.3368},
};
SDL_Vertex v[10];
double sin_r = sin(rotate);
double cos_r = cos(rotate);
float sin_r = sinf(rotate);
float cos_r = cosf(rotate);
for (int i = 0; i < 10; i++) {
v[i].position.x = radius * (p[i].x * cos_r - p[i].y * sin_r) + center_x;
v[i].position.y = radius * (p[i].x * sin_r + p[i].y * cos_r) + center_y;
@@ -1082,7 +1199,7 @@ static void draw_pentagram(int center_x, int center_y, double radius, double rot
SDL_RenderGeometry(sdl_renderer, NULL, v, 10, indices, 15);
}
static void draw_hexagram(int center_x, int center_y, double radius, double rotate) {
static void draw_hexagram(int center_x, int center_y, float radius, float rotate) {
const SDL_FPoint p[6] = {
{ 0, -1.0},
{-0.866, 0.5},
@@ -1093,8 +1210,8 @@ static void draw_hexagram(int center_x, int center_y, double radius, double rota
{ 0.866, -0.5}
};
SDL_Vertex v[6];
double sin_r = sin(rotate);
double cos_r = cos(rotate);
float sin_r = sinf(rotate);
float cos_r = cosf(rotate);
for (int i = 0; i < 6; i++) {
v[i].position.x = radius * (p[i].x * cos_r - p[i].y * sin_r) + center_x;
v[i].position.y = radius * (p[i].x * sin_r + p[i].y * cos_r) + center_y;
@@ -1103,12 +1220,12 @@ static void draw_hexagram(int center_x, int center_y, double radius, double rota
SDL_RenderGeometry(sdl_renderer, NULL, v, 6, NULL, 0);
}
static void draw_windmill_90(int w, int h, double theta) {
double cx = w / 2.0;
double cy = h / 2.0;
double r = max(cx, cy) * sqrt(2);
double r_sin = r * sin(theta);
double r_cos = r * cos(theta);
static void draw_windmill_90(int w, int h, float theta) {
float cx = w / 2.f;
float cy = h / 2.f;
float r = max(cx, cy) * sqrtf(2);
float r_sin = r * sinf(theta);
float r_cos = r * cosf(theta);
SDL_Vertex v[13] = {
// center
@@ -1131,7 +1248,7 @@ static void draw_windmill_90(int w, int h, double theta) {
{.position = {cx - r_cos, cy - r_sin}},
};
if (theta <= M_PI / 4) {
if (theta <= M_PIf / 4) {
const int indices[12] = {
0, 1, 3,
0, 4, 6,
@@ -1154,12 +1271,12 @@ static void draw_windmill_90(int w, int h, double theta) {
}
}
static void draw_windmill_180(int w, int h, double theta) {
double cx = w / 2.0;
double cy = h / 2.0;
double r = max(cx, cy) * sqrt(2);
double r_sin = r * sin(theta);
double r_cos = r * cos(theta);
static void draw_windmill_180(int w, int h, float theta) {
float cx = w / 2.f;
float cy = h / 2.f;
float r = max(cx, cy) * sqrtf(2);
float r_sin = r * sinf(theta);
float r_cos = r * cosf(theta);
SDL_Vertex v[11] = {
{.position = {cx, cy }}, // center
@@ -1174,7 +1291,7 @@ static void draw_windmill_180(int w, int h, double theta) {
{.position = {cx, cy + r }}, // bottom
{.position = {cx - r, cy + r }}, // left-bottom
{.position = {cx - r, cy }}, // left
{.position = {cx + r_cos, cy + r_sin}}, // theta+M_PI
{.position = {cx + r_cos, cy + r_sin}}, // theta+M_PIf
};
int indices[24];
@@ -1182,7 +1299,7 @@ static void draw_windmill_180(int w, int h, double theta) {
indices[i++] = 0; // center
indices[i++] = 9; // left
for (int j = 1; theta > M_PI / 4 * j; j++) {
for (int j = 1; theta > M_PIf / 4 * j; j++) {
indices[i++] = j;
indices[i++] = 0; // center
indices[i++] = j;
@@ -1191,22 +1308,22 @@ static void draw_windmill_180(int w, int h, double theta) {
indices[i++] = 0; // center
indices[i++] = 4; // right
for (int j = 1; theta > M_PI / 4 * j; j++) {
for (int j = 1; theta > M_PIf / 4 * j; j++) {
indices[i++] = j + 5;
indices[i++] = 0; // center
indices[i++] = j + 5;
}
indices[i++] = 10; // theta+M_PI
indices[i++] = 10; // theta+M_PIf
SDL_RenderGeometry(sdl_renderer, NULL, v, 11, indices, i);
}
static void draw_windmill_360(int w, int h, double theta) {
double cx = w / 2.0;
double cy = h / 2.0;
double r = max(cx, cy) * sqrt(2);
double r_sin = r * sin(theta);
double r_cos = r * cos(theta);
static void draw_windmill_360(int w, int h, float theta) {
float cx = w / 2.f;
float cy = h / 2.f;
float r = max(cx, cy) * sqrtf(2);
float r_sin = r * sinf(theta);
float r_cos = r * cosf(theta);
SDL_Vertex v[10] = {
{.position = {cx, cy }}, // center
@@ -1226,7 +1343,7 @@ static void draw_windmill_360(int w, int h, double theta) {
indices[i++] = 0; // center
indices[i++] = 8; // left
for (int j = 1; theta > M_PI / 4 * j; j++) {
for (int j = 1; theta > M_PIf / 4 * j; j++) {
indices[i++] = j;
indices[i++] = 0; // center
indices[i++] = j;
@@ -1235,7 +1352,7 @@ static void draw_windmill_360(int w, int h, double theta) {
SDL_RenderGeometry(sdl_renderer, NULL, v, 10, indices, i);
}
static void polygon_mask_step(struct sdl_effect *eff, double progress) {
static void polygon_mask_step(struct sdl_effect *eff, float progress) {
struct polygon_mask_effect *this = (struct polygon_mask_effect *)eff;
int w = eff->dst_rect.w;
int h = eff->dst_rect.h;
@@ -1243,25 +1360,25 @@ static void polygon_mask_step(struct sdl_effect *eff, double progress) {
SDL_RenderCopy(sdl_renderer, eff->tx_old, NULL, NULL);
switch (eff->type) {
case EFFECT_PENTAGRAM_IN_OUT:
draw_pentagram(w / 2, h / 2, max(w, h) * progress, M_PI * progress);
draw_pentagram(w / 2, h / 2, max(w, h) * progress, M_PIf * progress);
break;
case EFFECT_PENTAGRAM_OUT_IN:
draw_pentagram(w / 2, h / 2, max(w, h) * (1 - progress), M_PI * progress);
draw_pentagram(w / 2, h / 2, max(w, h) * (1 - progress), M_PIf * progress);
break;
case EFFECT_HEXAGRAM_IN_OUT:
draw_hexagram(w / 2, h / 2, max(w, h) * progress, M_PI * progress);
draw_hexagram(w / 2, h / 2, max(w, h) * progress, M_PIf * progress);
break;
case EFFECT_HEXAGRAM_OUT_IN:
draw_hexagram(w / 2, h / 2, max(w, h) * (1 - progress), M_PI * progress);
draw_hexagram(w / 2, h / 2, max(w, h) * (1 - progress), M_PIf * progress);
break;
case EFFECT_WINDMILL:
draw_windmill_90(w, h, M_PI / 2 * progress);
draw_windmill_90(w, h, M_PIf / 2 * progress);
break;
case EFFECT_WINDMILL_180:
draw_windmill_180(w, h, M_PI * progress);
draw_windmill_180(w, h, M_PIf * progress);
break;
case EFFECT_WINDMILL_360:
draw_windmill_360(w, h, M_PI * 2 * progress);
draw_windmill_360(w, h, M_PIf * 2 * progress);
break;
default:
assert(!"Cannot happen");
@@ -1284,7 +1401,7 @@ static void polygon_mask_free(struct sdl_effect *eff) {
// EFFECT_ROTATE_*
static void rotate_step(struct sdl_effect *eff, double progress);
static void rotate_step(struct sdl_effect *eff, float progress);
static void rotate_free(struct sdl_effect *eff);
static struct sdl_effect *rotate_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -1297,24 +1414,24 @@ static struct sdl_effect *rotate_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surfa
return eff;
}
static void rotate_step(struct sdl_effect *eff, double progress) {
static void rotate_step(struct sdl_effect *eff, float progress) {
SDL_Texture *bg_texture, *fg_texture;
double angle = progress * 360;
double scale = progress;
float angle = progress * 360;
float scale = progress;
switch (eff->type) {
case EFFECT_ROTATE_OUT:
scale = 1.0 - scale;
scale = 1.f - scale;
bg_texture = eff->tx_new;
fg_texture = eff->tx_old;
angle *= -1.0;
angle *= -1.f;
break;
case EFFECT_ROTATE_IN:
bg_texture = eff->tx_old;
fg_texture = eff->tx_new;
angle *= -1.0;
angle *= -1.f;
break;
case EFFECT_ROTATE_OUT_CW:
scale = 1.0 - scale;
scale = 1.f - scale;
bg_texture = eff->tx_new;
fg_texture = eff->tx_old;
break;
@@ -1331,8 +1448,8 @@ static void rotate_step(struct sdl_effect *eff, double progress) {
assert(!"Cannot happen");
}
SDL_Rect r = eff->dst_rect;
r.x += (1.0 - scale) * r.w / 2;
r.y += (1.0 - scale) * r.h / 2;
r.x += (1.f - scale) * r.w / 2;
r.y += (1.f - scale) * r.h / 2;
r.w *= scale;
r.h *= scale;
SDL_RenderCopy(sdl_renderer, bg_texture, NULL, &eff->dst_rect);
@@ -1347,7 +1464,7 @@ static void rotate_free(struct sdl_effect *eff) {
// EFFECT_POLYGON_ROTATE_*
static void polygon_rotate_step(struct sdl_effect *eff, double progress);
static void polygon_rotate_step(struct sdl_effect *eff, float progress);
static void polygon_rotate_free(struct sdl_effect *eff);
static struct sdl_effect *polygon_rotate_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new, enum sdl_effect_type type) {
@@ -1360,35 +1477,35 @@ static struct sdl_effect *polygon_rotate_new(SDL_Rect *rect, SDL_Surface *old, S
return eff;
}
static void polygon_rotate_step(struct sdl_effect *eff, double progress) {
static void polygon_rotate_step(struct sdl_effect *eff, float progress) {
bool vertical = eff->type == EFFECT_POLYGON_ROTATE_Y || eff->type == EFFECT_POLYGON_ROTATE_Y_CW;
SDL_Texture *texture = progress < 0.5 ? eff->tx_old : eff->tx_new;
double angle = progress < 0.5 ? progress * M_PI : (progress - 1.0) * M_PI;
SDL_Texture *texture = progress < 0.5f ? eff->tx_old : eff->tx_new;
float angle = progress < 0.5f ? progress * M_PIf : (progress - 1.f) * M_PIf;
if (eff->type == EFFECT_POLYGON_ROTATE_Y_CW || eff->type == EFFECT_POLYGON_ROTATE_X_CW)
angle *= -1;
const double distance = 2.0;
double cos_a = cos(angle);
double sin_a = sin(angle);
double lz = -0.5 * sin_a + distance;
double rz = 0.5 * sin_a + distance;
double lx = -0.5 * cos_a / lz;
double rx = 0.5 * cos_a / rz;
const float distance = 2.f;
float cos_a = cosf(angle);
float sin_a = sinf(angle);
float lz = -0.5f * sin_a + distance;
float rz = 0.5f * sin_a + distance;
float lx = -0.5f * cos_a / lz;
float rx = 0.5f * cos_a / rz;
int w = vertical ? eff->dst_rect.w : eff->dst_rect.h;
int h = vertical ? eff->dst_rect.h : eff->dst_rect.w;
double dlx = w * (lx * distance + 0.5);
double drx = w * (rx * distance + 0.5);
float dlx = w * (lx * distance + 0.5f);
float drx = w * (rx * distance + 0.5f);
// Perspective-correct interpolation.
for (int x = dlx; x <= drx; x++) {
if (x < 0 || x >= w)
continue;
double t = (x - dlx) / (drx - dlx);
double recip_z = (1 - t) * (1 / lz) + t * (1 / rz);
double tx = t * (w / rz) / recip_z;
float t = (x - dlx) / (drx - dlx);
float recip_z = (1 - t) * (1 / lz) + t * (1 / rz);
float tx = t * (w / rz) / recip_z;
SDL_Rect sr = {tx, 0, 1, h};
double dh = h * recip_z * distance;
float dh = h * recip_z * distance;
SDL_Rect dr = {x, (h - dh) / 2, 1, dh};
if (!vertical) {
transpose_rect(&sr);
@@ -1412,7 +1529,7 @@ struct zigzag_crossfade_effect {
SDL_Texture *tmp1, *tmp2;
};
static void zigzag_crossfade_step(struct sdl_effect *eff, double progress);
static void zigzag_crossfade_step(struct sdl_effect *eff, float progress);
static void zigzag_crossfade_free(struct sdl_effect *eff);
static struct sdl_effect *zigzag_crossfade_new(SDL_Rect *rect, SDL_Surface *old, SDL_Surface *new) {
@@ -1430,38 +1547,38 @@ static struct sdl_effect *zigzag_crossfade_new(SDL_Rect *rect, SDL_Surface *old,
return &eff->eff;
}
static void wave_warp_h(SDL_Texture *src, SDL_Texture *dst, int w, int h, double amplitude, double length, double phase) {
static void wave_warp_h(SDL_Texture *src, SDL_Texture *dst, int w, int h, float amplitude, float length, float phase) {
SDL_SetRenderTarget(sdl_renderer, dst);
SDL_RenderClear(sdl_renderer);
SDL_Rect sr = {0, 0, w, 1};
SDL_Rect dr = {0, 0, w, 1};
for (int y = 0; y < h; y++) {
sr.y = dr.y = y;
dr.x = sin(phase + y * (2 * M_PI / 360 * length)) * amplitude;
dr.x = sinf(phase + y * (2 * M_PIf / 360 * length)) * amplitude;
SDL_RenderCopy(sdl_renderer, src, &sr, &dr);
}
SDL_SetRenderTarget(sdl_renderer, NULL);
}
static void wave_warp_v(SDL_Texture *src, SDL_Texture *dst, int w, int h, double amplitude, double length, double phase) {
static void wave_warp_v(SDL_Texture *src, SDL_Texture *dst, int w, int h, float amplitude, float length, float phase) {
SDL_SetRenderTarget(sdl_renderer, dst);
SDL_RenderClear(sdl_renderer);
SDL_Rect sr = {0, 0, 1, h};
SDL_Rect dr = {0, 0, 1, h};
for (int x = 0; x < w; x++) {
sr.x = dr.x = x;
dr.y = sin(phase + x * (2 * M_PI / 360 * length)) * amplitude;
dr.y = sinf(phase + x * (2 * M_PIf / 360 * length)) * amplitude;
SDL_RenderCopy(sdl_renderer, src, &sr, &dr);
}
SDL_SetRenderTarget(sdl_renderer, NULL);
}
static void zigzag_crossfade_step(struct sdl_effect *eff, double progress) {
static void zigzag_crossfade_step(struct sdl_effect *eff, float progress) {
struct zigzag_crossfade_effect *this = (struct zigzag_crossfade_effect *)eff;
double amp = (progress < 0.5 ? progress : 1.0 - progress) * 80;
double len = (progress < 0.5 ? progress : 1.0 - progress) * 20;
double phase = progress * 10;
float amp = (progress < 0.5f ? progress : 1.f - progress) * 80;
float len = (progress < 0.5f ? progress : 1.f - progress) * 20;
float phase = progress * 10;
wave_warp_h(eff->tx_old, this->tmp1, eff->dst_rect.w, eff->dst_rect.h, amp, len, phase);
wave_warp_v(this->tmp1, this->tmp2, eff->dst_rect.w, eff->dst_rect.h, amp, len, phase);
@@ -1492,7 +1609,7 @@ struct magnify_effect {
SDL_Rect new_rect;
};
static void magnify_step(struct sdl_effect *eff, double progress);
static void magnify_step(struct sdl_effect *eff, float progress);
static void magnify_free(struct sdl_effect *eff);
static struct sdl_effect *magnify_new(SDL_Surface *sf, SDL_Rect *old_rect, SDL_Rect *new_rect) {
@@ -1506,7 +1623,7 @@ static struct sdl_effect *magnify_new(SDL_Surface *sf, SDL_Rect *old_rect, SDL_R
return &eff->eff;
}
static void magnify_step(struct sdl_effect *eff, double progress) {
static void magnify_step(struct sdl_effect *eff, float progress) {
struct magnify_effect *this = (struct magnify_effect *)eff;
SDL_Rect *or = &eff->dst_rect;
SDL_Rect *nr = &this->new_rect;
@@ -1525,6 +1642,41 @@ static void magnify_free(struct sdl_effect *eff) {
free(eff);
}
// EFFECT_RASTER_BLEND
static void raster_blend_step(struct sdl_effect *eff, float progress);
static void raster_blend_free(struct sdl_effect *eff);
static struct sdl_effect *raster_blend_new(SDL_Rect *rect, int sx, int sy) {
SDL_Surface *sprite = sdl_dib_to_surface_with_alpha(sx, sy, rect->w, rect->h);
struct sdl_effect *eff = calloc(1, sizeof(struct sdl_effect));
if (!eff)
NOMEMERR();
effect_init(eff, rect, NULL, sprite, EFFECT_RASTER_BLEND);
eff->step = raster_blend_step;
eff->finish = raster_blend_free;
return eff;
}
static void raster_blend_step(struct sdl_effect *eff, float progress) {
SDL_Rect s_rect = { 0, 0, eff->dst_rect.w, 1 };
SDL_Rect d_rect = eff->dst_rect;
d_rect.h = 1;
for (int y = 0; y < eff->dst_rect.h; y++) {
float t = 1.f - 4.f * progress + 3.f * y / eff->dst_rect.h;
d_rect.x = eff->dst_rect.x + (t < 0 ? 0 : sinf(2 * M_PIf * t) * 50);
SDL_RenderCopy(sdl_renderer, eff->tx_new, &s_rect, &d_rect);
s_rect.y++;
d_rect.y++;
}
SDL_RenderPresent(sdl_renderer);
}
static void raster_blend_free(struct sdl_effect *eff) {
effect_finish(eff, false);
free(eff);
}
// -----------------
static SDL_Surface *create_surface(agsurface_t *as, int x, int y, int w, int h) {
@@ -1571,6 +1723,12 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int
case EFFECT_DITHERING_WHITEOUT:
case EFFECT_DITHERING_WHITEIN:
return dithering_fade_new(rect, sf_old, sf_new, type);
case EFFECT_PAN_IN_DOWN:
case EFFECT_PAN_IN_UP:
return pan_in_new(rect, sf_old, sf_new, type);
case EFFECT_SKIP_LINE_UP_DOWN:
case EFFECT_SKIP_LINE_LR_RL:
return skip_line_new(rect, sf_old, sf_new, type);
case EFFECT_WIPE_IN:
case EFFECT_WIPE_OUT:
case EFFECT_WIPE_LR:
@@ -1627,12 +1785,31 @@ struct sdl_effect *sdl_effect_init(SDL_Rect *rect, agsurface_t *old, int ox, int
}
}
struct sdl_effect *sdl_sprite_effect_init(SDL_Rect *rect, int dx, int dy, int sx, int sy, int col, enum sdl_effect_type type) {
SDL_Surface *sf_old = create_surface(sdl_dibinfo, dx, dy, rect->w, rect->h);
SDL_Surface *sprite = sdl_dib_to_surface_colorkey(sx, sy, rect->w, rect->h, col);
switch (type) {
case EFFECT_PAN_IN_DOWN:
case EFFECT_PAN_IN_UP:
return pan_in_new(rect, sf_old, sprite, type);
case EFFECT_SKIP_LINE_UP_DOWN:
case EFFECT_SKIP_LINE_LR_RL:
return skip_line_new(rect, sf_old, sprite, type);
case EFFECT_RASTER_BLEND:
return raster_blend_new(rect, sx, sy);
default:
SYSERROR("Unknown sprite effect %d", type);
return NULL;
}
}
struct sdl_effect *sdl_effect_magnify_init(agsurface_t *surface, SDL_Rect *view_rect, SDL_Rect *target_rect) {
SDL_Surface *sf = create_surface(surface, view_rect->x, view_rect->y, view_rect->w, view_rect->h);
return magnify_new(sf, view_rect, target_rect);
}
void sdl_effect_step(struct sdl_effect *eff, double progress) {
void sdl_effect_step(struct sdl_effect *eff, float progress) {
SDL_RenderClear(sdl_renderer);
if (!eff->is_fullscreen)
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
+12 -18
View File
@@ -204,19 +204,18 @@ void sdl_drawImage24_fromData(cgdata *cg, int x, int y, int brightness) {
SDL_FreeSurface(s);
}
void sdl_copyAreaSP16_shadow(int sx, int sy, int w, int h, int dx, int dy, int lv) {
SDL_Surface *sdl_dib_to_surface_with_alpha(int x, int y, int w, int h) {
SDL_Surface *s = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_ARGB8888);
SDL_Rect r_src = {sx, sy, w, h};
SDL_Rect r_tmp = { 0, 0, w, h};
SDL_BlitSurface(sdl_dib, &r_src, s, &r_tmp);
SDL_Rect r_src = {x, y, w, h};
SDL_BlitSurface(sdl_dib, &r_src, s, NULL);
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
uint8_t *p_ds = s->pixels + 3;
#else
uint8_t *p_ds = s->pixels;
#endif
uint8_t *adata = GETOFFSET_ALPHA(sdl_dibinfo, sx, sy);
uint8_t *adata = GETOFFSET_ALPHA(sdl_dibinfo, x, y);
for (int y = 0; y < h; y++) {
uint8_t *p_src = adata;
uint8_t *p_dst = p_ds;
@@ -227,11 +226,16 @@ void sdl_copyAreaSP16_shadow(int sx, int sy, int w, int h, int dx, int dy, int l
adata += sdl_dibinfo->width;
p_ds += s->pitch;
}
return s;
}
void sdl_copyAreaSP16_shadow(int sx, int sy, int w, int h, int dx, int dy, int lv) {
SDL_Surface *s = sdl_dib_to_surface_with_alpha(sx, sy, w, h);
if (lv < 255)
SDL_SetSurfaceAlphaMod(s, lv);
SDL_Rect r_dst = {dx, dy, w, h};
SDL_BlitSurface(s, &r_tmp, sdl_dib, &r_dst);
SDL_BlitSurface(s, NULL, sdl_dib, &r_dst);
SDL_FreeSurface(s);
}
@@ -241,6 +245,7 @@ void sdl_copyAreaSP16_alphaBlend(int sx, int sy, int w, int h, int dx, int dy, i
SDL_SetSurfaceBlendMode(sdl_dib, SDL_BLENDMODE_BLEND);
SDL_SetSurfaceAlphaMod(sdl_dib, lv);
SDL_BlitSurface(sdl_dib, &r_src, sdl_dib, &r_dst);
SDL_SetSurfaceAlphaMod(sdl_dib, 255);
SDL_SetSurfaceBlendMode(sdl_dib, SDL_BLENDMODE_NONE);
}
@@ -251,6 +256,7 @@ void sdl_copyAreaSP16_alphaLevel(int sx, int sy, int w, int h, int dx, int dy, i
SDL_SetSurfaceAlphaMod(sdl_dib, lv);
SDL_FillRect(sdl_dib, &r_dst, 0);
SDL_BlitSurface(sdl_dib, &r_src, sdl_dib, &r_dst);
SDL_SetSurfaceAlphaMod(sdl_dib, 255);
SDL_SetSurfaceBlendMode(sdl_dib, SDL_BLENDMODE_NONE);
}
@@ -330,18 +336,6 @@ void sdl_putRegion(void *psrc, int x, int y) {
SDL_BlitSurface(src, &r_src, sdl_dib, &r_dst);
}
/*
* dib にセーブした領域からコピー
*/
void sdl_CopyRegion(void *psrc, int sx, int sy, int w,int h, int dx, int dy) {
SDL_Surface *src = (SDL_Surface *)psrc;
SDL_Rect r_src = {sx, sy, w, h};
SDL_Rect r_dst = {dx, dy, w, h};
SDL_BlitSurface(src, &r_src, sdl_dib, &r_dst);
}
/*
* dib に dstを描画後、後始末
*/
+2
View File
@@ -56,6 +56,8 @@ void sdl_event_init(void);
void sdl_cursor_init(void);
int sdl_nearest_color(int r, int g, int b);
boolean sdl_joy_open(int index);
SDL_Surface *sdl_dib_to_surface_with_alpha(int x, int y, int w, int h);
SDL_Surface *sdl_dib_to_surface_colorkey(int x, int y, int w, int h, int col);
extern struct sdl_private_data *sdl_videodev;
-7
View File
@@ -98,17 +98,10 @@ void sdl_Remove(void) {
if (sdl_videodev == NULL) return;
if (sdl_display) {
NOTICE("Now SDL shutdown ... ");
SDL_FreeSurface(sdl_dib);
SDL_DestroyRenderer(sdl_renderer);
SDL_JoystickClose(js);
SDL_Quit();
NOTICE("Done!");
}
}
+5 -2
View File
@@ -461,7 +461,10 @@ void sel_select() {
key = sys_keywait(25, KEYWAIT_CANCELABLE);
// Right-click exits the menu without waiting for button up.
if (key == SYS35KEY_SPC) break;
if (key == SYS35KEY_SPC) {
curElement = -1;
break;
}
if (!key && prevkey == SYS35KEY_RET && curElement != -1) break;
prevkey = key;
@@ -536,7 +539,7 @@ void sel_select() {
msg_nextPage(TRUE);
}
if (prevkey == SYS35KEY_RET) {
if (curElement != -1) {
sl_jmpNear(elmv[curElement]);
if (cb_select_page != 0) {
sl_callFar2(cb_select_page -1, cb_select_address);
-15
View File
@@ -123,12 +123,6 @@ static void sys35_usage(boolean verbose) {
#ifdef ENABLE_MIDI_SDLMIXER
puts(" -Me : SDL_mixer midi player");
#endif
#ifdef ENABLE_MIDI_RAWMIDI
puts(" -Mr : Raw Midi device");
#endif
#ifdef ENABLE_MIDI_SEQMIDI
puts(" -Ms? : Sequenceer device (?:devicenumber)");
#endif
#ifdef ENABLE_MIDI_PORTMIDI
puts(" -Mp? : ALSA (via PortMidi) (?:devicenumber)");
#endif
@@ -288,10 +282,6 @@ static void sys35_ParseOption(int *argc, char **argv) {
if (argv[i + 1] != NULL) {
muscd_set_playlist(argv[i + 1]);
}
} else if (0 == strcmp(argv[i], "-devmidi")) {
if (argv[i + 1] != NULL) {
midi_set_devicename(argv[i + 1]);
}
} else if (0 == strncmp(argv[i], "-M", 2)) {
int subdev = 0;
if (argv[i][3] != '\0') {
@@ -400,11 +390,6 @@ static void check_profile() {
if (param) {
sdl_setJoyDeviceIndex(atoi(param));
}
/* Raw MIDI device name の設定 */
param = get_profile("midi_device");
if (param) {
midi_set_devicename(param);
}
/* MIDI output device の設定 */
param = get_profile("midi_output_device");
if (param) {
-7
View File
@@ -49,11 +49,6 @@
#playlist: playlist.txt
# device name of the raw midi device or sequencer device.
#midi_device: /dev/midi
#midi_device: /dev/sequencer
# Audio buffer size in bytes.
# Too small value causes sound glitches, too large value causes sound delay.
@@ -62,8 +57,6 @@
# MIDI Output method
# 'e' : SDL_mixer (default)
# 'pX' : via PortMidi (X is the device number, usually 0)
# 'r' : raw midi device
# 'sX' : sequencer device (X is the port number, usually 0)
# '0' : disable MIDI
#midi_output_device: e
-133
View File
@@ -1,133 +0,0 @@
%define ver 1.7.3
%define rel 1
Summary: system35 scenario decoder on X
Name: xsystem35
Version: %{ver}pre5
Release: %{rel}
License: GPL
Group: Amusements/Games
Source: http://www.aist-nara.ac.jp/~masaki-c/private/unitbase/xsys35/down/xsystem35-1.7.3pre5.tar.gz
# Source: http://www.aist-nara.ac.jp/~masaki-c/private/unitbase/xsys35/down/test/xsystem35-%{ver}-pre5.tar.gz
Requires: gtk+ >= 1.0.0
BuildPreReq: gtk+-devel
URL: http://www.aist-nara.ac.jp/~masaki-c/private/unitbase/xsys35/index.html
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%description
system35 scenario decoder on X
Xsystem35 enables Alice Soft's games on X.
%description -l ja
アリスソフトのゲームをX上で実行するためのプログラムです。
最初に実行する前に ドキュメントディレクトリの xsys35rc.sample
をホームディレクトリに.xsys35rcとしてコピーしてお使い下さい。
%changelog
%prep
%setup -q
# %setup -q -n %{name}-%{ver}-pre5
#%patch -p1
rm -rf %{buildroot}
%build
./configure --prefix=/usr --enable-audio=oss,alsa,esd --enable-cdrom=linux,mp3 --enable-midi=extp,raw,seq --disable-debug --enable-qmidi
make
%install
%makeinstall
%clean
rm -rf %{buildroot}
%pre
%post
%preun
%postun
%files
%defattr(-, root, root)
%doc ABOUT-NLS COPYING INSTALL doc/* src/xsys35rc.sample
%doc contrib
%doc patch
%{_libdir}/xsystem35/*
%{_bindir}/xsystem35
%{_datadir}/locale/*/LC_MESSAGES/xsystem35*
%changelog
* Sun Dec 21 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.7.2]
- version 1.7.2
* Sun Aug 31 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.7.1]
- version 1.7.1
* Thu May 01 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.7.0]
- version 1.7.0 preX
* Sat Feb 01 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.6.0]
- version 1.6.0
* Sun Jan 05 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.6.0]
- 1.6.0 preX
* Tue May 14 2002 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.5.x]
- revised for xsystem35-1.5.x
* Sun May 1 2001 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.4.0]
- update to xsystem35-1.4.0
* Sun Apr 1 2001 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.3.4]
- update to xsystem35-1.3.4
* Sun Nov 26 2000 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.3.3]
- import spec file from JRPM to tar ball. (Grate thanks to Toshiya Takagi)
* Sun Dec 4 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.4-1]
- Updated to xsystem35-1.2.4
* Sun Sep 5 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.3-2]
- Use TiMidity and mp3 instead of CD-DA
* Thu Aug 26 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.3-1]
- Updated to xsystem35-1.2.3
* Sat Jul 24 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.2-1]
- Updated to xsystem35-1.2.2
* Thu Jun 10 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.1-1]
- Updated to xsystem35-1.2.1
* Mon May 24 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.0-1]
- Updated to xsystem35-1.2.0
* Thu May 13 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
- Changed /usr/local/lib/xsystem35 to /usr/X11R6/lib/xsystem35
* Mon May 3 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
- First release against glibc
-133
View File
@@ -1,133 +0,0 @@
%define ver @VERSION_MA@
%define rel 1
Summary: system35 scenario decoder on X
Name: xsystem35
Version: %{ver}@VERSION_MI@
Release: %{rel}
License: GPL
Group: Amusements/Games
Source: http://www.aist-nara.ac.jp/~masaki-c/private/unitbase/xsys35/down/xsystem35-@VERSION@.tar.gz
# Source: http://www.aist-nara.ac.jp/~masaki-c/private/unitbase/xsys35/down/test/xsystem35-%{ver}-@VERSION_MI@.tar.gz
Requires: gtk+ >= 1.0.0
BuildPreReq: gtk+-devel
URL: http://www.aist-nara.ac.jp/~masaki-c/private/unitbase/xsys35/index.html
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%description
system35 scenario decoder on X
Xsystem35 enables Alice Soft's games on X.
%description -l ja
アリスソフトのゲームをX上で実行するためのプログラムです。
最初に実行する前に ドキュメントディレクトリの xsys35rc.sample
をホームディレクトリに.xsys35rcとしてコピーしてお使い下さい。
%changelog
%prep
%setup -q
# %setup -q -n %{name}-%{ver}-@VERSION_MI@
#%patch -p1
rm -rf %{buildroot}
%build
./configure --prefix=/usr --enable-audio=oss,alsa,esd --enable-cdrom=linux,mp3 --enable-midi=extp,raw,seq --disable-debug --enable-qmidi
make
%install
%makeinstall
%clean
rm -rf %{buildroot}
%pre
%post
%preun
%postun
%files
%defattr(-, root, root)
%doc ABOUT-NLS COPYING INSTALL doc/* src/xsys35rc.sample
%doc contrib
%doc patch
%{_libdir}/xsystem35/*
%{_bindir}/xsystem35
%{_datadir}/locale/*/LC_MESSAGES/xsystem35*
%changelog
* Sun Dec 21 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.7.2]
- version 1.7.2
* Sun Aug 31 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.7.1]
- version 1.7.1
* Thu May 01 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.7.0]
- version 1.7.0 preX
* Sat Feb 01 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.6.0]
- version 1.6.0
* Sun Jan 05 2003 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.6.0]
- 1.6.0 preX
* Tue May 14 2002 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.5.x]
- revised for xsystem35-1.5.x
* Sun May 1 2001 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.4.0]
- update to xsystem35-1.4.0
* Sun Apr 1 2001 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.3.4]
- update to xsystem35-1.3.4
* Sun Nov 26 2000 CHIKAMA Masaki <masaki-c@is.aist-nara.ac.jp>
[xsystem35-1.3.3]
- import spec file from JRPM to tar ball. (Grate thanks to Toshiya Takagi)
* Sun Dec 4 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.4-1]
- Updated to xsystem35-1.2.4
* Sun Sep 5 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.3-2]
- Use TiMidity and mp3 instead of CD-DA
* Thu Aug 26 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.3-1]
- Updated to xsystem35-1.2.3
* Sat Jul 24 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.2-1]
- Updated to xsystem35-1.2.2
* Thu Jun 10 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.1-1]
- Updated to xsystem35-1.2.1
* Mon May 24 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
[xsystem35-1.2.0-1]
- Updated to xsystem35-1.2.0
* Thu May 13 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
- Changed /usr/local/lib/xsystem35 to /usr/X11R6/lib/xsystem35
* Mon May 3 1999 Toshiya Takagi <jwtoshi@mars.dti.ne.jp>
- First release against glibc