update SDL_mixer to SDL3_mixer 3.2.0
@@ -0,0 +1,196 @@
|
||||
#
|
||||
# CMake script for building the SDL examples
|
||||
#
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake")
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckStructHasMember)
|
||||
include(CMakePushCheckState)
|
||||
|
||||
set(SDLMIXER_EXAMPLE_EXECUTABLES)
|
||||
|
||||
if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(example_bin_dir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
if(NOT IS_ABSOLUTE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
set(example_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
endif()
|
||||
else()
|
||||
set(example_bin_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.20)
|
||||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
set(example_bin_dir "${example_bin_dir}$<$<BOOL:${is_multi_config}>:/$<CONFIG>>")
|
||||
endif()
|
||||
|
||||
file(GLOB RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.mp3 ${CMAKE_CURRENT_SOURCE_DIR}/*.wav)
|
||||
|
||||
set(RESOURCE_FILE_NAMES)
|
||||
set(RESOURCE_FILES_BINDIR)
|
||||
foreach(resource_file IN LISTS RESOURCE_FILES)
|
||||
get_filename_component(res_file_name ${resource_file} NAME)
|
||||
list(APPEND RESOURCE_FILE_NAMES "${res_file_name}")
|
||||
set(resource_file_bindir "${example_bin_dir}/${res_file_name}")
|
||||
add_custom_command(OUTPUT "${resource_file_bindir}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${resource_file}" "${resource_file_bindir}"
|
||||
DEPENDS "${resource_file}"
|
||||
)
|
||||
list(APPEND RESOURCE_FILES_BINDIR "${resource_file_bindir}")
|
||||
endforeach()
|
||||
add_custom_target(copy-sdlmixer-example-resources
|
||||
DEPENDS "${RESOURCE_FILES_BINDIR}"
|
||||
)
|
||||
|
||||
set(SDLMIXER_EXAMPLE_EXECUTABLES)
|
||||
|
||||
macro(add_sdlmixer_example_executable TARGET)
|
||||
cmake_parse_arguments(AST "BUILD_DEPENDENT" "" "SOURCES;DATAFILES" ${ARGN})
|
||||
if(AST_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown argument(s): ${AST_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
if(NOT AST_SOURCES)
|
||||
message(FATAL_ERROR "add_sdlmixer_example_executable needs at least one source")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
add_library(${TARGET} SHARED ${AST_SOURCES} ${AST_DATAFILES})
|
||||
else()
|
||||
add_executable(${TARGET} ${AST_SOURCES} ${AST_DATAFILES})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${TARGET}
|
||||
PRIVATE
|
||||
$<TARGET_PROPERTY:${sdl3_mixer_target_name},COMPILE_DEFINITIONS>
|
||||
)
|
||||
sdl_add_warning_options(${TARGET} WARNING_AS_ERROR ${SDLMIXER_WERROR})
|
||||
|
||||
target_link_libraries(${TARGET} PRIVATE SDL3_mixer::SDL3_mixer SDL3::SDL3)
|
||||
|
||||
list(APPEND SDLMIXER_EXAMPLE_EXECUTABLES ${TARGET})
|
||||
if(AST_DATAFILES)
|
||||
if(PSP OR PS2)
|
||||
add_custom_command(TARGET ${TARGET} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E make_directory $<TARGET_FILE_DIR:${TARGET}>/sdl-${TARGET}
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${AST_DATAFILES} $<TARGET_FILE_DIR:${TARGET}>/sdl-${TARGET}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
elseif(NOT APPLE AND NOT N3DS)
|
||||
add_dependencies(${TARGET} copy-sdlmixer-example-resources)
|
||||
endif()
|
||||
if(EMSCRIPTEN)
|
||||
foreach(res IN LISTS AST_DATAFILES)
|
||||
get_filename_component(res_name "${res}" NAME)
|
||||
target_link_options(${TARGET} PRIVATE "SHELL:--embed-file ${res}@${res_name}")
|
||||
endforeach()
|
||||
endif()
|
||||
set_property(TARGET ${TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES "$<TARGET_FILE_DIR:${TARGET}>/$<JOIN:${AST_DATAFILES},$<SEMICOLON>$<TARGET_FILE_DIR:${TARGET}>/>")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# Set Apple App ID / Bundle ID. This is needed to launch apps on some Apple
|
||||
# platforms (iOS, for example).
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
RESOURCES "${AST_DATAFILES}"
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.libsdl.${TARGET}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${SDL3_VERSION}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${SDL3_VERSION}"
|
||||
)
|
||||
set_property(SOURCE ${AST_DATAFILES} PROPERTY MACOSX_PACKAGE_LOCATION "Resources")
|
||||
elseif(WINDOWS)
|
||||
# CET support was added in VS 16.7
|
||||
if(MSVC_VERSION GREATER 1926 AND CMAKE_GENERATOR_PLATFORM MATCHES "Win32|x64")
|
||||
set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -CETCOMPAT")
|
||||
endif()
|
||||
elseif(EMSCRIPTEN)
|
||||
set_property(TARGET ${TARGET} PROPERTY SUFFIX ".html")
|
||||
target_link_options(${TARGET} PRIVATE -sALLOW_MEMORY_GROWTH=1)
|
||||
elseif(N3DS)
|
||||
set(ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/romfs/${TARGET}")
|
||||
file(MAKE_DIRECTORY "${ROMFS_DIR}")
|
||||
file(COPY ${AST_DATAFILES} DESTINATION "${ROMFS_DIR}")
|
||||
ctr_generate_smdh("${TARGET}.smdh"
|
||||
NAME "SDL-${TARGET}"
|
||||
DESCRIPTION "SDL3 example application"
|
||||
AUTHOR "SDL3 Contributors"
|
||||
ICON "${CMAKE_CURRENT_SOURCE_DIR}/../test/n3ds/logo48x48.png"
|
||||
)
|
||||
ctr_create_3dsx(
|
||||
${TARGET}
|
||||
ROMFS "${ROMFS_DIR}"
|
||||
SMDH "${TARGET}.smdh"
|
||||
)
|
||||
elseif(NGAGE)
|
||||
string(MD5 TARGET_MD5 "${TARGET}")
|
||||
string(SUBSTRING "${TARGET_MD5}" 0 8 TARGET_MD5_8)
|
||||
target_link_options(${TARGET} PRIVATE "SHELL:-s UID3=0x${TARGET_MD5_8}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
add_sdlmixer_example_executable(basics-load-and-play SOURCES basics/01-load-and-play/load-and-play.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/music.mp3)
|
||||
add_sdlmixer_example_executable(basics-play-with-options SOURCES basics/02-play-with-options/play-with-options.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/music.mp3)
|
||||
add_sdlmixer_example_executable(basics-play-multiple-sounds SOURCES basics/03-play-multiple-sounds/play-multiple-sounds.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/music.mp3 ${CMAKE_CURRENT_SOURCE_DIR}/sword.wav)
|
||||
add_sdlmixer_example_executable(basics-metadata SOURCES basics/04-metadata/metadata.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/music.mp3)
|
||||
add_sdlmixer_example_executable(basics-sinewave SOURCES basics/05-sinewave/sinewave.c)
|
||||
add_sdlmixer_example_executable(basics-seeking SOURCES basics/06-seeking/seeking.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/music.mp3)
|
||||
|
||||
# When you add an example, remember to add the Visual Studio project as well:
|
||||
# - Add a new example in examples/
|
||||
# - Run python VisualC/examples/generate.py
|
||||
# - Take note of the newly generated .vcxproj files
|
||||
# - Modify the .vcxproj files if necessary (adding content such as PNG or WAV files)
|
||||
# - Open VisualC/SDL.sln in Visual Studio or JetBrains Rider
|
||||
# - Locate the appropriate folder in the Solution Explorer
|
||||
# - Add the newly generated projects: Right click -> Add -> Existing project...
|
||||
# - Test if they work
|
||||
# - Save the SDL.sln solution
|
||||
|
||||
if(PSP)
|
||||
# Build EBOOT files if building for PSP
|
||||
foreach(APP ${SDLMIXER_EXAMPLE_EXECUTABLES})
|
||||
create_pbp_file(
|
||||
TARGET ${APP}
|
||||
TITLE SDL-${APP}
|
||||
ICON_PATH NULL
|
||||
BACKGROUND_PATH NULL
|
||||
PREVIEW_PATH NULL
|
||||
OUTPUT_DIR $<TARGET_FILE_DIR:${APP}>/sdl-${APP}
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(RISCOS)
|
||||
set(SDL_EXAMPLE_EXECUTABLES_AIF)
|
||||
foreach(APP ${SDLMIXER_EXAMPLE_EXECUTABLES})
|
||||
set_property(TARGET ${APP} APPEND_STRING PROPERTY LINK_FLAGS " -static")
|
||||
add_custom_command(
|
||||
OUTPUT ${APP},ff8
|
||||
COMMAND elf2aif ${APP} ${APP},ff8
|
||||
DEPENDS ${APP}
|
||||
)
|
||||
add_custom_target(${APP}-aif ALL DEPENDS ${APP},ff8)
|
||||
list(APPEND SDL_EXAMPLE_EXECUTABLES_AIF ${CMAKE_CURRENT_BINARY_DIR}/${APP},ff8)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(SDLMIXER_EXAMPLES_INSTALL)
|
||||
if(RISCOS)
|
||||
install(
|
||||
FILES ${SDL_EXAMPLE_EXECUTABLES_AIF}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3_mixer
|
||||
)
|
||||
else()
|
||||
install(
|
||||
TARGETS ${SDLMIXER_EXAMPLE_EXECUTABLES}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3_mixer
|
||||
)
|
||||
endif()
|
||||
if(MSVC)
|
||||
foreach(example IN LISTS SDLMIXER_EXAMPLE_EXECUTABLES)
|
||||
SDL_install_pdb(${example} "${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3_mixer")
|
||||
endforeach()
|
||||
endif()
|
||||
install(
|
||||
FILES ${RESOURCE_FILES}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3_mixer
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,82 @@
|
||||
# Examples
|
||||
|
||||
## What is this?
|
||||
|
||||
In here are a collection of standalone SDL_mixer application examples. Unless
|
||||
otherwise stated, they should work on all supported platforms out of the box.
|
||||
If they don't [please file a bug to let us know](https://github.com/libsdl-org/SDL_mixer/issues/new).
|
||||
|
||||
|
||||
## What is this SDL_AppIterate thing?
|
||||
|
||||
SDL can optionally build apps as a collection of callbacks instead of the
|
||||
usual program structure that starts and ends in a function called `main`.
|
||||
The examples use this format for two reasons.
|
||||
|
||||
First, it allows the examples to work when built as web applications without
|
||||
a pile of ugly `#ifdef`s, and all of these examples are published on the web
|
||||
at [examples.libsdl.org](https://examples.libsdl.org/), so you can easily see
|
||||
them in action.
|
||||
|
||||
Second, it's example code! The callbacks let us cleanly break the program up
|
||||
into the four logical pieces most apps care about:
|
||||
|
||||
- Program startup
|
||||
- Event handling
|
||||
- What the program actually does in a single frame
|
||||
- Program shutdown
|
||||
|
||||
A detailed technical explanation of these callbacks is in
|
||||
docs/README-main-functions.md (or view that page on the web on
|
||||
[the wiki](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3)).
|
||||
|
||||
|
||||
## I would like to build and run these examples myself.
|
||||
|
||||
When you build SDL with CMake, you can add `-DSDLMIXER_EXAMPLES=On` to the
|
||||
CMake command line. When you build SDL_mixer, these examples will be built
|
||||
with it.
|
||||
|
||||
But most of these can just be built as a single .c file, as long as you point
|
||||
your compiler at SDL3 and SDL3_mixer's headers and link against both of those
|
||||
libraries.
|
||||
|
||||
|
||||
## What is the license on the example code? Can I paste this into my project?
|
||||
|
||||
All code in the examples directory is considered public domain! You can do
|
||||
anything you like with it, including copy/paste it into your closed-source
|
||||
project, sell it, and pretend you wrote it yourself. We do not require you to
|
||||
give us credit for this code (but we always appreciate if you do!).
|
||||
|
||||
This is only true for the examples directory. The rest of SDL and SDL_mixer
|
||||
fall under the [zlib license](https://github.com/libsdl-org/SDL_mixer/blob/main/LICENSE.txt).
|
||||
|
||||
|
||||
## What is template.html and highlight-plugin.lua in this directory?
|
||||
|
||||
This is what [examples.libsdl.org](https://examples.libsdl.org/) uses when
|
||||
generating the web versions of these example programs. You can ignore this,
|
||||
unless you are improving it, in which case we definitely would love to hear
|
||||
from you!
|
||||
|
||||
|
||||
## What is template.c in this directory?
|
||||
|
||||
If writing new examples, this is the skeleton code we start from, to keep
|
||||
everything consistent. You can ignore it.
|
||||
|
||||
|
||||
## License for the audio files:
|
||||
|
||||
- music.mp3:
|
||||
Arcade Music Loop.wav by joshuaempyre ( https://www.empyreanma.com/welcome )
|
||||
(We converted this to MP3 format.)
|
||||
Original: https://freesound.org/s/251461/
|
||||
License: https://creativecommons.org/licenses/by/4.0/
|
||||
|
||||
- sword.wav:
|
||||
sword04.wav by Erdie
|
||||
Original: https://freesound.org/s/27858/
|
||||
License: https://creativecommons.org/licenses/by/4.0/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
This example code creates a mixer, loads a single sound, and plays it once.
|
||||
|
||||
(Remember that web browsers won't make sound until you click on the page!)
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* This example code creates a mixer, loads a single sound, and plays it once.
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
static MIX_Mixer *mixer = NULL;
|
||||
static MIX_Track *track = NULL;
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
char *path = NULL;
|
||||
MIX_Audio *audio = NULL;
|
||||
|
||||
SDL_SetAppMetadata("Example Load And Play", "1.0", "com.example.load-and-play");
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. Optional! */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* we don't need video, but we'll make a window for smooth operation. */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/basic/load-and-play", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!MIX_Init()) {
|
||||
SDL_Log("Couldn't init SDL_mixer library: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a mixer on the default audio device. Don't care about the specific audio format. */
|
||||
mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
|
||||
if (!mixer) {
|
||||
SDL_Log("Couldn't create mixer on default device: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* load a sound file */
|
||||
SDL_asprintf(&path, "%smusic.mp3", SDL_GetBasePath()); /* allocate a string of the full file path */
|
||||
audio = MIX_LoadAudio(mixer, path, false);
|
||||
if (!audio) {
|
||||
SDL_Log("Couldn't load %s: %s", path, SDL_GetError());
|
||||
SDL_free(path);
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_free(path); /* done with this, the file is loaded. */
|
||||
|
||||
/* we need a track on the mixer to play the audio. Each track has audio assigned to it, and
|
||||
all playing tracks are mixed together for the final output. */
|
||||
|
||||
track = MIX_CreateTrack(mixer);
|
||||
if (!track) {
|
||||
SDL_Log("Couldn't create a mixer track: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
MIX_SetTrackAudio(track, audio);
|
||||
|
||||
/* start the audio playing! */
|
||||
MIX_PlayTrack(track, 0); /* no extra options this time, so a zero for the second argument. */
|
||||
|
||||
/* we don't save `audio`; SDL_mixer will clean it up for us during MIX_Quit(). */
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
/* draw a blank video frame to keep the OS happy */
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
/* when the track has finished playing, end the program. */
|
||||
if (!MIX_TrackPlaying(track)) {
|
||||
return SDL_APP_SUCCESS;
|
||||
}
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us, MIX_Quit() destroys any mixer objects we made. */
|
||||
MIX_Quit();
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,4 @@
|
||||
This example code creates a mixer, loads a single sound, and plays it, with
|
||||
several playback options (fade-in, loop, etc).
|
||||
|
||||
(Remember that web browsers won't make sound until you click on the page!)
|
||||
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* This example code creates a mixer, loads a single sound, and plays it, with
|
||||
* several playback options (fade-in, loop, etc).
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
static MIX_Mixer *mixer = NULL;
|
||||
static MIX_Track *track = NULL;
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
char *path = NULL;
|
||||
MIX_Audio *audio = NULL;
|
||||
SDL_PropertiesID options = 0;
|
||||
|
||||
SDL_SetAppMetadata("Example Play With Options", "1.0", "com.example.play-with-options");
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. Optional! */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* we don't need video, but we'll make a window for smooth operation. */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/basic/play-with-options", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!MIX_Init()) {
|
||||
SDL_Log("Couldn't init SDL_mixer library: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a mixer on the default audio device. Don't care about the specific audio format. */
|
||||
mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
|
||||
if (!mixer) {
|
||||
SDL_Log("Couldn't create mixer on default device: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* load a sound file */
|
||||
SDL_asprintf(&path, "%smusic.mp3", SDL_GetBasePath()); /* allocate a string of the full file path */
|
||||
audio = MIX_LoadAudio(mixer, path, false);
|
||||
if (!audio) {
|
||||
SDL_Log("Couldn't load %s: %s", path, SDL_GetError());
|
||||
SDL_free(path);
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_free(path); /* done with this, the file is loaded. */
|
||||
|
||||
/* we need a track on the mixer to play the audio. Each track has audio assigned to it, and
|
||||
all playing tracks are mixed together for the final output. */
|
||||
|
||||
track = MIX_CreateTrack(mixer);
|
||||
if (!track) {
|
||||
SDL_Log("Couldn't create a mixer track: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
MIX_SetTrackAudio(track, audio);
|
||||
|
||||
/* start the audio playing! */
|
||||
options = SDL_CreateProperties();
|
||||
if (!options) {
|
||||
SDL_Log("Couldn't create play options: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* note these all use MILLISECONDS, since the track is generic, but you can use equivalent FRAMES properties, for frame-perfect mixing. */
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_START_MILLISECOND_NUMBER, 1000); /* start the first loop 1 second into the audio. */
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_MAX_MILLISECONDS_NUMBER, 10000); /* play at most 10 seconds of audio before ending/looping (since we started 1000 in, this will be the eleventh second). */
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, 2); /* loop 2 times, 3rd time through doesn't loop. */
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOP_START_MILLISECOND_NUMBER, 2000); /* when looping, start again here instead of the start of the track. */
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER, 5000); /* fade-in the first loop over five seconds. No fade on the loops, unless the initial fade is still in progress! */
|
||||
MIX_PlayTrack(track, options);
|
||||
SDL_DestroyProperties(options); /* MIX_PlayTrack makes a copy of the options, so this can go away. */
|
||||
|
||||
/* we don't save `audio`; SDL_mixer will clean it up for us during MIX_Quit(). */
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
/* draw a blank video frame to keep the OS happy */
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
/* when the track has finished playing, end the program. */
|
||||
if (!MIX_TrackPlaying(track)) {
|
||||
return SDL_APP_SUCCESS;
|
||||
}
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us, MIX_Quit() destroys any mixer objects we made. */
|
||||
MIX_Quit();
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,3 @@
|
||||
This example code creates a mixer, loads two sounds, and mixes them.
|
||||
|
||||
(Remember that web browsers won't make sound until you click on the page!)
|
||||
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This example code creates a mixer, loads two sounds, and mixes them.
|
||||
*
|
||||
* SDL_mixer is, of course, a mixer, so here are two sounds mixing together!
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
static MIX_Mixer *mixer = NULL;
|
||||
static MIX_Track *track1 = NULL;
|
||||
|
||||
static MIX_Audio *load_audio(const char *fname)
|
||||
{
|
||||
char *path = NULL;
|
||||
MIX_Audio *audio;
|
||||
SDL_asprintf(&path, "%s%s", SDL_GetBasePath(), fname); /* allocate a string of the full file path */
|
||||
audio = MIX_LoadAudio(mixer, path, false);
|
||||
if (!audio) {
|
||||
SDL_Log("Couldn't load %s: %s", path, SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_free(path); /* done with this. */
|
||||
return audio;
|
||||
}
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
MIX_Audio *music = NULL;
|
||||
MIX_Audio *sound = NULL;
|
||||
MIX_Track *track2 = NULL;
|
||||
SDL_PropertiesID options = 0;
|
||||
|
||||
SDL_SetAppMetadata("Example Play Multiple Sounds", "1.0", "com.example.play-multiple-sounds");
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. Optional! */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* we don't need video, but we'll make a window for smooth operation. */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/basic/play-multiple-sounds", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!MIX_Init()) {
|
||||
SDL_Log("Couldn't init SDL_mixer library: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a mixer on the default audio device. Don't care about the specific audio format. */
|
||||
mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
|
||||
if (!mixer) {
|
||||
SDL_Log("Couldn't create mixer on default device: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* load our audio files. Note that you can use any supported file format! */
|
||||
music = load_audio("music.mp3");
|
||||
if (!music) {
|
||||
return SDL_APP_FAILURE; /* we reported the error in load_audio */
|
||||
}
|
||||
sound = load_audio("sword.wav");
|
||||
if (!sound) {
|
||||
return SDL_APP_FAILURE; /* we reported the error in load_audio */
|
||||
}
|
||||
|
||||
/* we need a track on the mixer to play the audio. Each track has audio assigned to it, and
|
||||
all playing tracks are mixed together for the final output. */
|
||||
|
||||
track1 = MIX_CreateTrack(mixer);
|
||||
if (!track1) {
|
||||
SDL_Log("Couldn't create a mixer track: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
MIX_SetTrackAudio(track1, music);
|
||||
|
||||
track2 = MIX_CreateTrack(mixer);
|
||||
if (!track2) {
|
||||
SDL_Log("Couldn't create a mixer track: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
MIX_SetTrackAudio(track2, sound);
|
||||
options = SDL_CreateProperties();
|
||||
if (!options) {
|
||||
SDL_Log("Couldn't create play options: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, -1); /* loop forever. */
|
||||
|
||||
/* start the audio playing! music plays through once, with the sound effect playing in a loop at the same time. */
|
||||
MIX_PlayTrack(track1, 0); /* no extra options this time, so a zero for the second argument. */
|
||||
MIX_PlayTrack(track2, options);
|
||||
SDL_DestroyProperties(options); /* MIX_PlayTrack makes a copy of the options, so this can go away. */
|
||||
|
||||
/* we don't save `music`, `sound`, or `track2`; SDL_mixer will clean them up for us during MIX_Quit(). */
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
/* draw a blank video frame to keep the OS happy */
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
/* when the music has finished playing, end the program. */
|
||||
if (!MIX_TrackPlaying(track1)) {
|
||||
return SDL_APP_SUCCESS;
|
||||
}
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us, MIX_Quit() destroys any mixer objects we made. */
|
||||
MIX_Quit();
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1 @@
|
||||
This example code loads a single sound, and displays metadata.
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This example code loads a single sound, and displays metadata.
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
|
||||
static MIX_Audio *audio = NULL;
|
||||
static char *path = NULL;
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
SDL_SetAppMetadata("Example Metadata", "1.0", "com.example.metadata");
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. Optional! */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* we don't need video, but we'll make a window for smooth operation. */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/basic/metadata", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!MIX_Init()) {
|
||||
SDL_Log("Couldn't init SDL_mixer library: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_asprintf(&path, "%smusic.mp3", SDL_GetBasePath()); /* allocate a string of the full file path */
|
||||
audio = MIX_LoadAudio(NULL, path, false); /* MIX_Audios are shared between mixers, so you can pass a NULL mixer here; non-NULL just lets it optimize for a specific output. */
|
||||
|
||||
/* if MIX_LoadAudio failed, it's okay, the user can drop a new file on the window. */
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
} else if (event->type == SDL_EVENT_DROP_FILE) {
|
||||
MIX_DestroyAudio(audio);
|
||||
SDL_free(path);
|
||||
path = SDL_strdup(event->drop.data);
|
||||
audio = MIX_LoadAudio(NULL, path, false);
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
static void SDLCALL RenderMetadata(void *userdata, SDL_PropertiesID props, const char *name)
|
||||
{
|
||||
float *y = (float *) userdata;
|
||||
|
||||
switch (SDL_GetPropertyType(props, name)) {
|
||||
case SDL_PROPERTY_TYPE_INVALID:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [invalid type]", name);
|
||||
break;
|
||||
|
||||
case SDL_PROPERTY_TYPE_POINTER:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [pointer=%p]", name, SDL_GetPointerProperty(props, name, NULL));
|
||||
break;
|
||||
|
||||
case SDL_PROPERTY_TYPE_STRING:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [string=\"%s\"]", name, SDL_GetStringProperty(props, name, ""));
|
||||
break;
|
||||
|
||||
case SDL_PROPERTY_TYPE_NUMBER:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [number=%" SDL_PRIs64 "]", name, SDL_GetNumberProperty(props, name, 0));
|
||||
break;
|
||||
|
||||
case SDL_PROPERTY_TYPE_FLOAT:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [float=%f]", name, SDL_GetFloatProperty(props, name, 0.0f));
|
||||
break;
|
||||
|
||||
case SDL_PROPERTY_TYPE_BOOLEAN:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [boolean=%s]", name, SDL_GetBooleanProperty(props, name, false) ? "true" : "false");
|
||||
break;
|
||||
|
||||
default:
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, *y, " - %s [unknown type]", name);
|
||||
break;
|
||||
}
|
||||
|
||||
*y += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2;
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
/* audio file metadata is stored in an SDL Properties group; you can also hang any app-specific metadata on here, too! */
|
||||
SDL_PropertiesID props = MIX_GetAudioProperties(audio);
|
||||
SDL_AudioSpec audiospec;
|
||||
float y = 0.0f;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black */
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); /* white */
|
||||
|
||||
MIX_GetAudioFormat(audio, &audiospec);
|
||||
SDL_RenderDebugText(renderer, 0.0f, y, "== Drop a file on this window to get its metadata. ==");
|
||||
y += (float) SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2.0f;
|
||||
|
||||
if (audio) {
|
||||
SDL_RenderDebugText(renderer, 0.0f, y, path);
|
||||
y += (float) SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE + 2.0f;
|
||||
|
||||
SDL_RenderDebugTextFormat(renderer, 0.0f, y, "%s, %d channel%s, %d freq",
|
||||
SDL_GetAudioFormatName(audiospec.format),
|
||||
audiospec.channels,
|
||||
(audiospec.channels == 1) ? "" : "s",
|
||||
audiospec.freq);
|
||||
y += (float) SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * 2.0f;
|
||||
|
||||
/* now draw all the metadata. It happens in the RenderMetadata function, once per metadata item. */
|
||||
SDL_EnumerateProperties(props, RenderMetadata, &y);
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us, MIX_Quit() destroys any mixer objects we made. */
|
||||
MIX_Quit();
|
||||
SDL_free(path);
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,3 @@
|
||||
This example code creates a mixer, and plays a sinewave forever.
|
||||
|
||||
(Remember that web browsers won't make sound until you click on the page!)
|
||||
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This example code creates a mixer, and plays a sinewave forever.
|
||||
*
|
||||
* It's not super-useful to play a sinewave, but it is _something_
|
||||
* to play if you don't have anything else, and it's built-in to
|
||||
* SDL_mixer.
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
MIX_Mixer *mixer = NULL;
|
||||
MIX_Audio *audio = NULL;
|
||||
MIX_Track *track = NULL;
|
||||
|
||||
SDL_SetAppMetadata("Example Load And Play", "1.0", "com.example.load-and-play");
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. Optional! */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* we don't need video, but we'll make a window for smooth operation. */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/basic/load-and-play", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!MIX_Init()) {
|
||||
SDL_Log("Couldn't init SDL_mixer library: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a mixer on the default audio device. Don't care about the specific audio format. */
|
||||
mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
|
||||
if (!mixer) {
|
||||
SDL_Log("Couldn't create mixer on default device: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
audio = MIX_CreateSineWaveAudio(mixer, 300, 0.25f, -1); // -1: play forever. You can specify milliseconds otherwise to have a limit.
|
||||
if (!audio) {
|
||||
SDL_Log("Couldn't generate sinewave: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* we need a track on the mixer to play the audio. Each track has audio assigned to it, and
|
||||
all playing tracks are mixed together for the final output. */
|
||||
|
||||
track = MIX_CreateTrack(mixer);
|
||||
if (!track) {
|
||||
SDL_Log("Couldn't create a mixer track: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
MIX_SetTrackAudio(track, audio);
|
||||
|
||||
/* start the audio playing! */
|
||||
MIX_PlayTrack(track, 0); /* no extra options this time, so a zero for the second argument. */
|
||||
|
||||
/* we don't save `mixer`, `audio`, or `track`; SDL_mixer will clean it up for us during MIX_Quit(). */
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
/* draw a blank video frame to keep the OS happy */
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
/* there's nothing for use to do here, the sinewave will play forever until the app is manually quit. */
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us, MIX_Quit() destroys any mixer objects we made. */
|
||||
MIX_Quit();
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,4 @@
|
||||
This example code creates a mixer, loads a single sound, and plays it on loop,
|
||||
letting the user seek around in playback with a slider.
|
||||
|
||||
(Remember that web browsers won't make sound until you click on the page!)
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This example code creates a mixer, loads a single sound, and plays it on
|
||||
* loop, letting the user seek around in playback with a slider.
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
static MIX_Mixer *mixer = NULL;
|
||||
static MIX_Audio *audio = NULL;
|
||||
static MIX_Track *track = NULL;
|
||||
|
||||
#define KNOB_WIDTH 30
|
||||
static const SDL_FRect progressbar = { 120, 225, 400, 75 };
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
char *path = NULL;
|
||||
SDL_PropertiesID options = 0;
|
||||
|
||||
SDL_SetAppMetadata("Example Seeking", "1.0", "com.example.seeking");
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. Optional! */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* we don't need video, but we'll make a window for smooth operation. */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/basic/seeking", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!MIX_Init()) {
|
||||
SDL_Log("Couldn't init SDL_mixer library: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a mixer on the default audio device. Don't care about the specific audio format. */
|
||||
mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
|
||||
if (!mixer) {
|
||||
SDL_Log("Couldn't create mixer on default device: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* load a sound file */
|
||||
SDL_asprintf(&path, "%smusic.mp3", SDL_GetBasePath()); /* allocate a string of the full file path */
|
||||
audio = MIX_LoadAudio(mixer, path, false);
|
||||
if (!audio) {
|
||||
SDL_Log("Couldn't load %s: %s", path, SDL_GetError());
|
||||
SDL_free(path);
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_free(path); /* done with this, the file is loaded. */
|
||||
|
||||
/* we need a track on the mixer to play the audio. Each track has audio assigned to it, and
|
||||
all playing tracks are mixed together for the final output. */
|
||||
|
||||
track = MIX_CreateTrack(mixer);
|
||||
if (!track) {
|
||||
SDL_Log("Couldn't create a mixer track: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
MIX_SetTrackAudio(track, audio);
|
||||
|
||||
/* start the audio playing! */
|
||||
options = SDL_CreateProperties();
|
||||
if (!options) {
|
||||
SDL_Log("Couldn't create play options: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
/* note these all use MILLISECONDS, since the track is generic, but you can use equivalent FRAMES properties, for frame-perfect mixing. */
|
||||
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, -1); /* loop forever */
|
||||
MIX_PlayTrack(track, options);
|
||||
SDL_DestroyProperties(options); /* MIX_PlayTrack makes a copy of the options, so this can go away. */
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
static void seek_audio(float x, float y)
|
||||
{
|
||||
const SDL_FPoint pt = { x, y };
|
||||
if (SDL_PointInRectFloat(&pt, &progressbar)) {
|
||||
/* seek to a new position in the track, based on where the mouse clicked/dragged in the progress bar. */
|
||||
const float pct = (pt.x - progressbar.x) / progressbar.w;
|
||||
MIX_SetTrackPlaybackPosition(track, (Sint64) ((float) MIX_GetAudioDuration(audio) * pct));
|
||||
}
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
} else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||
if (event->button.button == 1) {
|
||||
seek_audio(event->button.x, event->button.y);
|
||||
}
|
||||
} else if (event->type == SDL_EVENT_MOUSE_MOTION) {
|
||||
if (event->motion.state & SDL_BUTTON_LMASK) {
|
||||
seek_audio(event->motion.x, event->motion.y);
|
||||
}
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
SDL_FRect knob = { progressbar.x, progressbar.y, KNOB_WIDTH, progressbar.h };
|
||||
knob.x += (progressbar.w - knob.w) * (((float) MIX_GetTrackPlaybackPosition(track)) / ((float) MIX_GetAudioDuration(audio)));
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 100, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
|
||||
SDL_RenderFillRect(renderer, &progressbar);
|
||||
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||
SDL_RenderFillRect(renderer, &knob);
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us, MIX_Quit() destroys any mixer objects we made. */
|
||||
MIX_Quit();
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 416 B |
@@ -0,0 +1,100 @@
|
||||
-- This code adapted from https://gitlab.com/saalen/highlight/-/wikis/Plug-Ins
|
||||
|
||||
-- first add a description of what the plug-in does
|
||||
Description="Add wiki.libsdl.org reference links to HTML, LaTeX or RTF output"
|
||||
|
||||
-- define the plugin categories (ie. supported output formats; languages)
|
||||
Categories = { "c", "c++" }
|
||||
|
||||
-- the syntaxUpdate function contains code related to syntax recognition
|
||||
function syntaxUpdate(desc)
|
||||
|
||||
-- if the current file is not C/C++ file we exit
|
||||
if desc~="C and C++" then
|
||||
return
|
||||
end
|
||||
|
||||
-- this function returns a qt-project reference link of the given token
|
||||
function getSDLURL(token)
|
||||
-- generate the URL
|
||||
url='https://wiki.libsdl.org/SDL3/'.. token
|
||||
|
||||
-- embed the URL in a hyperlink according to the output format
|
||||
-- first HTML, then LaTeX and RTF
|
||||
if (HL_OUTPUT== HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML) then
|
||||
return '<a class="hl" target="new" href="'
|
||||
.. url .. '">'.. token .. '</a>'
|
||||
elseif (HL_OUTPUT == HL_FORMAT_LATEX) then
|
||||
return '\\href{'..url..'}{'..token..'}'
|
||||
elseif (HL_OUTPUT == HL_FORMAT_RTF) then
|
||||
return '{{\\field{\\*\\fldinst HYPERLINK "'
|
||||
..url..'" }{\\fldrslt\\ul\\ulc0 '..token..'}}}'
|
||||
end
|
||||
end
|
||||
|
||||
function getMixerURL(token)
|
||||
-- generate the URL
|
||||
url='https://wiki.libsdl.org/SDL3_mixer/'.. token
|
||||
|
||||
-- embed the URL in a hyperlink according to the output format
|
||||
-- first HTML, then LaTeX and RTF
|
||||
if (HL_OUTPUT== HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML) then
|
||||
return '<a class="hl" target="new" href="'
|
||||
.. url .. '">'.. token .. '</a>'
|
||||
elseif (HL_OUTPUT == HL_FORMAT_LATEX) then
|
||||
return '\\href{'..url..'}{'..token..'}'
|
||||
elseif (HL_OUTPUT == HL_FORMAT_RTF) then
|
||||
return '{{\\field{\\*\\fldinst HYPERLINK "'
|
||||
..url..'" }{\\fldrslt\\ul\\ulc0 '..token..'}}}'
|
||||
end
|
||||
end
|
||||
|
||||
-- the Decorate function will be invoked for every recognized token
|
||||
function Decorate(token, state)
|
||||
|
||||
-- we are only interested in keywords, preprocessor or default items
|
||||
if (state ~= HL_STANDARD and state ~= HL_KEYWORD and
|
||||
state ~=HL_PREPROC) then
|
||||
return
|
||||
end
|
||||
|
||||
-- SDL keywords start with SDL_
|
||||
-- SDL_mixer keywords start with MIX_
|
||||
-- if this pattern applies to the token, we return the URL
|
||||
-- if we return nothing, the token is outputted as is
|
||||
if ( (token == "Uint8") or (token == "Uint16") or (token == "Uint32") or (token == "Uint64") or
|
||||
(token == "Sint8") or (token == "Sint16") or (token == "Sint32") or (token == "Sint64") or
|
||||
(string.find(token, "SDL_") == 1) ) then
|
||||
return getSDLURL(token)
|
||||
end
|
||||
|
||||
if (string.find(token, "MIX_") == 1) then
|
||||
return getMixerURL(token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- the themeUpdate function contains code related to the theme
|
||||
function themeUpdate(desc)
|
||||
-- the Injections table can be used to add style information to the theme
|
||||
|
||||
-- HTML: we add additional CSS style information to beautify hyperlinks,
|
||||
-- they should have the same color as their surrounding tags
|
||||
if (HL_OUTPUT == HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML) then
|
||||
Injections[#Injections+1]=
|
||||
"a.hl, a.hl:visited {color:inherit;font-weight:inherit;text-decoration:none}"
|
||||
|
||||
-- LaTeX: hyperlinks require the hyperref package, so we add this here
|
||||
-- the colorlinks and pdfborderstyle options remove ugly boxes in the output
|
||||
elseif (HL_OUTPUT==HL_FORMAT_LATEX) then
|
||||
Injections[#Injections+1]=
|
||||
"\\usepackage[colorlinks=false, pdfborderstyle={/S/U/W 1}]{hyperref}"
|
||||
end
|
||||
end
|
||||
|
||||
-- let highlight load the chunks
|
||||
Plugins={
|
||||
{ Type="lang", Chunk=syntaxUpdate },
|
||||
{ Type="theme", Chunk=themeUpdate },
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
This is for generating thumbnails and videos of examples. Just include it
|
||||
temporarily and let it override SDL_RenderPresent, etc, and it'll dump each
|
||||
frame rendered to a new .png file.
|
||||
*/
|
||||
|
||||
static bool SAVERENDERING_SDL_RenderPresent(SDL_Renderer *renderer)
|
||||
{
|
||||
static unsigned int framenum = 0;
|
||||
SDL_Surface *surface = SDL_RenderReadPixels(renderer, NULL);
|
||||
if (!surface) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to read pixels for frame #%u! (%s)", framenum, SDL_GetError());
|
||||
} else {
|
||||
char fname[64];
|
||||
SDL_snprintf(fname, sizeof (fname), "frame%05u.png", framenum);
|
||||
if (!SDL_SavePNG(surface, fname)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to save png for frame #%u! (%s)", framenum, SDL_GetError());
|
||||
}
|
||||
SDL_DestroySurface(surface);
|
||||
}
|
||||
|
||||
framenum++;
|
||||
|
||||
return SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
#define SDL_RenderPresent SAVERENDERING_SDL_RenderPresent
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>@project_name@ Examples: @category_description@</title>
|
||||
<link rel="icon" href="/@project_name@/thumbnail.png" type="image/png" />
|
||||
|
||||
@preload_images_html@
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="/@project_name@/examples.css"
|
||||
/>
|
||||
<style>
|
||||
main > h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="@project_name@ Examples: @category_description@">
|
||||
<meta property="og:description" content="@project_name@ Examples: @category_description@">
|
||||
<meta property="og:image" content="@preview_image@" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="/">@project_name@ Examples</a>
|
||||
</header>
|
||||
<main>
|
||||
<nav class="breadcrumb">
|
||||
<ul>
|
||||
<li><a href="/@project_name@/">@project_name@</a></li>
|
||||
<li><a href="/@project_name@/@category_name@/">@category_name@</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h1>@project_name@ examples: @category_description@</h1>
|
||||
<div class="list">@examples_list_html@</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>@project_name@ Examples</title>
|
||||
<link rel="icon" href="/@project_name@/thumbnail.png" type="image/png" />
|
||||
|
||||
@preload_images_html@
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="/@project_name@/examples.css"
|
||||
/>
|
||||
<style>
|
||||
main > h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="@project_name@ Examples">
|
||||
<meta property="og:description" content="@project_name@ Examples">
|
||||
<meta property="og:image" content="@preview_image@" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="/">SDL Examples</a>
|
||||
</header>
|
||||
<main>
|
||||
<nav class="breadcrumb">
|
||||
<ul>
|
||||
<li><a href="/@project_name@/">@project_name@</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h1>@project_name@ examples</h1>
|
||||
|
||||
@homepage_list_html@
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This example code $WHAT_IT_DOES.
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
/* We will use this renderer to draw into this window every frame. */
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
|
||||
|
||||
/* This function runs once at startup. */
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
SDL_SetAppMetadata("Example HUMAN READABLE NAME", "1.0", "com.example.CATEGORY-NAME");
|
||||
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!SDL_CreateWindowAndRenderer("examples/CATEGORY/NAME", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
SDL_SetRenderLogicalPresentation(renderer, 640, 480, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
||||
}
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once per frame, and is the heart of the program. */
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
return SDL_APP_CONTINUE; /* carry on with the program! */
|
||||
}
|
||||
|
||||
/* This function runs once at shutdown. */
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
/* SDL will clean up the window/renderer for us. */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/** from ghwikipp.css */
|
||||
:root {
|
||||
color-scheme: dark light; /* both supported */
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
padding: 2vw;
|
||||
color: #333;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0969da;
|
||||
/* text-decoration: none; */
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #064998;
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-bottom: 2px solid #efefef;
|
||||
}
|
||||
|
||||
h2 {
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 85ch;
|
||||
}
|
||||
|
||||
li {
|
||||
max-width: 85ch;
|
||||
}
|
||||
|
||||
div.sourceCode {
|
||||
background-color: #f6f8fa;
|
||||
max-width: 100%;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f6f8fa;
|
||||
padding: 0px;
|
||||
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
|
||||
"Liberation Mono", monospace;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #808080;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #808080;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
|
||||
.wikitopbanner {
|
||||
background-color: #efefef;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.wikibottombanner {
|
||||
background-color: #efefef;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.alertBox {
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
max-width: 60%;
|
||||
padding: 10;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.anchorImage {
|
||||
visibility: hidden;
|
||||
padding-left: 0.2em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.anchorText:hover .anchorImage {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #efefef;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Text and background color for dark mode */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
color: #e6edf3;
|
||||
background-color: #0d1117;
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-color: rgba(48, 54, 61, 0.7);
|
||||
}
|
||||
|
||||
h2 {
|
||||
border-color: rgba(48, 54, 61, 0.7);
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: rgba(48, 54, 61, 0.7);
|
||||
}
|
||||
|
||||
div.sourceCode {
|
||||
background-color: #161b22;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #161b22;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4493f8;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #2f66ad;
|
||||
}
|
||||
|
||||
table {
|
||||
border-color: rgba(48, 54, 61, 0.7);
|
||||
}
|
||||
|
||||
td {
|
||||
border-color: rgba(48, 54, 61, 0.7);
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #161b22;
|
||||
}
|
||||
|
||||
.wikitopbanner {
|
||||
background-color: #263040;
|
||||
}
|
||||
|
||||
.wikibottombanner {
|
||||
background-color: #263040;
|
||||
}
|
||||
|
||||
.anchorText:hover .anchorImage {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #0969da;
|
||||
}
|
||||
|
||||
.wikitopbanner,
|
||||
.anchorText,
|
||||
.wikibottombanner {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/** additional (& overrides) for examples */
|
||||
header {
|
||||
background-color: #efefef;
|
||||
padding: 10px;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
header > a,
|
||||
header > a:hover,
|
||||
header > a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
padding: 0.75rem 0.75rem;
|
||||
}
|
||||
|
||||
.breadcrumb ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb li:not(:last-child)::after {
|
||||
display: inline-block;
|
||||
margin: 0 0.25rem;
|
||||
content: "»";
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.list > a > div {
|
||||
width: 200px;
|
||||
border: 5px solid #efefef;
|
||||
border-radius: 5px;
|
||||
background: #efefef;
|
||||
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
||||
transition: border 0.25s;
|
||||
}
|
||||
|
||||
.list > a > div:hover {
|
||||
border-color: #064998;
|
||||
}
|
||||
|
||||
.list > a > div > img {
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.list > a > div > div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.list > a,
|
||||
.list > a:visited {
|
||||
display: block;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.list > a:hover {
|
||||
color: #0969da;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
header {
|
||||
background-color: #263040;
|
||||
}
|
||||
|
||||
.breadcrumb li:not(:last-child)::after {
|
||||
color: #efefef;
|
||||
}
|
||||
|
||||
.list > a > div {
|
||||
border-color: #333;
|
||||
background: #333;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 992px) {
|
||||
.list > a > div {
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>@project_name@ Example: @category_name@/@example_name@</title>
|
||||
<link rel="icon" href="/@project_name@/thumbnail.png" type="image/png" />
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="@project_name@ Example: @category_name@/@example_name@">
|
||||
<meta property="og:description" content="@short_description@">
|
||||
<meta property="og:image" content="@preview_image@" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/@project_name@/examples.css" />
|
||||
<style>
|
||||
main {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
main > #sidebar {
|
||||
flex: 0 1 25%;
|
||||
border-left: 2px solid #efefef;
|
||||
padding: 1rem 1rem;
|
||||
}
|
||||
|
||||
main > #content {
|
||||
flex: 1 1 auto;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
main > #content > h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
main > #sidebar ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
main > #sidebar li {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
#example-description {
|
||||
max-width: 85ch;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
max-width: 100%;
|
||||
box-shadow: 0 0 0.5rem #7787;
|
||||
}
|
||||
|
||||
#output-container {
|
||||
position: fixed;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
background-color: black;
|
||||
border: none;
|
||||
border-top: 1px solid #778;
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
|
||||
transition: top 0.25s;
|
||||
}
|
||||
|
||||
#output-container::before {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
right: 1rem;
|
||||
|
||||
content: 'Console';
|
||||
font-size: 1.5rem;
|
||||
color: white;
|
||||
background: black;
|
||||
border: 1px solid #778;
|
||||
border-bottom: none;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
}
|
||||
|
||||
#output-container:hover,
|
||||
#output-container:focus-within {
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
#output-container:focus-within {
|
||||
border-top: 2px solid orange;
|
||||
}
|
||||
|
||||
#output-container:focus-within::before {
|
||||
border: 2px solid orange;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#output {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
border: none;
|
||||
background: black;
|
||||
color: white;
|
||||
outline: none;
|
||||
resize: none;
|
||||
|
||||
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
|
||||
"Liberation Mono", monospace;
|
||||
}
|
||||
|
||||
#source-code {
|
||||
position: fixed;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
background: #e0eaee;
|
||||
padding: 1rem;
|
||||
|
||||
transition: top 0.25s;
|
||||
}
|
||||
|
||||
#source-code::before {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 1rem;
|
||||
|
||||
content: 'Source code';
|
||||
font-size: 1.5rem;
|
||||
background: linear-gradient(to bottom, #789, #e0eaee);
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
|
||||
/* Used for a hack to avoid tab labels showing on top of tabs; see
|
||||
comment below for details. */
|
||||
transition: bottom 0.25s;
|
||||
}
|
||||
|
||||
#source-code:hover,
|
||||
#source-code:focus-within {
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
#source-code:focus-within {
|
||||
border-top: 2px solid orange;
|
||||
}
|
||||
|
||||
#source-code:focus-within::before {
|
||||
border: 2px solid orange;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#source-code-contents {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
/* Hack: Sinze z-index only goes one way, and both tab labels should be
|
||||
behind each other's tab, put the former on top (higher z-index) and
|
||||
make the latter one disappear when the former is hovered. */
|
||||
#output-container:hover ~ #source-code::before,
|
||||
#output-container:focus-within ~ #source-code::before {
|
||||
bottom: -100%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
main > #sidebar {
|
||||
border-color: rgba(48, 54, 61, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 992px) {
|
||||
main {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main > #sidebar {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="highlight.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="/">SDL_mixer Examples</a>
|
||||
</header>
|
||||
<main>
|
||||
<div id="content">
|
||||
<nav class="breadcrumb">
|
||||
<ul>
|
||||
<li><a href="/@project_name@/">@project_name@</a></li>
|
||||
<li><a href="/@project_name@/@category_name@/">@category_name@</a></li>
|
||||
<li><a href="/@project_name@/@category_name@/@example_name@/">@example_name@</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<hr/>
|
||||
<div id="example-description">@description@</div>
|
||||
<div class="canvas-container">
|
||||
<canvas
|
||||
id="canvas"
|
||||
oncontextmenu="event.preventDefault()"
|
||||
tabindex="-1"
|
||||
></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sidebar">
|
||||
<h3>Other examples:</h3>
|
||||
@other_examples_html@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div id="output-container">
|
||||
<textarea id="output" rows="8" spellcheck="false" readonly></textarea>
|
||||
</div>
|
||||
|
||||
<div id="source-code" tabindex="1">
|
||||
<div id="source-code-contents">@htmlified_source_code@</div>
|
||||
</div>
|
||||
|
||||
<script type='text/javascript'>
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
print: (function() {
|
||||
var element = document.getElementById('output');
|
||||
if (element) element.value = ''; // clear browser cache
|
||||
return function(text) {
|
||||
var elem = document.getElementById('output-container');
|
||||
if (elem.style['top'] == '') {
|
||||
elem.style['top'] = '20%';
|
||||
setTimeout(function() { elem.style['top'] = ''; }, 3000);
|
||||
}
|
||||
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
// These replacements are necessary if you render to raw HTML
|
||||
//text = text.replace(/&/g, "&");
|
||||
//text = text.replace(/</g, "<");
|
||||
//text = text.replace(/>/g, ">");
|
||||
//text = text.replace('\n', '<br>', 'g');
|
||||
console.log(text);
|
||||
if (element) {
|
||||
element.value += text + "\n";
|
||||
element.scrollTop = element.scrollHeight; // focus on bottom
|
||||
}
|
||||
};
|
||||
})(),
|
||||
printErr: function(text) { Module.print(text) },
|
||||
canvas: (() => {
|
||||
var canvas = document.getElementById('canvas');
|
||||
|
||||
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
||||
// application robust, you may want to override this behavior before shipping!
|
||||
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
||||
canvas.addEventListener("webglcontextlost", (e) => { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
|
||||
|
||||
return canvas;
|
||||
})(),
|
||||
setStatus: (text) => {},
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: (left) => {
|
||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
|
||||
}
|
||||
};
|
||||
Module.setStatus('Downloading...');
|
||||
window.onerror = (event) => {
|
||||
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
|
||||
Module.setStatus('Exception thrown, see JavaScript console');
|
||||
Module.setStatus = (text) => {
|
||||
if (text) console.error('[post-exception status] ' + text);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
<script async type="text/javascript" src="@javascript_file@"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||