@goldenratio/wolf 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -0
- package/README.md +33 -0
- package/package.json +44 -0
- package/target/types/howl.d.ts +132 -0
- package/target/types/howler.d.ts +42 -0
- package/target/types/main.d.ts +3 -0
- package/target/types/sound.d.ts +32 -0
- package/target/types/types.d.ts +52 -0
- package/target/types/utils.d.ts +8 -0
- package/target/wolf.js +1606 -0
- package/target/wolf.js.map +7 -0
- package/target/wolf.min.js +2 -0
- package/target/wolf.min.js.map +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
zlib License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Karthik Jayakumar (@goldenratio)
|
|
4
|
+
|
|
5
|
+
This software is provided "as-is", without any express or implied warranty. In no event
|
|
6
|
+
will the authors be held liable for any damages arising from the use of this software.
|
|
7
|
+
|
|
8
|
+
Permission is granted to anyone to use this software for any purpose, including commercial
|
|
9
|
+
applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
|
10
|
+
|
|
11
|
+
1. The origin of this software must not be misrepresented; you must not claim that you
|
|
12
|
+
wrote the original software. If you use this software in a product, an acknowledgment
|
|
13
|
+
in the product documentation would be appreciated but is not required.
|
|
14
|
+
|
|
15
|
+
2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
|
16
|
+
as being the original software.
|
|
17
|
+
|
|
18
|
+
3. This notice may not be removed or altered from any source distribution.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# wolf
|
|
2
|
+
> Javascript audio library for the modern web. Port of howler.js in TypeScript (ESM)
|
|
3
|
+
|
|
4
|
+
### What is different from original [Howler.js](https://github.com/goldfire/howler.js)
|
|
5
|
+
|
|
6
|
+
- Written in TypeScript (better type safety)
|
|
7
|
+
- Compatible with [Google Closure Compiler](https://github.com/google/closure-compiler)
|
|
8
|
+
- ESM only
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
### NPM
|
|
13
|
+
|
|
14
|
+
```console
|
|
15
|
+
npm install --save @goldenratio/wolf
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
https://www.npmjs.com/package/@goldenratio/wolf
|
|
19
|
+
|
|
20
|
+
## Release
|
|
21
|
+
|
|
22
|
+
### NPM
|
|
23
|
+
```console
|
|
24
|
+
npm version {major | minor | patch}
|
|
25
|
+
npm publish
|
|
26
|
+
|
|
27
|
+
# If you have ignore-scripts enabled
|
|
28
|
+
npm version {major | minor | patch}
|
|
29
|
+
npm run version
|
|
30
|
+
npm run postversion
|
|
31
|
+
npm publish
|
|
32
|
+
|
|
33
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@goldenratio/wolf",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Port of howler.js in TypeScript (ESM)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "./target/wolf.js",
|
|
7
|
+
"types": "./target/types/main.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./target/types/main.d.ts",
|
|
11
|
+
"import": "./target/wolf.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"clean": "rm -rf target js",
|
|
16
|
+
"build": "npm run clean && tsc && node ./build.ts",
|
|
17
|
+
"test": "node --import tsx --test ./tests/*.test.ts",
|
|
18
|
+
"generate-docs": "rm -rf ./docs && typedoc --theme default --excludePrivate --excludeProtected",
|
|
19
|
+
"version": "npm run build",
|
|
20
|
+
"postversion": "git push && git push --tags"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://codeberg.org/goldenratio/wolf.git"
|
|
25
|
+
},
|
|
26
|
+
"author": "Karthik Jayakumar",
|
|
27
|
+
"license": "Zlib",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://codeberg.org/goldenratio/wolf"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"target/",
|
|
33
|
+
"package.json",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"homepage": "https://codeberg.org/goldenratio/wolf",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "25.0.10",
|
|
40
|
+
"esbuild": "0.27.2",
|
|
41
|
+
"typedoc": "0.28.16",
|
|
42
|
+
"typescript": "5.9.3"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { HowlEventHandler, HowlEventName, HowlListener, HowlOptions, HowlState, HowlXHR, HowlSpriteMap, WebAudioNodeWithSource } from "./types.js";
|
|
2
|
+
import { Sound } from "./sound.js";
|
|
3
|
+
export declare class Howl {
|
|
4
|
+
private readonly howler;
|
|
5
|
+
_autoplay: boolean;
|
|
6
|
+
_format: readonly string[] | undefined;
|
|
7
|
+
_html5: boolean;
|
|
8
|
+
_muted: boolean;
|
|
9
|
+
_loop: boolean;
|
|
10
|
+
_pool: number;
|
|
11
|
+
_preload: boolean | "metadata" | "none";
|
|
12
|
+
_rate: number;
|
|
13
|
+
_sprite: HowlSpriteMap;
|
|
14
|
+
_src: readonly string[];
|
|
15
|
+
_volume: number;
|
|
16
|
+
_xhr: HowlXHR;
|
|
17
|
+
_duration: number;
|
|
18
|
+
_state: HowlState;
|
|
19
|
+
_sounds: Sound[];
|
|
20
|
+
_endTimers: Record<number, ReturnType<typeof setTimeout> | (() => void)>;
|
|
21
|
+
_queue: Array<{
|
|
22
|
+
event: string;
|
|
23
|
+
action: () => void;
|
|
24
|
+
}>;
|
|
25
|
+
_playLock: boolean;
|
|
26
|
+
_webAudio: boolean;
|
|
27
|
+
_onend: HowlListener[];
|
|
28
|
+
_onfade: HowlListener[];
|
|
29
|
+
_onload: HowlListener[];
|
|
30
|
+
_onloaderror: HowlListener[];
|
|
31
|
+
_onplayerror: HowlListener[];
|
|
32
|
+
_onpause: HowlListener[];
|
|
33
|
+
_onplay: HowlListener[];
|
|
34
|
+
_onstop: HowlListener[];
|
|
35
|
+
_onmute: HowlListener[];
|
|
36
|
+
_onvolume: HowlListener[];
|
|
37
|
+
_onrate: HowlListener[];
|
|
38
|
+
_onseek: HowlListener[];
|
|
39
|
+
_onunlock: HowlListener[];
|
|
40
|
+
_onresume: HowlListener[];
|
|
41
|
+
constructor(options: HowlOptions);
|
|
42
|
+
load(): void;
|
|
43
|
+
play(spriteOrId?: string | number, internal?: boolean): number | undefined;
|
|
44
|
+
state(): HowlState;
|
|
45
|
+
/**
|
|
46
|
+
* Check if a sound (or any sound) is playing.
|
|
47
|
+
*/
|
|
48
|
+
playing(id?: number): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Duration of group, or sprite duration if sound id passed.
|
|
51
|
+
*/
|
|
52
|
+
duration(id?: number): number;
|
|
53
|
+
/**
|
|
54
|
+
* Pause playback and save current position.
|
|
55
|
+
*/
|
|
56
|
+
pause(id?: number, internal?: boolean): this;
|
|
57
|
+
/**
|
|
58
|
+
* Get/set playback rate.
|
|
59
|
+
* rate() -> first sound rate (or group rate fallback)
|
|
60
|
+
* rate(id) -> sound rate
|
|
61
|
+
* rate(rate) -> set group rate
|
|
62
|
+
* rate(rate, id) -> set sound rate
|
|
63
|
+
*/
|
|
64
|
+
rate(): number;
|
|
65
|
+
rate(id: number): number;
|
|
66
|
+
rate(rate: number): this;
|
|
67
|
+
rate(rate: number, id: number): this;
|
|
68
|
+
/**
|
|
69
|
+
* Get/set seek position.
|
|
70
|
+
* seek() -> first sound seek
|
|
71
|
+
* seek(id) -> sound seek
|
|
72
|
+
* seek(seek) -> set first sound seek
|
|
73
|
+
* seek(seek, id) -> set sound seek
|
|
74
|
+
*/
|
|
75
|
+
seek(): number;
|
|
76
|
+
seek(id: number): number;
|
|
77
|
+
seek(seek: number): this;
|
|
78
|
+
seek(seek: number, id: number): this;
|
|
79
|
+
stop(id?: number, internal?: boolean): this;
|
|
80
|
+
/**
|
|
81
|
+
* Mute/unmute a single sound or all sounds in this Howl group.
|
|
82
|
+
* @param muted Set to true to mute and false to unmute.
|
|
83
|
+
* @param id The sound ID to update (omit to mute/unmute all).
|
|
84
|
+
*/
|
|
85
|
+
mute(muted?: boolean, id?: number): this | boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Get/set the volume of this sound or of the Howl group.
|
|
88
|
+
* volume() -> group volume
|
|
89
|
+
* volume(id) -> sound volume
|
|
90
|
+
* volume(vol) -> set group volume
|
|
91
|
+
* volume(vol, id) -> set sound volume
|
|
92
|
+
*/
|
|
93
|
+
volume(): number;
|
|
94
|
+
volume(id: number): number;
|
|
95
|
+
volume(vol: number): this;
|
|
96
|
+
volume(vol: number, id: number): this;
|
|
97
|
+
volume(vol: number, id: number, internal?: boolean): this;
|
|
98
|
+
/**
|
|
99
|
+
* Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).
|
|
100
|
+
*/
|
|
101
|
+
fade(from: number, to: number, len: number, id?: number): this;
|
|
102
|
+
/**
|
|
103
|
+
* loop() from your snippet.
|
|
104
|
+
*/
|
|
105
|
+
loop(): boolean;
|
|
106
|
+
loop(id: number): boolean;
|
|
107
|
+
loop(loop: boolean): this;
|
|
108
|
+
loop(loop: boolean, id: number): this;
|
|
109
|
+
unload(): void;
|
|
110
|
+
on(event: HowlEventName, fn: HowlEventHandler, id?: number, once?: boolean): this;
|
|
111
|
+
off(event?: HowlEventName, fn?: HowlEventHandler | number, id?: number): this;
|
|
112
|
+
once(event: HowlEventName, fn: HowlEventHandler, id?: number): this;
|
|
113
|
+
/**
|
|
114
|
+
* Starts the internal interval to fade a sound.
|
|
115
|
+
*/
|
|
116
|
+
private _startFadeInterval;
|
|
117
|
+
/**
|
|
118
|
+
* Stop an active fade.
|
|
119
|
+
*/
|
|
120
|
+
private _stopFade;
|
|
121
|
+
_emit(event: HowlEventName, id?: number, errorMsg?: string): this;
|
|
122
|
+
_loadQueue(event?: string): this;
|
|
123
|
+
_ended(sound: Sound): this;
|
|
124
|
+
_clearTimer(id: number): this;
|
|
125
|
+
_soundById(id: number): Sound | undefined;
|
|
126
|
+
_inactiveSound(): Sound;
|
|
127
|
+
_drain(): void;
|
|
128
|
+
_getSoundIds(id?: number): number[];
|
|
129
|
+
_refreshBuffer(sound: Sound): void;
|
|
130
|
+
_cleanBuffer(node: WebAudioNodeWithSource): void;
|
|
131
|
+
_clearSound(node: HTMLAudioElement): void;
|
|
132
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Howl } from "./howl.js";
|
|
2
|
+
import type { HowlerState, Html5AudioUnlocked } from "./types.js";
|
|
3
|
+
declare class HowlerGlobal {
|
|
4
|
+
_counter: number;
|
|
5
|
+
_html5AudioPool: Html5AudioUnlocked[];
|
|
6
|
+
html5PoolSize: number;
|
|
7
|
+
_codecs: Record<string, boolean>;
|
|
8
|
+
_howls: Howl[];
|
|
9
|
+
_muted: boolean;
|
|
10
|
+
_volume: number;
|
|
11
|
+
_canPlayEvent: "canplaythrough" | "canplay";
|
|
12
|
+
readonly _navigator?: Navigator;
|
|
13
|
+
_audioUnlocked?: boolean;
|
|
14
|
+
_mobileUnloaded?: boolean;
|
|
15
|
+
_scratchBuffer?: AudioBuffer;
|
|
16
|
+
_suspendTimer?: ReturnType<typeof setTimeout>;
|
|
17
|
+
_resumeAfterSuspend?: boolean;
|
|
18
|
+
cache: Record<string, AudioBuffer>;
|
|
19
|
+
masterGain?: GainNode;
|
|
20
|
+
noAudio: boolean;
|
|
21
|
+
usingWebAudio: boolean;
|
|
22
|
+
autoSuspend: boolean;
|
|
23
|
+
ctx?: AudioContext;
|
|
24
|
+
autoUnlock: boolean;
|
|
25
|
+
state: HowlerState;
|
|
26
|
+
constructor();
|
|
27
|
+
volume(): number;
|
|
28
|
+
volume(volume: number): this;
|
|
29
|
+
mute(muted: boolean): this;
|
|
30
|
+
stop(): this;
|
|
31
|
+
unload(): this;
|
|
32
|
+
codecs(ext: string): boolean;
|
|
33
|
+
_setup(): void;
|
|
34
|
+
_setupCodecs(): void;
|
|
35
|
+
_unlockAudio(): void;
|
|
36
|
+
_obtainHtml5Audio(): Html5AudioUnlocked;
|
|
37
|
+
_releaseHtml5Audio(audio: Html5AudioUnlocked): this;
|
|
38
|
+
_autoSuspend(): void;
|
|
39
|
+
_autoResume(): void;
|
|
40
|
+
}
|
|
41
|
+
export declare const Howler: HowlerGlobal;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Howl } from "./howl.js";
|
|
2
|
+
import type { SoundNode } from "./types.js";
|
|
3
|
+
import type { Howler } from "./howler.js";
|
|
4
|
+
export declare class Sound {
|
|
5
|
+
private readonly howler;
|
|
6
|
+
private readonly parent;
|
|
7
|
+
_muted: boolean;
|
|
8
|
+
_loop: boolean;
|
|
9
|
+
_volume: number;
|
|
10
|
+
_rate: number;
|
|
11
|
+
_seek: number;
|
|
12
|
+
_rateSeek: number;
|
|
13
|
+
_paused: boolean;
|
|
14
|
+
_ended: boolean;
|
|
15
|
+
_sprite: string;
|
|
16
|
+
_id: number;
|
|
17
|
+
_node?: SoundNode;
|
|
18
|
+
_panner?: AudioNode;
|
|
19
|
+
_start: number;
|
|
20
|
+
_stop: number;
|
|
21
|
+
_playStart: number;
|
|
22
|
+
_interval?: ReturnType<typeof setTimeout>;
|
|
23
|
+
_fadeTo?: number;
|
|
24
|
+
_errorFn?: (ev: Event) => void;
|
|
25
|
+
_loadFn?: (ev: Event) => void;
|
|
26
|
+
_endFn?: (ev: Event) => void;
|
|
27
|
+
constructor(parent: Howl, howler: typeof Howler);
|
|
28
|
+
reset(): this;
|
|
29
|
+
private errorListener;
|
|
30
|
+
private loadListener;
|
|
31
|
+
private endListener;
|
|
32
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type HowlState = "unloaded" | "loading" | "loaded";
|
|
2
|
+
export type HowlerState = "suspended" | "suspending" | "running";
|
|
3
|
+
export type HowlEventName = "end" | "fade" | "load" | "loaderror" | "playerror" | "pause" | "play" | "stop" | "mute" | "volume" | "rate" | "seek" | "unlock" | "resume";
|
|
4
|
+
export type HowlEventHandler = (soundId?: number, errorMsg?: string) => void;
|
|
5
|
+
export interface HowlListener {
|
|
6
|
+
readonly id?: number;
|
|
7
|
+
readonly fn: HowlEventHandler;
|
|
8
|
+
readonly once?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface HowlXHR {
|
|
11
|
+
readonly method: string;
|
|
12
|
+
readonly withCredentials: boolean;
|
|
13
|
+
readonly headers?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export type HowlSpriteDef = [startMs: number, durationMs: number, loop?: boolean];
|
|
16
|
+
export type HowlSpriteMap = Record<string, HowlSpriteDef>;
|
|
17
|
+
export interface HowlOptions {
|
|
18
|
+
readonly src: string | readonly string[];
|
|
19
|
+
readonly autoplay?: boolean;
|
|
20
|
+
readonly format?: string | readonly string[];
|
|
21
|
+
readonly html5?: boolean;
|
|
22
|
+
readonly mute?: boolean;
|
|
23
|
+
readonly loop?: boolean;
|
|
24
|
+
readonly pool?: number;
|
|
25
|
+
readonly preload?: boolean | "metadata" | "none";
|
|
26
|
+
readonly rate?: number;
|
|
27
|
+
readonly sprite?: HowlSpriteMap;
|
|
28
|
+
readonly volume?: number;
|
|
29
|
+
readonly xhr?: Partial<HowlXHR>;
|
|
30
|
+
readonly onend?: HowlEventHandler;
|
|
31
|
+
readonly onfade?: HowlEventHandler;
|
|
32
|
+
readonly onload?: HowlEventHandler;
|
|
33
|
+
readonly onloaderror?: HowlEventHandler;
|
|
34
|
+
readonly onplayerror?: HowlEventHandler;
|
|
35
|
+
readonly onpause?: HowlEventHandler;
|
|
36
|
+
readonly onplay?: HowlEventHandler;
|
|
37
|
+
readonly onstop?: HowlEventHandler;
|
|
38
|
+
readonly onmute?: HowlEventHandler;
|
|
39
|
+
readonly onvolume?: HowlEventHandler;
|
|
40
|
+
readonly onrate?: HowlEventHandler;
|
|
41
|
+
readonly onseek?: HowlEventHandler;
|
|
42
|
+
readonly onunlock?: HowlEventHandler;
|
|
43
|
+
readonly onresume?: HowlEventHandler;
|
|
44
|
+
}
|
|
45
|
+
export interface WebAudioNodeWithSource extends GainNode {
|
|
46
|
+
bufferSource?: AudioBufferSourceNode;
|
|
47
|
+
paused?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface Html5AudioUnlocked extends HTMLAudioElement {
|
|
50
|
+
_unlocked?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export type SoundNode = WebAudioNodeWithSource | Html5AudioUnlocked;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Howl } from "./howl.js";
|
|
2
|
+
import type { Html5AudioUnlocked, SoundNode } from "./types.js";
|
|
3
|
+
import type { Howler } from "./howler.js";
|
|
4
|
+
export declare function isHtml5Audio(node: SoundNode): node is Html5AudioUnlocked;
|
|
5
|
+
export declare function loadBuffer(howl: Howl, howler: typeof Howler): void;
|
|
6
|
+
export declare function safeXhrSend(xhr: XMLHttpRequest): void;
|
|
7
|
+
export declare function loadSound(self: Howl, buffer?: AudioBuffer): void;
|
|
8
|
+
export declare function setupAudioContext(howler: typeof Howler): void;
|