react-native-audiosprites 0.4.0 → 0.5.0
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/README.md +432 -6
- package/lib/module/index.js +147 -10
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +48 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +8 -3
- package/src/index.tsx +180 -11
package/README.md
CHANGED
|
@@ -27,6 +27,20 @@ audiosprite --output src/__tests__/sounds/mygameaudio --format howler --loop "bg
|
|
|
27
27
|
|
|
28
28
|
This command will generate `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a`, and `mygameaudio.ac3` in the `src/__tests__/sounds/` directory.
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* ⚠️ ANDROID RESOURCE CONFLICT FIX ⚠️
|
|
32
|
+
* * Android's build system (Gradle) generates resource IDs based on filenames WITHOUT extensions.
|
|
33
|
+
* If we generate "game_go_v2.mp3" and "game_go_v2.json", Android sees them both
|
|
34
|
+
* as the resource ID `R.raw.game_go_v2`, causing a "Duplicate resources" build error.
|
|
35
|
+
* * To fix this, make a script to automatically rename the generated JSON file to:
|
|
36
|
+
* `${outputFileName}_data.json`
|
|
37
|
+
* * Result:
|
|
38
|
+
* - game_go_v2.mp3 -> R.raw.game_go_v2
|
|
39
|
+
* - game_go_v2_data.json -> R.raw.game_go_v2_data
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
30
44
|
### Looping Sounds
|
|
31
45
|
|
|
32
46
|
You can create looping sounds by using the `--loop` option with the `audiosprite` command. The value of the `--loop` option should be the name of the sound you want to loop.
|
|
@@ -41,6 +55,40 @@ When you play a looping sound, it will play continuously until you stop it using
|
|
|
41
55
|
|
|
42
56
|
Then, you can use the `AudioSpritePlayer` to play the sounds from the sprite.
|
|
43
57
|
|
|
58
|
+
### Type Safety for Native Audio Extensions
|
|
59
|
+
|
|
60
|
+
This library includes robust type definitions for `react-native-audio-api` extensions, such as `createBufferQueueSource`. These types are automatically generated and synchronized with the native audio library version `0.10.1`.
|
|
61
|
+
|
|
62
|
+
### Audio Routing and Volume Control (Mixer Graph)
|
|
63
|
+
|
|
64
|
+
The library features a mixer graph that allows you to control the volume of Sound Effects (SFX) and Music separately, as well as a global Master volume.
|
|
65
|
+
|
|
66
|
+
- `sfx`: Short sound effects (coins, jumps, UI). High priority.
|
|
67
|
+
- `music`: Background tracks. Lower priority.
|
|
68
|
+
|
|
69
|
+
You can specify the channel when playing a sound:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Play on 'sfx' channel (default)
|
|
73
|
+
player.play('coin_sound');
|
|
74
|
+
|
|
75
|
+
// Play on 'music' channel
|
|
76
|
+
player.play('bg_music', { channel: 'music' });
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
You can control the volume dynamically:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Set Music Volume (0.0 to 1.0)
|
|
83
|
+
player.setMusicVolume(0.5);
|
|
84
|
+
|
|
85
|
+
// Set SFX Volume (0.0 to 1.0)
|
|
86
|
+
player.setSFXVolume(0.8);
|
|
87
|
+
|
|
88
|
+
// Set Master Volume (affects both)
|
|
89
|
+
player.volume = 1.0;
|
|
90
|
+
```
|
|
91
|
+
|
|
44
92
|
### Browser Environment
|
|
45
93
|
|
|
46
94
|
```typescript
|
|
@@ -159,7 +207,12 @@ export default function App() {
|
|
|
159
207
|
const playSound = (soundName: string) => {
|
|
160
208
|
const player = playerRef.current;
|
|
161
209
|
if (player && isLoaded) {
|
|
162
|
-
|
|
210
|
+
// Play on music channel
|
|
211
|
+
if (soundName === 'bg_loop') {
|
|
212
|
+
player.play(soundName, { channel: 'music' });
|
|
213
|
+
} else {
|
|
214
|
+
player.play(soundName);
|
|
215
|
+
}
|
|
163
216
|
console.log(`Playing sound: ${soundName}`);
|
|
164
217
|
} else {
|
|
165
218
|
console.warn('Player not loaded yet.');
|
|
@@ -263,6 +316,315 @@ Made with [create-react-native-library](https://github.com/callstack/react-nativ
|
|
|
263
316
|
|
|
264
317
|
# Translations
|
|
265
318
|
|
|
319
|
+
## Telugu
|
|
320
|
+
|
|
321
|
+

|
|
322
|
+
|
|
323
|
+
# react-native-audiosprites
|
|
324
|
+
|
|
325
|
+
'audiosprite' టూల్ ద్వారా రూపొందించబడిన ఆడియో స్ప్రైట్ల కోసం ఒక యూనివర్సల్ ప్లేయర్.
|
|
326
|
+
ఒకే సమయంలో అనేక శబ్దాలను ప్లే చేయడానికి మద్దతు ఇస్తుంది!
|
|
327
|
+
|
|
328
|
+
## ఇన్స్టాలేషన్
|
|
329
|
+
|
|
330
|
+
```sh
|
|
331
|
+
npm install react-native-audiosprites
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
```sh
|
|
335
|
+
yarn add react-native-audiosprites
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## వినియోగం
|
|
339
|
+
|
|
340
|
+
ముందుగా, మీరు `audiosprite` టూల్ను ఉపయోగించి ఆడియో స్ప్రైట్ మరియు JSON మానిఫెస్ట్ ఫైల్ను రూపొందించాలి.
|
|
341
|
+
|
|
342
|
+
మీరు [`audiosprite`](https://www.npmjs.com/package/audiosprite)ని గ్లోబల్గా ఇన్స్టాల్ చేశారని అనుకుందాం:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
audiosprite --output src/__tests__/sounds/mygameaudio --format howler --loop "bg_loop" src/__tests__/sounds/bg_loop.wav src/__tests__/sounds/Sound_1.m4a src/__tests__/sounds/Sound_2.m4a src/__tests__/sounds/Sound_3.m4a src/__tests__/sounds/Sound_4.m4a
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
ఈ కమాండ్ `src/__tests__/sounds/` డైరెక్టరీలో `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a`, మరియు `mygameaudio.ac3` ఫైళ్లను సృష్టిస్తుంది.
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* ⚠️ ANDROID వనరుల సంఘర్షణ పరిష్కారం ⚠️
|
|
352
|
+
* * Android బిల్డ్ సిస్టమ్ (Gradle) ఎక్స్టెన్షన్లు లేకుండా ఫైల్నేమ్ల ఆధారంగా వనరుల IDలను సృష్టిస్తుంది.
|
|
353
|
+
* ఒకవేళ మనం "game_go_v2.mp3" మరియు "game_go_v2.json"ను రూపొందిస్తే, Android రెండింటినీ
|
|
354
|
+
* `R.raw.game_go_v2` అనే ఒకే వనరు IDగా చూస్తుంది, దీనివల్ల "డూప్లికేట్ వనరులు" బిల్డ్ ఎర్రర్ వస్తుంది.
|
|
355
|
+
* * దీన్ని పరిష్కరించడానికి, రూపొందించిన JSON ఫైల్ పేరును ఈ విధంగా మార్చాలి:
|
|
356
|
+
* `${outputFileName}_data.json`
|
|
357
|
+
* * ఫలితం:
|
|
358
|
+
* - game_go_v2.mp3 -> R.raw.game_go_v2
|
|
359
|
+
* - game_go_v2_data.json -> R.raw.game_go_v2_data
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
### లూపింగ్ సౌండ్స్ (Looping Sounds)
|
|
363
|
+
|
|
364
|
+
మీరు `audiosprite` కమాండ్తో `--loop` ఎంపికను ఉపయోగించి లూపింగ్ శబ్దాలను సృష్టించవచ్చు. `--loop` ఎంపిక యొక్క విలువ మీరు లూప్ చేయాలనుకుంటున్న శబ్దం పేరు అయి ఉండాలి.
|
|
365
|
+
|
|
366
|
+
ఉదాహరణకు, `bg_music` శబ్దాన్ని లూప్ చేయడానికి, మీరు ఈ కింది కమాండ్ను ఉపయోగిస్తారు:
|
|
367
|
+
|
|
368
|
+
```sh
|
|
369
|
+
audiosprite --output audiosprite --format howler --loop "bg_music" --path ./src/__tests__/ Sound_1.m4a Sound_2.m4a Sound_3.m4a Sound_4.m4a bg_music.wav
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
మీరు లూపింగ్ శబ్దాన్ని ప్లే చేసినప్పుడు, మీరు `player.stop()` పద్ధతిని ఉపయోగించి దాన్ని ఆపే వరకు అది నిరంతరాయంగా ప్లే అవుతూనే ఉంటుంది. వెబ్ మరియు మొబైల్ ప్లాట్ఫారమ్లలో లూపింగ్ ఫంక్షనాలిటీకి మద్దతు ఉంది.
|
|
373
|
+
|
|
374
|
+
తరువాత, మీరు స్ప్రైట్ నుండి శబ్దాలను ప్లే చేయడానికి `AudioSpritePlayer`ని ఉపయోగించవచ్చు.
|
|
375
|
+
|
|
376
|
+
### ఆడియో రూటింగ్ మరియు వాల్యూమ్ నియంత్రణ (మిక్సర్ గ్రాఫ్)
|
|
377
|
+
|
|
378
|
+
ఈ లైబ్రరీ మిక్సర్ గ్రాఫ్ ఫీచర్ను కలిగి ఉంది, ఇది సౌండ్ ఎఫెక్ట్స్ (SFX) మరియు మ్యూజిక్ వాల్యూమ్లను విడివిడిగా, అలాగే గ్లోబల్ మాస్టర్ వాల్యూమ్ను నియంత్రించడానికి మిమ్మల్ని అనుమతిస్తుంది.
|
|
379
|
+
|
|
380
|
+
- `sfx`: చిన్న సౌండ్ ఎఫెక్ట్స్ (కాయిన్స్, జంప్స్, UI). అధిక ప్రాధాన్యత.
|
|
381
|
+
- `music`: నేపథ్య ట్రాక్లు (Background tracks). తక్కువ ప్రాధాన్యత.
|
|
382
|
+
|
|
383
|
+
శబ్దాన్ని ప్లే చేస్తున్నప్పుడు మీరు ఛానెల్ని పేర్కొనవచ్చు:
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// 'sfx' ఛానెల్లో ప్లే చేయండి (డిఫాల్ట్)
|
|
387
|
+
player.play('coin_sound');
|
|
388
|
+
|
|
389
|
+
// 'music' ఛానెల్లో ప్లే చేయండి
|
|
390
|
+
player.play('bg_music', { channel: 'music' });
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
మీరు వాల్యూమ్ను డైనమిక్గా నియంత్రించవచ్చు:
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
// మ్యూజిక్ వాల్యూమ్ను సెట్ చేయండి (0.0 నుండి 1.0)
|
|
397
|
+
player.setMusicVolume(0.5);
|
|
398
|
+
|
|
399
|
+
// SFX వాల్యూమ్ను సెట్ చేయండి (0.0 నుండి 1.0)
|
|
400
|
+
player.setSFXVolume(0.8);
|
|
401
|
+
|
|
402
|
+
// మాస్టర్ వాల్యూమ్ను సెట్ చేయండి (రెండింటినీ ప్రభావితం చేస్తుంది)
|
|
403
|
+
player.volume = 1.0;
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### బ్రౌజర్ ఎన్విరాన్మెంట్ (Browser Environment)
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
410
|
+
|
|
411
|
+
const player = new AudioSpritePlayer({
|
|
412
|
+
platform: 'web',
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
async function playSound(soundName: string) {
|
|
416
|
+
try {
|
|
417
|
+
// ఆడియో స్ప్రైట్ మానిఫెస్ట్ మరియు ఆడియో ఫైళ్లను లోడ్ చేయండి
|
|
418
|
+
// మీ audiosprite.json ఫైల్ పాత్ను సరిచూసుకోండి
|
|
419
|
+
await player.load('./src/__tests__/sounds/mygameaudio.json');
|
|
420
|
+
console.log('ఆడియో స్ప్రైట్ విజయవంతంగా లోడ్ అయింది.');
|
|
421
|
+
|
|
422
|
+
// స్ప్రైట్మ్యాప్ నుండి శబ్దాన్ని ప్లే చేయండి
|
|
423
|
+
player.play(soundName);
|
|
424
|
+
console.log(`శబ్దాన్ని ప్లే చేస్తోంది: ${soundName}`);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
console.error('శబ్దాన్ని ప్లే చేయడంలో లోపం:', error);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function stopSound() {
|
|
431
|
+
player.stop();
|
|
432
|
+
console.log('లూపింగ్ శబ్దం ఆగిపోయింది.');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// వినియోగ ఉదాహరణ:
|
|
436
|
+
playSound('Sound_1');
|
|
437
|
+
// playSound('Sound_2');
|
|
438
|
+
// లూపింగ్ శబ్దాన్ని ఆపడానికి:
|
|
439
|
+
// stopSound();
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### రియాక్ట్ నేటివ్ ఎన్విరాన్మెంట్ (React Native Environment)
|
|
443
|
+
|
|
444
|
+
రియాక్ట్ నేటివ్ కోసం, ఆడియో ప్లేబ్యాక్ మరియు అసెట్ లోడింగ్ను నిర్వహించడానికి మీకు `react-native-audio-api` మరియు `expo-asset` అవసరం.
|
|
445
|
+
|
|
446
|
+
ముందుగా, డిపెండెన్సీలను ఇన్స్టాల్ చేయండి:
|
|
447
|
+
|
|
448
|
+
```sh
|
|
449
|
+
npm install react-native-audio-api expo-asset expo-file-system
|
|
450
|
+
# లేదా
|
|
451
|
+
yarn add react-native-audio-api expo-asset expo-file-system
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
`react-native-audio-api` డాక్యుమెంటేషన్ ప్రకారం `metro.config.js`ని మార్చండి: https://docs.swmansion.com/react-native-audio-api/docs/fundamentals/getting-started
|
|
455
|
+
|
|
456
|
+
```js
|
|
457
|
+
module.exports = wrapWithAudioAPIMetroConfig(config);
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
తరువాత, మీరు దీన్ని మీ కాంపోనెంట్లో ఉపయోగించవచ్చు:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { StyleSheet, View, Text, Platform, TouchableOpacity } from 'react-native';
|
|
464
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
465
|
+
import { AudioManager, AudioContext } from 'react-native-audio-api';
|
|
466
|
+
import { useEffect, useState, useRef } from 'react';
|
|
467
|
+
import { Asset } from 'expo-asset';
|
|
468
|
+
import { fetch } from 'expo/fetch';
|
|
469
|
+
import manifest from '../assets/mygameaudio.json';
|
|
470
|
+
|
|
471
|
+
// ఆడియో అసెట్ను ఇంపోర్ట్ చేయండి
|
|
472
|
+
const audioAsset = require('../assets/mygameaudio.mp3');
|
|
473
|
+
|
|
474
|
+
export default function App() {
|
|
475
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
476
|
+
const playerRef = useRef<AudioSpritePlayer | null>(null);
|
|
477
|
+
|
|
478
|
+
useEffect(() => {
|
|
479
|
+
const loadPlayer = async () => {
|
|
480
|
+
const asset = Asset.fromModule(audioAsset);
|
|
481
|
+
await asset.downloadAsync();
|
|
482
|
+
const audioUri = asset.localUri || asset.uri;
|
|
483
|
+
|
|
484
|
+
if (!audioUri) {
|
|
485
|
+
console.error('ఆడియో URIని పొందడంలో విఫలమైంది.');
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (Platform.OS === 'ios') {
|
|
490
|
+
try {
|
|
491
|
+
await AudioManager.setAudioSessionOptions({
|
|
492
|
+
iosCategory: 'playback',
|
|
493
|
+
iosOptions: ['mixWithOthers'],
|
|
494
|
+
});
|
|
495
|
+
await AudioManager.setAudioSessionActivity(true);
|
|
496
|
+
} catch (e) {
|
|
497
|
+
console.error('AudioSession ఎంపికలను కాన్ఫిగర్ చేయడంలో విఫలమైంది:', e);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const audioContext = new AudioContext();
|
|
502
|
+
const audioPlayer = new AudioSpritePlayer({
|
|
503
|
+
audioContext,
|
|
504
|
+
fetch: fetch.bind(globalThis),
|
|
505
|
+
platform: Platform.OS,
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
await audioPlayer.load(manifest, audioUri);
|
|
510
|
+
playerRef.current = audioPlayer;
|
|
511
|
+
setIsLoaded(true);
|
|
512
|
+
console.log('ఆడియో స్ప్రైట్ విజయవంతంగా లోడ్ అయింది.');
|
|
513
|
+
} catch (error) {
|
|
514
|
+
console.error('ఆడియో స్ప్రైట్ను లోడ్ చేయడంలో విఫలమైంది:', error);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
loadPlayer();
|
|
519
|
+
}, []);
|
|
520
|
+
|
|
521
|
+
const playSound = (soundName: string) => {
|
|
522
|
+
const player = playerRef.current;
|
|
523
|
+
if (player && isLoaded) {
|
|
524
|
+
if (soundName === 'bg_loop') {
|
|
525
|
+
player.play(soundName, { channel: 'music' });
|
|
526
|
+
} else {
|
|
527
|
+
player.play(soundName);
|
|
528
|
+
}
|
|
529
|
+
console.log(`శబ్దాన్ని ప్లే చేస్తోంది: ${soundName}`);
|
|
530
|
+
} else {
|
|
531
|
+
console.warn('ప్లేయర్ ఇంకా లోడ్ కాలేదు.');
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const stopBGM = () => {
|
|
536
|
+
const player = playerRef.current;
|
|
537
|
+
if (player) {
|
|
538
|
+
player.stop();
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
return (
|
|
543
|
+
<View style={styles.container}>
|
|
544
|
+
<Text>AudioSprite Player ఉదాహరణ</Text>
|
|
545
|
+
<TouchableOpacity
|
|
546
|
+
onPress={() => loadPlayer()}
|
|
547
|
+
style={styles.button}
|
|
548
|
+
disabled={!isLoaded}
|
|
549
|
+
>
|
|
550
|
+
<Text style={styles.buttonText}>ప్లేయర్ని లోడ్ చేయండి</Text>
|
|
551
|
+
</TouchableOpacity>
|
|
552
|
+
<TouchableOpacity
|
|
553
|
+
onPress={() => playSound('Sound_1')}
|
|
554
|
+
style={styles.button}
|
|
555
|
+
disabled={!isLoaded}
|
|
556
|
+
>
|
|
557
|
+
<Text style={styles.buttonText}>Sound 1 ప్లే చేయండి</Text>
|
|
558
|
+
</TouchableOpacity>
|
|
559
|
+
<TouchableOpacity
|
|
560
|
+
onPress={() => playSound('Sound_2')}
|
|
561
|
+
style={styles.button}
|
|
562
|
+
disabled={!isLoaded}
|
|
563
|
+
>
|
|
564
|
+
<Text style={styles.buttonText}>Sound 2 ప్లే చేయండి</Text>
|
|
565
|
+
</TouchableOpacity>
|
|
566
|
+
<TouchableOpacity
|
|
567
|
+
onPress={() => playSound('bg_loop')}
|
|
568
|
+
style={styles.button}
|
|
569
|
+
disabled={!isLoaded}
|
|
570
|
+
>
|
|
571
|
+
<Text style={styles.buttonText}>బ్యాక్గ్రౌండ్ లూప్ను ప్లే చేయండి</Text>
|
|
572
|
+
</TouchableOpacity>
|
|
573
|
+
<TouchableOpacity
|
|
574
|
+
onPress={stopBGM}
|
|
575
|
+
style={styles.button}
|
|
576
|
+
disabled={!isLoaded}
|
|
577
|
+
>
|
|
578
|
+
<Text style={styles.buttonText}>BGM ఆపు</Text>
|
|
579
|
+
</TouchableOpacity>
|
|
580
|
+
</View>
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const styles = StyleSheet.create({
|
|
585
|
+
container: {
|
|
586
|
+
flex: 1,
|
|
587
|
+
alignItems: 'center',
|
|
588
|
+
justifyContent: 'center',
|
|
589
|
+
},
|
|
590
|
+
button: {
|
|
591
|
+
backgroundColor: '#DDDDDD',
|
|
592
|
+
padding: 10,
|
|
593
|
+
marginVertical: 5,
|
|
594
|
+
borderRadius: 5,
|
|
595
|
+
},
|
|
596
|
+
buttonText: {
|
|
597
|
+
color: '#000000',
|
|
598
|
+
textAlign: 'center',
|
|
599
|
+
},
|
|
600
|
+
});
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
## స్ఫూర్తి (Inspiration)
|
|
604
|
+
|
|
605
|
+
https://github.com/goldfire/howler.js
|
|
606
|
+
జనరేట్ చేయబడిన json new Howl({
|
|
607
|
+
sprite: {
|
|
608
|
+
key1: [offset, duration, (loop)]
|
|
609
|
+
},
|
|
610
|
+
}); తో కూడా పనిచేస్తుంది.
|
|
611
|
+
|
|
612
|
+
## సహకారం (Contributing)
|
|
613
|
+
|
|
614
|
+
- [డెవలప్మెంట్ వర్క్ఫ్లో](CONTRIBUTING.md#development-workflow)
|
|
615
|
+
- [పుల్ రిక్వెస్ట్ పంపడం](CONTRIBUTING.md#sending-a-pull-request)
|
|
616
|
+
- [ప్రవర్తనా నియమావళి](CODE_OF_CONDUCT.md)
|
|
617
|
+
|
|
618
|
+
## లైసెన్స్ (License)
|
|
619
|
+
|
|
620
|
+
MIT
|
|
621
|
+
|
|
622
|
+
## క్రెడిట్స్ (Credits)
|
|
623
|
+
|
|
624
|
+
[Shaker, Woda, Conga, Bongo, Templeblock.wav](https://freesound.org/people/kwazi/sounds/34115/) by [kwazi](https://freesound.org/people/kwazi/) | లైసెన్స్: [అట్రిబ్యూషన్ 3.0](http://creativecommons.org/licenses/by/3.0/)
|
|
625
|
+
|
|
626
|
+
[create-react-native-library](https://github.com/callstack/react-native-builder-bob)తో తయారు చేయబడింది
|
|
627
|
+
|
|
266
628
|
## Spanish
|
|
267
629
|
|
|
268
630
|

|
|
@@ -294,6 +656,18 @@ audiosprite --output src/__tests__/sounds/mygameaudio --format howler --loop "bg
|
|
|
294
656
|
|
|
295
657
|
Este comando generará `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a` y `mygameaudio.ac3` en el directorio `src/__tests__/sounds/`.
|
|
296
658
|
|
|
659
|
+
/**
|
|
660
|
+
* ⚠️ SOLUCIÓN DE CONFLICTO DE RECURSOS DE ANDROID ⚠️
|
|
661
|
+
* * El sistema de compilación de Android (Gradle) genera ID de recursos basados en nombres de archivo SIN extensiones.
|
|
662
|
+
* Si generamos "game_go_v2.mp3" y "game_go_v2.json", Android los ve a ambos
|
|
663
|
+
* como el ID de recurso `R.raw.game_go_v2`, lo que causa un error de compilación de "Recursos duplicados".
|
|
664
|
+
* * Para solucionar esto, renombre el archivo JSON generado a:
|
|
665
|
+
* `${outputFileName}_data.json`
|
|
666
|
+
* * Resultado:
|
|
667
|
+
* - game_go_v2.mp3 -> R.raw.game_go_v2
|
|
668
|
+
* - game_go_v2_data.json -> R.raw.game_go_v2_data
|
|
669
|
+
*/
|
|
670
|
+
|
|
297
671
|
### Sonidos en Bucle
|
|
298
672
|
|
|
299
673
|
Puedes crear sonidos en bucle usando la opción `--loop` con el comando `audiosprite`. El valor de la opción `--loop` debe ser el nombre del sonido que deseas repetir.
|
|
@@ -426,7 +800,11 @@ export default function App() {
|
|
|
426
800
|
const playSound = (soundName: string) => {
|
|
427
801
|
const player = playerRef.current;
|
|
428
802
|
if (player && isLoaded) {
|
|
429
|
-
|
|
803
|
+
if (soundName === 'bg_loop') {
|
|
804
|
+
player.play(soundName, { channel: 'music' });
|
|
805
|
+
} else {
|
|
806
|
+
player.play(soundName);
|
|
807
|
+
}
|
|
430
808
|
console.log(`Reproduciendo sonido: ${soundName}`);
|
|
431
809
|
} else {
|
|
432
810
|
console.warn('El reproductor aún no se ha cargado.');
|
|
@@ -557,6 +935,18 @@ audiosprite --output src/__tests__/sounds/mygameaudio --format howler --loop "bg
|
|
|
557
935
|
|
|
558
936
|
Эта команда создаст `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a` и `mygameaudio.ac3` в каталоге `src/__tests__/sounds/`.
|
|
559
937
|
|
|
938
|
+
/**
|
|
939
|
+
* ⚠️ ИСПРАВЛЕНИЕ КОНФЛИКТА РЕСУРСОВ ANDROID ⚠️
|
|
940
|
+
* * Система сборки Android (Gradle) генерирует идентификаторы ресурсов на основе имен файлов БЕЗ расширений.
|
|
941
|
+
* Если мы сгенерируем "game_go_v2.mp3" и "game_go_v2.json", Android увидит их обоих
|
|
942
|
+
* как идентификатор ресурса `R.raw.game_go_v2`, что вызовет ошибку сборки "Дублирующиеся ресурсы".
|
|
943
|
+
* * Чтобы исправить это, переименуйте сгенерированный файл JSON в:
|
|
944
|
+
* `${outputFileName}_data.json`
|
|
945
|
+
* * Результат:
|
|
946
|
+
* - game_go_v2.mp3 -> R.raw.game_go_v2
|
|
947
|
+
* - game_go_v2_data.json -> R.raw.game_go_v2_data
|
|
948
|
+
*/
|
|
949
|
+
|
|
560
950
|
### Зацикленные звуки
|
|
561
951
|
|
|
562
952
|
Вы можете создавать зацикленные звуки, используя опцию `--loop` с командой `audiosprite`. Значением опции `--loop` должно быть имя звука, который вы хотите зациклить.
|
|
@@ -689,7 +1079,11 @@ export default function App() {
|
|
|
689
1079
|
const playSound = (soundName: string) => {
|
|
690
1080
|
const player = playerRef.current;
|
|
691
1081
|
if (player && isLoaded) {
|
|
692
|
-
|
|
1082
|
+
if (soundName === 'bg_loop') {
|
|
1083
|
+
player.play(soundName, { channel: 'music' });
|
|
1084
|
+
} else {
|
|
1085
|
+
player.play(soundName);
|
|
1086
|
+
}
|
|
693
1087
|
console.log(`Воспроизведение звука: ${soundName}`);
|
|
694
1088
|
} else {
|
|
695
1089
|
console.warn('Проигрыватель еще не загружен.');
|
|
@@ -820,6 +1214,18 @@ audiosprite --output src/__tests__/sounds/mygameaudio --format howler --loop "bg
|
|
|
820
1214
|
|
|
821
1215
|
यह कमांड `src/__tests__/sounds/` डायरेक्टरी में `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a`, और `mygameaudio.ac3` उत्पन्न करेगा।
|
|
822
1216
|
|
|
1217
|
+
/**
|
|
1218
|
+
* ⚠️ Android संसाधन संघर्ष सुधार ⚠️
|
|
1219
|
+
* * Android की बिल्ड सिस्टम (Gradle) फ़ाइल नामों के आधार पर संसाधन ID उत्पन्न करती है बिना एक्सटेंशन के।
|
|
1220
|
+
* यदि हम "game_go_v2.mp3" और "game_go_v2.json" उत्पन्न करते हैं, तो Android उन दोनों को
|
|
1221
|
+
* `R.raw.game_go_v2` संसाधन ID के रूप में देखता है, जिससे "डुप्लिकेट संसाधन" बिल्ड त्रुटि होती है।
|
|
1222
|
+
* * इसे ठीक करने के लिए, उत्पन्न JSON फ़ाइल का नाम बदलकर यह करें:
|
|
1223
|
+
* `${outputFileName}_data.json`
|
|
1224
|
+
* * परिणाम:
|
|
1225
|
+
* - game_go_v2.mp3 -> R.raw.game_go_v2
|
|
1226
|
+
* - game_go_v2_data.json -> R.raw.game_go_v2_data
|
|
1227
|
+
*/
|
|
1228
|
+
|
|
823
1229
|
### लूपिंग ध्वनियाँ
|
|
824
1230
|
|
|
825
1231
|
आप `audiosprite` कमांड के साथ `--loop` विकल्प का उपयोग करके लूपिंग ध्वनियाँ बना सकते हैं। `--loop` विकल्प का मान उस ध्वनि का नाम होना चाहिए जिसे आप लूप करना चाहते हैं।
|
|
@@ -952,7 +1358,11 @@ export default function App() {
|
|
|
952
1358
|
const playSound = (soundName: string) => {
|
|
953
1359
|
const player = playerRef.current;
|
|
954
1360
|
if (player && isLoaded) {
|
|
955
|
-
|
|
1361
|
+
if (soundName === 'bg_loop') {
|
|
1362
|
+
player.play(soundName, { channel: 'music' });
|
|
1363
|
+
} else {
|
|
1364
|
+
player.play(soundName);
|
|
1365
|
+
}
|
|
956
1366
|
console.log(`ध्वनि बज रही है: ${soundName}`);
|
|
957
1367
|
} else {
|
|
958
1368
|
console.warn('खिलाड़ी अभी तक लोड नहीं हुआ है।');
|
|
@@ -1083,6 +1493,18 @@ audiosprite --output src/__tests__/sounds/mygameaudio --format howler --loop "bg
|
|
|
1083
1493
|
|
|
1084
1494
|
此命令将在 `src/__tests__/sounds/` 目录中生成 `mygameaudio.json`、`mygameaudio.mp3`、`mygameaudio.ogg`、`mygameaudio.m4a` 和 `mygameaudio.ac3`。
|
|
1085
1495
|
|
|
1496
|
+
/**
|
|
1497
|
+
* ⚠️ ANDROID 资源冲突修复 ⚠️
|
|
1498
|
+
* * Android 的构建系统 (Gradle) 基于不带扩展名的文件名生成资源 ID。
|
|
1499
|
+
* 如果我们生成 "game_go_v2.mp3" 和 "game_go_v2.json",Android 会将它们都视为
|
|
1500
|
+
* 资源 ID `R.raw.game_go_v2`,从而导致“重复资源”构建错误。
|
|
1501
|
+
* * 要修复此问题,请将生成的 JSON 文件重命名为:
|
|
1502
|
+
* `${outputFileName}_data.json`
|
|
1503
|
+
* * 结果:
|
|
1504
|
+
* - game_go_v2.mp3 -> R.raw.game_go_v2
|
|
1505
|
+
* - game_go_v2_data.json -> R.raw.game_go_v2_data
|
|
1506
|
+
*/
|
|
1507
|
+
|
|
1086
1508
|
### 循环声音
|
|
1087
1509
|
|
|
1088
1510
|
您可以使用 `audiosprite` 命令的 `--loop` 选项创建循环声音。`--loop` 选项的值应该是您想要循环的声音的名称。
|
|
@@ -1215,7 +1637,11 @@ export default function App() {
|
|
|
1215
1637
|
const playSound = (soundName: string) => {
|
|
1216
1638
|
const player = playerRef.current;
|
|
1217
1639
|
if (player && isLoaded) {
|
|
1218
|
-
|
|
1640
|
+
if (soundName === 'bg_loop') {
|
|
1641
|
+
player.play(soundName, { channel: 'music' });
|
|
1642
|
+
} else {
|
|
1643
|
+
player.play(soundName);
|
|
1644
|
+
}
|
|
1219
1645
|
console.log(`正在播放声音: ${soundName}`);
|
|
1220
1646
|
} else {
|
|
1221
1647
|
console.warn('播放器尚未加载。');
|
|
@@ -1313,4 +1739,4 @@ key1: [offset, duration, (loop)]
|
|
|
1313
1739
|
|
|
1314
1740
|
[Shaker, Woda, Conga, Bongo, Templeblock.wav](https://freesound.org/people/kwazi/sounds/34115/) by [kwazi](https://freesound.org/people/kwazi/) | 执照: [署名 3.0](http://creativecommons.org/licenses/by/3.0/)
|
|
1315
1741
|
|
|
1316
|
-
使用 [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 制作
|
|
1742
|
+
使用 [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 制作
|
package/lib/module/index.js
CHANGED
|
@@ -5,12 +5,28 @@
|
|
|
5
5
|
* Requires an AudioContext and fetch to be injected.
|
|
6
6
|
* Uses AudioBufferQueueSourceNode and buffer splitting for mobile stability.
|
|
7
7
|
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Defines the available audio routing channels.
|
|
11
|
+
* - 'sfx': Short sound effects (coins, jumps, UI). High priority, usually usually non-looping.
|
|
12
|
+
* - 'music': Background tracks. Lower priority, usually looping, separate volume control.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration options for playing a specific sound sprite.
|
|
17
|
+
*/
|
|
18
|
+
|
|
8
19
|
export class AudioSpritePlayer {
|
|
9
20
|
// The full audio buffer
|
|
10
21
|
|
|
11
22
|
// Cache for the small, pre-split AudioBuffers used by mobile's QueueSourceNode
|
|
12
23
|
spriteBufferCache = {};
|
|
13
24
|
loopingSource = null;
|
|
25
|
+
sourcePool = []; // NEW: Pool for non-looping sources
|
|
26
|
+
maxPoolSize = 5; // Adjust this based on testing (5 is a good start)
|
|
27
|
+
|
|
28
|
+
// NEW: The Mixer
|
|
29
|
+
|
|
14
30
|
constructor({
|
|
15
31
|
audioContext,
|
|
16
32
|
fetch,
|
|
@@ -40,6 +56,20 @@ export class AudioSpritePlayer {
|
|
|
40
56
|
// @ts-ignore
|
|
41
57
|
this.audioContext = new AudioContext();
|
|
42
58
|
}
|
|
59
|
+
|
|
60
|
+
// 1. Create Master Output
|
|
61
|
+
this.masterGain = this.audioContext.createGain();
|
|
62
|
+
this.masterGain.gain.value = 1.0;
|
|
63
|
+
this.masterGain.connect(this.audioContext.destination);
|
|
64
|
+
|
|
65
|
+
// 2. Create Channels
|
|
66
|
+
this.sfxGain = this.audioContext.createGain();
|
|
67
|
+
this.sfxGain.gain.value = 1.0;
|
|
68
|
+
this.sfxGain.connect(this.masterGain); // Connect to Master
|
|
69
|
+
|
|
70
|
+
this.musicGain = this.audioContext.createGain();
|
|
71
|
+
this.musicGain.gain.value = 1.0;
|
|
72
|
+
this.musicGain.connect(this.masterGain); // Connect to Master
|
|
43
73
|
}
|
|
44
74
|
|
|
45
75
|
/**
|
|
@@ -100,6 +130,59 @@ export class AudioSpritePlayer {
|
|
|
100
130
|
// console.log(`Cached sprite buffer for ${soundName}, frames: ${durationFrames}`);
|
|
101
131
|
}
|
|
102
132
|
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Retrieves a source node from the pool or creates a new one if the pool is under capacity.
|
|
136
|
+
*/
|
|
137
|
+
_getOrCreateSourceNode() {
|
|
138
|
+
if (this.platform === 'web') {
|
|
139
|
+
// Web logic remains simple: always create a standard AudioBufferSourceNode
|
|
140
|
+
const source = this.audioContext.createBufferSource();
|
|
141
|
+
// source.connect(this.audioContext.destination);
|
|
142
|
+
return source;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Mobile/QueueSourceNode logic
|
|
146
|
+
let source;
|
|
147
|
+
if (this.sourcePool.length > 0) {
|
|
148
|
+
source = this.sourcePool.pop(); // Reuse an available source
|
|
149
|
+
// Disconnect the previous onEnded handler if it had one
|
|
150
|
+
source.onEnded = null;
|
|
151
|
+
// console.log('Reusing source from pool. Pool size:', this.sourcePool.length);
|
|
152
|
+
} else if (this.sourcePool.length < this.maxPoolSize) {
|
|
153
|
+
// Create a new source if pool is not full
|
|
154
|
+
if (!this.audioContext.createBufferQueueSource) {
|
|
155
|
+
console.error('RNAS Error: createBufferQueueSource is not available. Cannot create pool.');
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
source = this.audioContext.createBufferQueueSource();
|
|
159
|
+
// source.connect(this.audioContext.destination);
|
|
160
|
+
// console.log('Created new source. Pool size:', this.sourcePool.length);
|
|
161
|
+
} else {
|
|
162
|
+
// If pool is full, we might have to block or fail.
|
|
163
|
+
// For simplicity, we'll return null and warn, but a robust system
|
|
164
|
+
// might implement a "wait-and-retry" mechanism.
|
|
165
|
+
console.warn('RNAS Warning: Source pool is full. Dropping non-looping sound.');
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Define the cleanup/recycling function
|
|
170
|
+
const cleanupAndRecycle = () => {
|
|
171
|
+
// Only recycle if we are under maxPoolSize and it's not the looping source
|
|
172
|
+
if (this.sourcePool.length < this.maxPoolSize) {
|
|
173
|
+
this.sourcePool.push(source);
|
|
174
|
+
// console.log('Recycled source. Pool size:', this.sourcePool.length);
|
|
175
|
+
} else {
|
|
176
|
+
// If pool is full, let it be garbage collected
|
|
177
|
+
source.disconnect();
|
|
178
|
+
// console.log('Source disconnected (GC candidate).');
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Assign the cleanup function to run when the sound finishes playing
|
|
183
|
+
source.onEnded = cleanupAndRecycle;
|
|
184
|
+
return source;
|
|
185
|
+
}
|
|
103
186
|
async load(json, audio) {
|
|
104
187
|
try {
|
|
105
188
|
let decodedBuffer;
|
|
@@ -157,7 +240,7 @@ export class AudioSpritePlayer {
|
|
|
157
240
|
throw error; // Re-throw for user to catch
|
|
158
241
|
}
|
|
159
242
|
}
|
|
160
|
-
play(soundName) {
|
|
243
|
+
play(soundName, options) {
|
|
161
244
|
if (!this.audioBuffer || !this.manifest) {
|
|
162
245
|
console.warn('Audio sprite not loaded. Call load() first.');
|
|
163
246
|
return;
|
|
@@ -179,6 +262,15 @@ export class AudioSpritePlayer {
|
|
|
179
262
|
console.warn(`Sound "${soundName}" has invalid duration.`);
|
|
180
263
|
return;
|
|
181
264
|
}
|
|
265
|
+
|
|
266
|
+
// 1. Determine Channel (Default to 'sfx')
|
|
267
|
+
const channel = options?.channel || 'sfx';
|
|
268
|
+
const targetNode = channel === 'music' ? this.musicGain : this.sfxGain;
|
|
269
|
+
|
|
270
|
+
// 2. Determine Loop (Options override Manifest)
|
|
271
|
+
// defined in your existing code as: const sound = this.manifest.sprite[soundName];
|
|
272
|
+
// const manifestLoop = sound[2];
|
|
273
|
+
const loop = options?.loop !== undefined ? options.loop : sound[2];
|
|
182
274
|
let source;
|
|
183
275
|
const spriteBuffer = this.spriteBufferCache[soundName];
|
|
184
276
|
|
|
@@ -192,12 +284,12 @@ export class AudioSpritePlayer {
|
|
|
192
284
|
console.error('RNAS Error: createBufferQueueSource is not available on this native platform.');
|
|
193
285
|
return;
|
|
194
286
|
}
|
|
195
|
-
const loop = sound[2];
|
|
196
287
|
if (loop) {
|
|
197
288
|
// Always use AudioBufferQueueSourceNode
|
|
198
289
|
source = this.audioContext.createBufferQueueSource();
|
|
199
290
|
source.enqueueBuffer(spriteBuffer);
|
|
200
|
-
source.connect(this.audioContext.destination);
|
|
291
|
+
// source.connect(this.audioContext.destination);
|
|
292
|
+
source.connect(targetNode);
|
|
201
293
|
|
|
202
294
|
// Manual looping using onEnded
|
|
203
295
|
const loopHandler = () => {
|
|
@@ -217,12 +309,19 @@ export class AudioSpritePlayer {
|
|
|
217
309
|
source.start(0); // Start immediately
|
|
218
310
|
this.loopingSource = source; // Store reference to looping source
|
|
219
311
|
} else {
|
|
220
|
-
//
|
|
221
|
-
source = this.
|
|
312
|
+
// **NEW: USE POOL FOR NON-LOOPING MOBILE SOUNDS**
|
|
313
|
+
source = this._getOrCreateSourceNode();
|
|
314
|
+
if (!source) return; // Dropped sound because pool was full
|
|
315
|
+
|
|
316
|
+
// Reconnect to the correct channel (since pooled nodes might have been connected elsewhere)
|
|
317
|
+
source.disconnect();
|
|
318
|
+
source.connect(targetNode);
|
|
319
|
+
|
|
320
|
+
// Must re-enqueue the buffer since the source was reused
|
|
222
321
|
source.enqueueBuffer(spriteBuffer);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
322
|
+
|
|
323
|
+
// Start immediately (start time 0 for BufferQueueSourceNode means "as soon as possible")
|
|
324
|
+
source.start(0);
|
|
226
325
|
}
|
|
227
326
|
} else {
|
|
228
327
|
// 🌐 WEB LOGIC (Standard Web Audio API)
|
|
@@ -232,8 +331,10 @@ export class AudioSpritePlayer {
|
|
|
232
331
|
return;
|
|
233
332
|
}
|
|
234
333
|
source.buffer = spriteBuffer;
|
|
235
|
-
source.connect(this.audioContext.destination);
|
|
236
|
-
|
|
334
|
+
// source.connect(this.audioContext.destination);
|
|
335
|
+
source.connect(targetNode);
|
|
336
|
+
|
|
337
|
+
// const loop = sound[2]; // audiosprite stores loop as the third element in the array
|
|
237
338
|
if (loop) {
|
|
238
339
|
source.loop = true;
|
|
239
340
|
source.loopStart = 0; // Relative to the spriteBuffer
|
|
@@ -277,5 +378,41 @@ export class AudioSpritePlayer {
|
|
|
277
378
|
console.log('RNAS: No looping audio to stop.');
|
|
278
379
|
}
|
|
279
380
|
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Sets the volume for background music only.
|
|
384
|
+
* @param value 0.0 to 1.0
|
|
385
|
+
*/
|
|
386
|
+
setMusicVolume(value) {
|
|
387
|
+
if (this.musicGain) {
|
|
388
|
+
// secure against uninitialized context
|
|
389
|
+
this.musicGain.gain.setTargetAtTime(value, this.audioContext.currentTime, 0.02);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Sets the volume for sound effects only.
|
|
395
|
+
* @param value 0.0 to 1.0
|
|
396
|
+
*/
|
|
397
|
+
setSFXVolume(value) {
|
|
398
|
+
if (this.sfxGain) {
|
|
399
|
+
this.sfxGain.gain.setTargetAtTime(value, this.audioContext.currentTime, 0.02);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Sets the Global Master Volume (affects both Music and SFX).
|
|
405
|
+
* @param value 0.0 to 1.0
|
|
406
|
+
*/
|
|
407
|
+
set volume(value) {
|
|
408
|
+
if (this.masterGain) {
|
|
409
|
+
this.masterGain.gain.setTargetAtTime(value, this.audioContext.currentTime, 0.02);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Master Volume getter
|
|
414
|
+
get volume() {
|
|
415
|
+
return this.masterGain?.gain?.value ?? 1.0;
|
|
416
|
+
}
|
|
280
417
|
}
|
|
281
418
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["AudioSpritePlayer","spriteBufferCache","loopingSource","constructor","audioContext","fetch","platform","AudioContext","Error","audioBuffer","manifest","createBufferSource","name","console","log","_cacheSpriteBuffers","sampleRate","numChannels","numberOfChannels","soundName","sprite","sound","startFrame","Math","floor","endFrame","ceil","durationFrames","warn","spriteBuffer","createBuffer","i","sourceData","getChannelData","destinationData","segment","subarray","set","load","json","audio","decodedBuffer","response","ok","statusText","urls","audioFileName","audioUrl","URL","url","href","audioResponse","arrayBuffer","decodeAudioData","typedArrayView","Uint8Array","buffer","error","play","state","resume","catch","e","duration","source","createBufferQueueSource","loop","enqueueBuffer","connect","destination","loopHandler","start","onEnded","stop","loopStart","loopEnd","getManifest","getAudioBuffer"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["AudioSpritePlayer","spriteBufferCache","loopingSource","sourcePool","maxPoolSize","constructor","audioContext","fetch","platform","AudioContext","Error","audioBuffer","manifest","createBufferSource","name","console","log","masterGain","createGain","gain","value","connect","destination","sfxGain","musicGain","_cacheSpriteBuffers","sampleRate","numChannels","numberOfChannels","soundName","sprite","sound","startFrame","Math","floor","endFrame","ceil","durationFrames","warn","spriteBuffer","createBuffer","i","sourceData","getChannelData","destinationData","segment","subarray","set","_getOrCreateSourceNode","source","length","pop","onEnded","createBufferQueueSource","error","cleanupAndRecycle","push","disconnect","load","json","audio","decodedBuffer","response","ok","statusText","urls","audioFileName","audioUrl","URL","url","href","audioResponse","arrayBuffer","decodeAudioData","typedArrayView","Uint8Array","buffer","play","options","state","resume","catch","e","duration","channel","targetNode","loop","undefined","enqueueBuffer","loopHandler","start","stop","loopStart","loopEnd","getManifest","getAudioBuffer","setMusicVolume","setTargetAtTime","currentTime","setSFXVolume","volume"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
* Requires an AudioContext and fetch to be injected.
|
|
4
4
|
* Uses AudioBufferQueueSourceNode and buffer splitting for mobile stability.
|
|
5
5
|
*/
|
|
6
|
+
/**
|
|
7
|
+
* Defines the available audio routing channels.
|
|
8
|
+
* - 'sfx': Short sound effects (coins, jumps, UI). High priority, usually usually non-looping.
|
|
9
|
+
* - 'music': Background tracks. Lower priority, usually looping, separate volume control.
|
|
10
|
+
*/
|
|
11
|
+
export type AudioChannel = 'sfx' | 'music';
|
|
12
|
+
/**
|
|
13
|
+
* Configuration options for playing a specific sound sprite.
|
|
14
|
+
*/
|
|
15
|
+
export interface PlayOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Specifies which mixer channel to route the audio through.
|
|
18
|
+
* Use 'music' for BGM to ensure it responds to music volume settings.
|
|
19
|
+
* @default 'sfx'
|
|
20
|
+
*/
|
|
21
|
+
channel?: AudioChannel;
|
|
22
|
+
/**
|
|
23
|
+
* Force the sound to loop (or not), overriding the setting
|
|
24
|
+
* defined in the original audiosprite JSON manifest.
|
|
25
|
+
*/
|
|
26
|
+
loop?: boolean;
|
|
27
|
+
}
|
|
6
28
|
export declare class AudioSpritePlayer {
|
|
7
29
|
audioContext: any | null;
|
|
8
30
|
fetch: any | null;
|
|
@@ -11,6 +33,11 @@ export declare class AudioSpritePlayer {
|
|
|
11
33
|
platform: string;
|
|
12
34
|
private spriteBufferCache;
|
|
13
35
|
private loopingSource;
|
|
36
|
+
private sourcePool;
|
|
37
|
+
private maxPoolSize;
|
|
38
|
+
masterGain: any;
|
|
39
|
+
sfxGain: any;
|
|
40
|
+
musicGain: any;
|
|
14
41
|
constructor({ audioContext, fetch, platform, }: {
|
|
15
42
|
audioContext: any | null;
|
|
16
43
|
fetch: any;
|
|
@@ -40,8 +67,12 @@ export declare class AudioSpritePlayer {
|
|
|
40
67
|
* }
|
|
41
68
|
*/
|
|
42
69
|
private _cacheSpriteBuffers;
|
|
70
|
+
/**
|
|
71
|
+
* Retrieves a source node from the pool or creates a new one if the pool is under capacity.
|
|
72
|
+
*/
|
|
73
|
+
private _getOrCreateSourceNode;
|
|
43
74
|
load(json: any, audio?: any): Promise<void>;
|
|
44
|
-
play(soundName: string): void;
|
|
75
|
+
play(soundName: string, options?: PlayOptions): void;
|
|
45
76
|
getManifest(): any;
|
|
46
77
|
getAudioBuffer(): any;
|
|
47
78
|
/**
|
|
@@ -49,5 +80,21 @@ export declare class AudioSpritePlayer {
|
|
|
49
80
|
* If a looping sound is playing, it will be stopped immediately.
|
|
50
81
|
*/
|
|
51
82
|
stop(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Sets the volume for background music only.
|
|
85
|
+
* @param value 0.0 to 1.0
|
|
86
|
+
*/
|
|
87
|
+
setMusicVolume(value: number): void;
|
|
88
|
+
/**
|
|
89
|
+
* Sets the volume for sound effects only.
|
|
90
|
+
* @param value 0.0 to 1.0
|
|
91
|
+
*/
|
|
92
|
+
setSFXVolume(value: number): void;
|
|
93
|
+
/**
|
|
94
|
+
* Sets the Global Master Volume (affects both Music and SFX).
|
|
95
|
+
* @param value 0.0 to 1.0
|
|
96
|
+
*/
|
|
97
|
+
set volume(value: number);
|
|
98
|
+
get volume(): number;
|
|
52
99
|
}
|
|
53
100
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,YAAY,EAAE,GAAG,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,GAAG,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,GAAG,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,iBAAiB,CAA2B;IACpD,OAAO,CAAC,aAAa,CAAoB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,OAAO,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,qBAAa,iBAAiB;IAC5B,YAAY,EAAE,GAAG,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,GAAG,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,GAAG,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,iBAAiB,CAA2B;IACpD,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAa;IAGzB,UAAU,EAAE,GAAG,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC;IACb,SAAS,EAAE,GAAG,CAAC;gBAEV,EACV,YAAY,EACZ,KAAK,EACL,QAAQ,GACT,EAAE;QACD,YAAY,EAAE,GAAG,GAAG,IAAI,CAAC;QACzB,KAAK,EAAE,GAAG,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;KAClB;IAgDD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,mBAAmB;IA8C3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAuDxB,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG;IA0EjC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW;IAoI7C,WAAW;IAIX,cAAc;IAId;;;OAGG;IACH,IAAI;IAUJ;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM;IAW5B;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM;IAU1B;;;OAGG;IACH,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAQvB;IAGD,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audiosprites",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "audio sprites ",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "audio sprites for react native ios, android and web",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
"typecheck": "tsc",
|
|
37
37
|
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
38
38
|
"clean": "del-cli lib",
|
|
39
|
+
"types:sync": "node scripts/generate-audio-types.mjs",
|
|
40
|
+
"prebuild": "npm run types:sync",
|
|
39
41
|
"prepare": "bob build",
|
|
40
42
|
"release:alpha": "release-it --preRelease=alpha",
|
|
41
43
|
"release": "release-it --only-version",
|
|
@@ -81,11 +83,13 @@
|
|
|
81
83
|
"@eslint/eslintrc": "^3.3.1",
|
|
82
84
|
"@eslint/js": "^9.35.0",
|
|
83
85
|
"@evilmartians/lefthook": "^1.12.3",
|
|
86
|
+
"@react-native-community/slider": "^5.1.1",
|
|
84
87
|
"@react-native/babel-preset": "0.81.1",
|
|
85
88
|
"@react-native/eslint-config": "^0.81.1",
|
|
86
89
|
"@release-it/conventional-changelog": "^10.0.1",
|
|
87
90
|
"@types/jest": "^29.5.14",
|
|
88
91
|
"@types/react": "^19.1.12",
|
|
92
|
+
"arktype": "^2.1.29",
|
|
89
93
|
"commitlint": "^19.8.1",
|
|
90
94
|
"del-cli": "^6.0.0",
|
|
91
95
|
"eslint": "^9.35.0",
|
|
@@ -95,9 +99,10 @@
|
|
|
95
99
|
"prettier": "^3.6.2",
|
|
96
100
|
"react": "19.1.0",
|
|
97
101
|
"react-native": "0.81.5",
|
|
98
|
-
"react-native-audio-api": "
|
|
102
|
+
"react-native-audio-api": "0.10.1",
|
|
99
103
|
"react-native-builder-bob": "^0.40.13",
|
|
100
104
|
"release-it": "^19.0.4",
|
|
105
|
+
"ts-morph": "^27.0.2",
|
|
101
106
|
"typescript": "^5.9.2"
|
|
102
107
|
},
|
|
103
108
|
"peerDependencies": {
|
package/src/index.tsx
CHANGED
|
@@ -3,6 +3,32 @@
|
|
|
3
3
|
* Requires an AudioContext and fetch to be injected.
|
|
4
4
|
* Uses AudioBufferQueueSourceNode and buffer splitting for mobile stability.
|
|
5
5
|
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Defines the available audio routing channels.
|
|
9
|
+
* - 'sfx': Short sound effects (coins, jumps, UI). High priority, usually usually non-looping.
|
|
10
|
+
* - 'music': Background tracks. Lower priority, usually looping, separate volume control.
|
|
11
|
+
*/
|
|
12
|
+
export type AudioChannel = 'sfx' | 'music';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Configuration options for playing a specific sound sprite.
|
|
16
|
+
*/
|
|
17
|
+
export interface PlayOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Specifies which mixer channel to route the audio through.
|
|
20
|
+
* Use 'music' for BGM to ensure it responds to music volume settings.
|
|
21
|
+
* @default 'sfx'
|
|
22
|
+
*/
|
|
23
|
+
channel?: AudioChannel;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Force the sound to loop (or not), overriding the setting
|
|
27
|
+
* defined in the original audiosprite JSON manifest.
|
|
28
|
+
*/
|
|
29
|
+
loop?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
6
32
|
export class AudioSpritePlayer {
|
|
7
33
|
audioContext: any | null;
|
|
8
34
|
fetch: any | null;
|
|
@@ -12,6 +38,13 @@ export class AudioSpritePlayer {
|
|
|
12
38
|
// Cache for the small, pre-split AudioBuffers used by mobile's QueueSourceNode
|
|
13
39
|
private spriteBufferCache: Record<string, any> = {};
|
|
14
40
|
private loopingSource: any | null = null;
|
|
41
|
+
private sourcePool: any[] = []; // NEW: Pool for non-looping sources
|
|
42
|
+
private maxPoolSize: number = 5; // Adjust this based on testing (5 is a good start)
|
|
43
|
+
|
|
44
|
+
// NEW: The Mixer
|
|
45
|
+
public masterGain: any;
|
|
46
|
+
public sfxGain: any;
|
|
47
|
+
public musicGain: any;
|
|
15
48
|
|
|
16
49
|
constructor({
|
|
17
50
|
audioContext,
|
|
@@ -53,6 +86,20 @@ export class AudioSpritePlayer {
|
|
|
53
86
|
// @ts-ignore
|
|
54
87
|
this.audioContext = new AudioContext();
|
|
55
88
|
}
|
|
89
|
+
|
|
90
|
+
// 1. Create Master Output
|
|
91
|
+
this.masterGain = this.audioContext.createGain();
|
|
92
|
+
this.masterGain.gain.value = 1.0;
|
|
93
|
+
this.masterGain.connect(this.audioContext.destination);
|
|
94
|
+
|
|
95
|
+
// 2. Create Channels
|
|
96
|
+
this.sfxGain = this.audioContext.createGain();
|
|
97
|
+
this.sfxGain.gain.value = 1.0;
|
|
98
|
+
this.sfxGain.connect(this.masterGain); // Connect to Master
|
|
99
|
+
|
|
100
|
+
this.musicGain = this.audioContext.createGain();
|
|
101
|
+
this.musicGain.gain.value = 1.0;
|
|
102
|
+
this.musicGain.connect(this.masterGain); // Connect to Master
|
|
56
103
|
}
|
|
57
104
|
|
|
58
105
|
/**
|
|
@@ -124,6 +171,64 @@ export class AudioSpritePlayer {
|
|
|
124
171
|
}
|
|
125
172
|
}
|
|
126
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Retrieves a source node from the pool or creates a new one if the pool is under capacity.
|
|
176
|
+
*/
|
|
177
|
+
private _getOrCreateSourceNode(): any {
|
|
178
|
+
if (this.platform === 'web') {
|
|
179
|
+
// Web logic remains simple: always create a standard AudioBufferSourceNode
|
|
180
|
+
const source = this.audioContext.createBufferSource();
|
|
181
|
+
// source.connect(this.audioContext.destination);
|
|
182
|
+
return source;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Mobile/QueueSourceNode logic
|
|
186
|
+
let source;
|
|
187
|
+
if (this.sourcePool.length > 0) {
|
|
188
|
+
source = this.sourcePool.pop(); // Reuse an available source
|
|
189
|
+
// Disconnect the previous onEnded handler if it had one
|
|
190
|
+
source.onEnded = null;
|
|
191
|
+
// console.log('Reusing source from pool. Pool size:', this.sourcePool.length);
|
|
192
|
+
} else if (this.sourcePool.length < this.maxPoolSize) {
|
|
193
|
+
// Create a new source if pool is not full
|
|
194
|
+
if (!this.audioContext.createBufferQueueSource) {
|
|
195
|
+
console.error(
|
|
196
|
+
'RNAS Error: createBufferQueueSource is not available. Cannot create pool.'
|
|
197
|
+
);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
source = this.audioContext.createBufferQueueSource();
|
|
201
|
+
// source.connect(this.audioContext.destination);
|
|
202
|
+
// console.log('Created new source. Pool size:', this.sourcePool.length);
|
|
203
|
+
} else {
|
|
204
|
+
// If pool is full, we might have to block or fail.
|
|
205
|
+
// For simplicity, we'll return null and warn, but a robust system
|
|
206
|
+
// might implement a "wait-and-retry" mechanism.
|
|
207
|
+
console.warn(
|
|
208
|
+
'RNAS Warning: Source pool is full. Dropping non-looping sound.'
|
|
209
|
+
);
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Define the cleanup/recycling function
|
|
214
|
+
const cleanupAndRecycle = () => {
|
|
215
|
+
// Only recycle if we are under maxPoolSize and it's not the looping source
|
|
216
|
+
if (this.sourcePool.length < this.maxPoolSize) {
|
|
217
|
+
this.sourcePool.push(source);
|
|
218
|
+
// console.log('Recycled source. Pool size:', this.sourcePool.length);
|
|
219
|
+
} else {
|
|
220
|
+
// If pool is full, let it be garbage collected
|
|
221
|
+
source.disconnect();
|
|
222
|
+
// console.log('Source disconnected (GC candidate).');
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Assign the cleanup function to run when the sound finishes playing
|
|
227
|
+
source.onEnded = cleanupAndRecycle;
|
|
228
|
+
|
|
229
|
+
return source;
|
|
230
|
+
}
|
|
231
|
+
|
|
127
232
|
async load(json: any, audio?: any) {
|
|
128
233
|
try {
|
|
129
234
|
let decodedBuffer: any;
|
|
@@ -198,7 +303,7 @@ export class AudioSpritePlayer {
|
|
|
198
303
|
}
|
|
199
304
|
}
|
|
200
305
|
|
|
201
|
-
play(soundName: string) {
|
|
306
|
+
play(soundName: string, options?: PlayOptions) {
|
|
202
307
|
if (!this.audioBuffer || !this.manifest) {
|
|
203
308
|
console.warn('Audio sprite not loaded. Call load() first.');
|
|
204
309
|
return;
|
|
@@ -223,6 +328,15 @@ export class AudioSpritePlayer {
|
|
|
223
328
|
return;
|
|
224
329
|
}
|
|
225
330
|
|
|
331
|
+
// 1. Determine Channel (Default to 'sfx')
|
|
332
|
+
const channel = options?.channel || 'sfx';
|
|
333
|
+
const targetNode = channel === 'music' ? this.musicGain : this.sfxGain;
|
|
334
|
+
|
|
335
|
+
// 2. Determine Loop (Options override Manifest)
|
|
336
|
+
// defined in your existing code as: const sound = this.manifest.sprite[soundName];
|
|
337
|
+
// const manifestLoop = sound[2];
|
|
338
|
+
const loop = options?.loop !== undefined ? options.loop : sound[2];
|
|
339
|
+
|
|
226
340
|
let source: any;
|
|
227
341
|
const spriteBuffer = this.spriteBufferCache[soundName];
|
|
228
342
|
|
|
@@ -242,13 +356,12 @@ export class AudioSpritePlayer {
|
|
|
242
356
|
return;
|
|
243
357
|
}
|
|
244
358
|
|
|
245
|
-
const loop = sound[2];
|
|
246
|
-
|
|
247
359
|
if (loop) {
|
|
248
360
|
// Always use AudioBufferQueueSourceNode
|
|
249
361
|
source = this.audioContext.createBufferQueueSource();
|
|
250
362
|
source.enqueueBuffer(spriteBuffer);
|
|
251
|
-
source.connect(this.audioContext.destination);
|
|
363
|
+
// source.connect(this.audioContext.destination);
|
|
364
|
+
source.connect(targetNode);
|
|
252
365
|
|
|
253
366
|
// Manual looping using onEnded
|
|
254
367
|
const loopHandler = () => {
|
|
@@ -268,12 +381,19 @@ export class AudioSpritePlayer {
|
|
|
268
381
|
source.start(0); // Start immediately
|
|
269
382
|
this.loopingSource = source; // Store reference to looping source
|
|
270
383
|
} else {
|
|
271
|
-
//
|
|
272
|
-
source = this.
|
|
384
|
+
// **NEW: USE POOL FOR NON-LOOPING MOBILE SOUNDS**
|
|
385
|
+
source = this._getOrCreateSourceNode();
|
|
386
|
+
if (!source) return; // Dropped sound because pool was full
|
|
387
|
+
|
|
388
|
+
// Reconnect to the correct channel (since pooled nodes might have been connected elsewhere)
|
|
389
|
+
source.disconnect();
|
|
390
|
+
source.connect(targetNode);
|
|
391
|
+
|
|
392
|
+
// Must re-enqueue the buffer since the source was reused
|
|
273
393
|
source.enqueueBuffer(spriteBuffer);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
394
|
+
|
|
395
|
+
// Start immediately (start time 0 for BufferQueueSourceNode means "as soon as possible")
|
|
396
|
+
source.start(0);
|
|
277
397
|
}
|
|
278
398
|
} else {
|
|
279
399
|
// 🌐 WEB LOGIC (Standard Web Audio API)
|
|
@@ -287,9 +407,10 @@ export class AudioSpritePlayer {
|
|
|
287
407
|
}
|
|
288
408
|
|
|
289
409
|
source.buffer = spriteBuffer;
|
|
290
|
-
source.connect(this.audioContext.destination);
|
|
410
|
+
// source.connect(this.audioContext.destination);
|
|
411
|
+
source.connect(targetNode);
|
|
291
412
|
|
|
292
|
-
const loop = sound[2]; // audiosprite stores loop as the third element in the array
|
|
413
|
+
// const loop = sound[2]; // audiosprite stores loop as the third element in the array
|
|
293
414
|
if (loop) {
|
|
294
415
|
source.loop = true;
|
|
295
416
|
source.loopStart = 0; // Relative to the spriteBuffer
|
|
@@ -335,4 +456,52 @@ export class AudioSpritePlayer {
|
|
|
335
456
|
console.log('RNAS: No looping audio to stop.');
|
|
336
457
|
}
|
|
337
458
|
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Sets the volume for background music only.
|
|
462
|
+
* @param value 0.0 to 1.0
|
|
463
|
+
*/
|
|
464
|
+
setMusicVolume(value: number) {
|
|
465
|
+
if (this.musicGain) {
|
|
466
|
+
// secure against uninitialized context
|
|
467
|
+
this.musicGain.gain.setTargetAtTime(
|
|
468
|
+
value,
|
|
469
|
+
this.audioContext.currentTime,
|
|
470
|
+
0.02
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Sets the volume for sound effects only.
|
|
477
|
+
* @param value 0.0 to 1.0
|
|
478
|
+
*/
|
|
479
|
+
setSFXVolume(value: number) {
|
|
480
|
+
if (this.sfxGain) {
|
|
481
|
+
this.sfxGain.gain.setTargetAtTime(
|
|
482
|
+
value,
|
|
483
|
+
this.audioContext.currentTime,
|
|
484
|
+
0.02
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Sets the Global Master Volume (affects both Music and SFX).
|
|
491
|
+
* @param value 0.0 to 1.0
|
|
492
|
+
*/
|
|
493
|
+
set volume(value: number) {
|
|
494
|
+
if (this.masterGain) {
|
|
495
|
+
this.masterGain.gain.setTargetAtTime(
|
|
496
|
+
value,
|
|
497
|
+
this.audioContext.currentTime,
|
|
498
|
+
0.02
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Master Volume getter
|
|
504
|
+
get volume(): number {
|
|
505
|
+
return this.masterGain?.gain?.value ?? 1.0;
|
|
506
|
+
}
|
|
338
507
|
}
|