Skip to content

Commit

Permalink
Basic audio support and play-wav example (#28)
Browse files Browse the repository at this point in the history
* First version of play-wav examples.

* Move RWMode to rw.ts and remove types.ts

* Throw an error in denoFromPlatformCallback.

* Mark SDL_AudioSpec.callback as defective and allow SDL_AudioSpec to be constructed wihtout any parameters.
  • Loading branch information
smack0007 authored Jul 25, 2024
1 parent 5ca6567 commit ed5f25a
Show file tree
Hide file tree
Showing 29 changed files with 1,440 additions and 298 deletions.
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@
"runtimeArgs": ["task", "run:hello-world-async"],
"attachSimplePort": 9229
},
{
"name": "Play Wav",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"env": { "DENO_FLAGS": "--inspect-brk" },
"runtimeExecutable": "deno",
"runtimeArgs": ["task", "run:play-wav"],
"attachSimplePort": 9229
},
{
"name": "Renderer",
"type": "node",
Expand Down
6 changes: 5 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@

"editor.defaultFormatter": "denoland.vscode-deno",

"editor.tabSize": 2
"editor.tabSize": 2,

"[josn,ts]": {
"editor.defaultFormatter": "denoland.vscode-deno"
}
}
17 changes: 17 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,23 @@
},
"problemMatcher": ["$deno"]
},
{
"label": "Run Play Wav",
"group": {
"kind": "none",
"isDefault": true
},
"type": "deno",
"command": "task",
"args": ["run:play-wav"],
"options": {
"env": {
"GDK_BACKEND": "wayland"
},
"cwd": "${workspaceFolder}"
},
"problemMatcher": ["$deno"]
},
{
"label": "Run Renderer",
"group": {
Expand Down
Binary file added assets/powerup.wav
Binary file not shown.
1 change: 1 addition & 0 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"run:doom-fire": "cd ./examples/doom-fire && SDL_TS_ENV_DIR=$INIT_CWD deno run --unstable-ffi --allow-env --allow-ffi --allow-read=../.. $DENO_FLAGS ./main.ts",
"run:hello-world": "cd ./examples/hello-world && SDL_TS_ENV_DIR=$INIT_CWD deno run --unstable-ffi --allow-env --allow-ffi --allow-read=../.. $DENO_FLAGS ./main.ts",
"run:hello-world-async": "cd ./examples/hello-world-async && SDL_TS_ENV_DIR=$INIT_CWD deno run --unstable-ffi --allow-env --allow-ffi --allow-read=../.. $DENO_FLAGS ./main.ts",
"run:play-wav": "cd ./examples/play-wav && SDL_TS_ENV_DIR=$INIT_CWD deno run --unstable-ffi --allow-env --allow-ffi --allow-read=../.. $DENO_FLAGS ./main.ts",
"run:renderer": "cd ./examples/renderer && SDL_TS_ENV_DIR=$INIT_CWD deno run --unstable-ffi --allow-env --allow-ffi --allow-read=../.. $DENO_FLAGS ./main.ts",
"run:same-game": "cd ./examples/same-game && SDL_TS_ENV_DIR=$INIT_CWD deno run --unstable-ffi --allow-env --allow-ffi --allow-read=../.. $DENO_FLAGS ./main.ts",
"test": "deno test --unstable-ffi --allow-ffi"
Expand Down
61 changes: 61 additions & 0 deletions examples/play-wav/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Adapted from https://gigi.nullneuron.net/gigilabs/playing-a-wav-file-using-sdl2/

import { Box, Pointer, SDL, U32, U8, u32, u8 } from "SDL_ts";
import { SDL_FUNCTIONS } from "./sdlConfig.ts";
import { ASSETS_PATH } from "../../shared/constants.ts";
import { path } from "../../deps.ts";

const main = (): number => {
if (SDL.Init(SDL.InitFlags.AUDIO, { functions: SDL_FUNCTIONS }) < 0) {
return 1;
}

console.info("SDL Initialized.");

const wavSpec = new SDL.AudioSpec();
const wavBufferBox = new Box<Pointer<u8>>(Pointer);
const wavLengthBox = new Box<u32>(U32);

if (
SDL.LoadWav(
path.join(ASSETS_PATH, "powerup.wav"),
wavSpec,
wavBufferBox,
wavLengthBox
) == null
) {
console.error("ERROR: Failed to load wav file.");
return 1;
}

const audioDeviceID = SDL.OpenAudioDevice(null, 0, wavSpec, null, 0);
if (audioDeviceID <= 0) {
console.error("ERROR: Faield to open an audio device.");
return 1;
}

if (
SDL.QueueAudio(audioDeviceID, wavBufferBox.value, wavLengthBox.value) != 0
) {
console.error(`ERROR: Faield to queue audio: ${SDL.GetError()}`);
return 1;
}

SDL.PauseAudioDevice(audioDeviceID, 0);

SDL.Delay(1000);

SDL.CloseAudioDevice(audioDeviceID);
SDL.FreeWAV(wavBufferBox.value);
SDL.Quit();
console.info("SDL Shutdown.");

return 0;
};

try {
Deno.exit(main());
} catch (error) {
console.error(error);
Deno.exit(1);
}
17 changes: 17 additions & 0 deletions examples/play-wav/sdlConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { SDL } from "SDL_ts";

// This file contains the list of functions that are used in the project.

export const SDL_FUNCTIONS = [
SDL.CloseAudioDevice,
SDL.Delay,
SDL.FreeWAV,
SDL.GetError,
SDL.Init,
SDL.LoadWAV_RW,
SDL.OpenAudioDevice,
SDL.PauseAudioDevice,
SDL.QueueAudio,
SDL.Quit,
SDL.RWFromFile,
] as const;
2 changes: 2 additions & 0 deletions mod.SDL.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
export * from "./src/SDL/audio.ts";
export * from "./src/SDL/callbacks.ts";
export * from "./src/SDL/constants.ts";
export * from "./src/SDL/enums.ts";
export * from "./src/SDL/events.ts";
export * from "./src/SDL/functionMacros.ts";
export * from "./src/SDL/functions.ts";
export * from "./src/SDL/pixels.ts";
export * from "./src/SDL/rw.ts";
export * from "./src/SDL/structs.ts";
22 changes: 20 additions & 2 deletions src/SDL/_callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import Platform from "../_platform.ts";
import { PlatformPointer } from "../_types.ts";
import { Event } from "./events.ts";
import { i32, u32 } from "../types.ts";
import { i32, u32, u8 } from "../types.ts";

import { EventFilter } from "./callbacks.ts";
import { AudioCallback, EventFilter } from "./callbacks.ts";
import {
AudioSpec,
Color,
DisplayMode,
Keysym,
Expand All @@ -27,6 +28,23 @@ import {
} from "./structs.ts";

export const callbacks = {
SDL_AudioCallback: {
parameters: [
/* void* userdata */ "pointer",
/* Uint8* stream */ "pointer",
/* int len */ "i32",
],
result: /* void */ "void",
wrap: (callback: AudioCallback) => {
return (userdata: PlatformPointer<unknown>, stream: PlatformPointer<u8>, len: i32): void => {
return callback(
Platform.fromPlatformPointer(userdata)!,
Platform.fromPlatformPointer(stream)!,
len!,
);
};
},
},
SDL_EventFilter: {
parameters: [
/* void* userdata */ "pointer",
Expand Down
47 changes: 47 additions & 0 deletions src/SDL/_symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ export const symbols = {
],
result: /* int */ "i32",
},
SDL_CloseAudioDevice: {
parameters: [
/* SDL_AudioDeviceID dev */ "u32",
],
result: /* void */ "void",
},
SDL_ConvertSurface: {
parameters: [
/* SDL_Surface* src */ "pointer",
Expand Down Expand Up @@ -177,6 +183,12 @@ export const symbols = {
],
result: /* int */ "i32",
},
SDL_FreeWAV: {
parameters: [
/* Uint8* audio_buf */ "pointer",
],
result: /* void */ "void",
},
SDL_FreeSurface: {
parameters: [
/* SDL_Surface* surface */ "pointer",
Expand Down Expand Up @@ -488,6 +500,16 @@ export const symbols = {
],
result: /* SDL_Surface* */ "pointer",
},
SDL_LoadWAV_RW: {
parameters: [
/* SDL_RWops* src */ "pointer",
/* int freesrc */ "i32",
/* SDL_AudioSpec* spec */ "pointer",
/* Uint8** audio_buf */ "pointer",
/* Uint32* audio_len */ "pointer",
],
result: /* SDL_AudioSpec* */ "pointer",
},
SDL_LockSurface: {
parameters: [
/* SDL_Surface* surface */ "pointer",
Expand Down Expand Up @@ -525,6 +547,23 @@ export const symbols = {
],
result: /* void */ "void",
},
SDL_OpenAudioDevice: {
parameters: [
/* char* device */ "pointer",
/* int iscapture */ "i32",
/* SDL_AudioSpec* desired */ "pointer",
/* SDL_AudioSpec* obtained */ "pointer",
/* int allowed_changes */ "i32",
],
result: /* SDL_AudioDeviceID */ "u32",
},
SDL_PauseAudioDevice: {
parameters: [
/* SDL_AudioDeviceID dev */ "u32",
/* int pause_on */ "i32",
],
result: /* void */ "void",
},
SDL_PollEvent: {
parameters: [
/* SDL_Event* event */ "pointer",
Expand All @@ -545,6 +584,14 @@ export const symbols = {
parameters: [],
result: /* void */ "void",
},
SDL_QueueAudio: {
parameters: [
/* SDL_AudioDeviceID dev */ "u32",
/* void* data */ "pointer",
/* Uint32 len */ "u32",
],
result: /* int */ "i32",
},
SDL_RWFromFile: {
parameters: [
/* char* file */ "pointer",
Expand Down
4 changes: 4 additions & 0 deletions src/SDL/audio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { u16, u32 } from "../types.ts";

export type AudioFormat = u16;
export type AudioDeviceID = u32;
12 changes: 11 additions & 1 deletion src/SDL/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@
// deno-lint-ignore-file no-unused-vars

import { Pointer } from "../pointers.ts";
import { Callback, i32, u32 } from "../types.ts";
import { Callback, i32, u32, u8 } from "../types.ts";
import { Event } from "./events.ts";

export type AudioCallback =
& (
(
userdata: Pointer<unknown> | null,
stream: Pointer<u8>,
len: i32,
) => void
)
& Callback;

export type EventFilter =
& (
(
Expand Down
24 changes: 22 additions & 2 deletions src/SDL/functionMacros.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,34 @@
// 1 to 1 mapping.

import { LoadBMP_RW, RWFromFile } from "./functions.ts";
import { Surface } from "./structs.ts";
import { AudioSpec, Surface } from "./structs.ts";
import { Box } from "../boxes.ts";
import { SDLError } from "../error.ts";
import { Pointer, PointerLike } from "../pointers.ts";
import { LoadWAV_RW } from "../../mod.SDL.ts";
import { u32, u8 } from "../types.ts";

export function LoadBMP(file: string): Surface | null {
const rw = RWFromFile(file, "rb");

if (rw == null) {
throw new Error("RWFromFile failed.");
throw new SDLError("RWFromFile failed.");
}

return LoadBMP_RW(rw, 1);
}

export function LoadWav(
file: string,
spec: PointerLike<AudioSpec>,
audio_buf: Box<Pointer<u8>>,
audio_len: PointerLike<u32>
): AudioSpec | null {
const rw = RWFromFile(file, "rb");

if (rw == null) {
throw new SDLError("RWFromFile failed.");
}

return LoadWAV_RW(rw, 1, spec, audio_buf, audio_len);
}
Loading

0 comments on commit ed5f25a

Please sign in to comment.