react-native-audiosprites 0.3.1 → 0.4.1
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 +1056 -0
- package/lib/module/index.js +75 -6
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.tsx +78 -6
package/README.md
CHANGED
|
@@ -258,3 +258,1059 @@ MIT
|
|
|
258
258
|
[Shaker, Woda, Conga, Bongo, Templeblock.wav](https://freesound.org/people/kwazi/sounds/34115/) by [kwazi](https://freesound.org/people/kwazi/) | License: [Attribution 3.0](http://creativecommons.org/licenses/by/3.0/)
|
|
259
259
|
|
|
260
260
|
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
# Translations
|
|
265
|
+
|
|
266
|
+
## Spanish
|
|
267
|
+
|
|
268
|
+

|
|
269
|
+
|
|
270
|
+
# react-native-audiosprites
|
|
271
|
+
|
|
272
|
+
Un reproductor universal para sprites de audio generados por la herramienta 'audiosprite'.
|
|
273
|
+
¡Soporta la reproducción de múltiples sonidos al mismo tiempo!
|
|
274
|
+
|
|
275
|
+
## Instalación
|
|
276
|
+
|
|
277
|
+
```sh
|
|
278
|
+
npm install react-native-audiosprites
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```sh
|
|
282
|
+
yarn add react-native-audiosprites
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Uso
|
|
286
|
+
|
|
287
|
+
Primero, necesitas generar un sprite de audio y un archivo de manifiesto JSON usando la herramienta `audiosprite`.
|
|
288
|
+
|
|
289
|
+
Asumiendo que tienes [`audiosprite`](https://www.npmjs.com/package/audiosprite) instalado globalmente:
|
|
290
|
+
|
|
291
|
+
```sh
|
|
292
|
+
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
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Este comando generará `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a` y `mygameaudio.ac3` en el directorio `src/__tests__/sounds/`.
|
|
296
|
+
|
|
297
|
+
### Sonidos en Bucle
|
|
298
|
+
|
|
299
|
+
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.
|
|
300
|
+
|
|
301
|
+
Por ejemplo, para repetir el sonido `bg_music`, usarías el siguiente comando:
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
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
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Cuando reproduces un sonido en bucle, se reproducirá continuamente hasta que lo detengas usando el método `player.stop()`. La funcionalidad de bucle es compatible tanto en plataformas web como móviles.
|
|
308
|
+
|
|
309
|
+
Luego, puedes usar el `AudioSpritePlayer` para reproducir los sonidos del sprite.
|
|
310
|
+
|
|
311
|
+
### Entorno del Navegador
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
315
|
+
|
|
316
|
+
const player = new AudioSpritePlayer({
|
|
317
|
+
platform: 'web',
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
async function playSound(soundName: string) {
|
|
321
|
+
try {
|
|
322
|
+
// Carga el manifiesto del sprite de audio y los archivos de audio
|
|
323
|
+
// Ajusta la ruta a tu archivo audiosprite.json
|
|
324
|
+
await player.load('./src/__tests__/sounds/mygameaudio.json');
|
|
325
|
+
console.log('Sprite de audio cargado exitosamente.');
|
|
326
|
+
|
|
327
|
+
// Reproduce un sonido del spritemap
|
|
328
|
+
player.play(soundName);
|
|
329
|
+
console.log(`Reproduciendo sonido: ${soundName}`);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
console.error('Error al reproducir el sonido:', error);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function stopSound() {
|
|
336
|
+
player.stop();
|
|
337
|
+
console.log('Sonido en bucle detenido.');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Ejemplo de uso:
|
|
341
|
+
playSound('Sound_1');
|
|
342
|
+
// playSound('Sound_2');
|
|
343
|
+
// Para detener un sonido en bucle:
|
|
344
|
+
// stopSound();
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Entorno de React Native
|
|
348
|
+
|
|
349
|
+
Para React Native, necesitarás `react-native-audio-api` y `expo-asset` para manejar la reproducción de audio y la carga de activos.
|
|
350
|
+
|
|
351
|
+
Primero, instala las dependencias:
|
|
352
|
+
|
|
353
|
+
```sh
|
|
354
|
+
npm install react-native-audio-api expo-asset expo-file-system
|
|
355
|
+
# o
|
|
356
|
+
yarn add react-native-audio-api expo-asset expo-file-system
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Cambia `metro.config.js` según la documentación de `react-native-audio-api`: https://docs.swmansion.com/react-native-audio-api/docs/fundamentals/getting-started
|
|
360
|
+
|
|
361
|
+
```js
|
|
362
|
+
module.exports = wrapWithAudioAPIMetroConfig(config);
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Luego, puedes usarlo en tu componente:
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import { StyleSheet, View, Text, Platform, TouchableOpacity } from 'react-native';
|
|
369
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
370
|
+
import { AudioManager, AudioContext } from 'react-native-audio-api';
|
|
371
|
+
import { useEffect, useState, useRef } from 'react';
|
|
372
|
+
import { Asset } from 'expo-asset';
|
|
373
|
+
import { fetch } from 'expo/fetch';
|
|
374
|
+
import manifest from '../assets/mygameaudio.json';
|
|
375
|
+
|
|
376
|
+
// Importa el activo de audio
|
|
377
|
+
const audioAsset = require('../assets/mygameaudio.mp3');
|
|
378
|
+
|
|
379
|
+
export default function App() {
|
|
380
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
381
|
+
const playerRef = useRef<AudioSpritePlayer | null>(null);
|
|
382
|
+
|
|
383
|
+
useEffect(() => {
|
|
384
|
+
const loadPlayer = async () => {
|
|
385
|
+
const asset = Asset.fromModule(audioAsset);
|
|
386
|
+
await asset.downloadAsync();
|
|
387
|
+
const audioUri = asset.localUri || asset.uri;
|
|
388
|
+
|
|
389
|
+
if (!audioUri) {
|
|
390
|
+
console.error('No se pudo obtener la URI del audio.');
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (Platform.OS === 'ios') {
|
|
395
|
+
try {
|
|
396
|
+
await AudioManager.setAudioSessionOptions({
|
|
397
|
+
iosCategory: 'playback',
|
|
398
|
+
iosOptions: ['mixWithOthers'],
|
|
399
|
+
});
|
|
400
|
+
await AudioManager.setAudioSessionActivity(true);
|
|
401
|
+
} catch (e) {
|
|
402
|
+
console.error('Error al configurar las opciones de AudioSession:', e);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const audioContext = new AudioContext();
|
|
407
|
+
const audioPlayer = new AudioSpritePlayer({
|
|
408
|
+
audioContext,
|
|
409
|
+
fetch: fetch.bind(globalThis),
|
|
410
|
+
platform: Platform.OS,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
try {
|
|
414
|
+
await audioPlayer.load(manifest, audioUri);
|
|
415
|
+
playerRef.current = audioPlayer;
|
|
416
|
+
setIsLoaded(true);
|
|
417
|
+
console.log('Sprite de audio cargado exitosamente.');
|
|
418
|
+
} catch (error) {
|
|
419
|
+
console.error('Error al cargar el sprite de audio:', error);
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
loadPlayer();
|
|
424
|
+
}, []);
|
|
425
|
+
|
|
426
|
+
const playSound = (soundName: string) => {
|
|
427
|
+
const player = playerRef.current;
|
|
428
|
+
if (player && isLoaded) {
|
|
429
|
+
player.play(soundName);
|
|
430
|
+
console.log(`Reproduciendo sonido: ${soundName}`);
|
|
431
|
+
} else {
|
|
432
|
+
console.warn('El reproductor aún no se ha cargado.');
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const stopBGM = () => {
|
|
437
|
+
const player = playerRef.current;
|
|
438
|
+
if (player) {
|
|
439
|
+
player.stop();
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
return (
|
|
444
|
+
<View style={styles.container}>
|
|
445
|
+
<Text>Ejemplo de AudioSprite Player</Text>
|
|
446
|
+
<TouchableOpacity
|
|
447
|
+
onPress={() => loadPlayer()}
|
|
448
|
+
style={styles.button}
|
|
449
|
+
disabled={!isLoaded}
|
|
450
|
+
>
|
|
451
|
+
<Text style={styles.buttonText}>Cargar Reproductor</Text>
|
|
452
|
+
</TouchableOpacity>
|
|
453
|
+
<TouchableOpacity
|
|
454
|
+
onPress={() => playSound('Sound_1')}
|
|
455
|
+
style={styles.button}
|
|
456
|
+
disabled={!isLoaded}
|
|
457
|
+
>
|
|
458
|
+
<Text style={styles.buttonText}>Reproducir Sonido 1</Text>
|
|
459
|
+
</TouchableOpacity>
|
|
460
|
+
<TouchableOpacity
|
|
461
|
+
onPress={() => playSound('Sound_2')}
|
|
462
|
+
style={styles.button}
|
|
463
|
+
disabled={!isLoaded}
|
|
464
|
+
>
|
|
465
|
+
<Text style={styles.buttonText}>Reproducir Sonido 2</Text>
|
|
466
|
+
</TouchableOpacity>
|
|
467
|
+
<TouchableOpacity
|
|
468
|
+
onPress={() => playSound('bg_loop')}
|
|
469
|
+
style={styles.button}
|
|
470
|
+
disabled={!isLoaded}
|
|
471
|
+
>
|
|
472
|
+
<Text style={styles.buttonText}>Reproducir Bucle de Fondo</Text>
|
|
473
|
+
</TouchableOpacity>
|
|
474
|
+
<TouchableOpacity
|
|
475
|
+
onPress={stopBGM}
|
|
476
|
+
style={styles.button}
|
|
477
|
+
disabled={!isLoaded}
|
|
478
|
+
>
|
|
479
|
+
<Text style={styles.buttonText}>Detener BGM</Text>
|
|
480
|
+
</TouchableOpacity>
|
|
481
|
+
</View>
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const styles = StyleSheet.create({
|
|
486
|
+
container: {
|
|
487
|
+
flex: 1,
|
|
488
|
+
alignItems: 'center',
|
|
489
|
+
justifyContent: 'center',
|
|
490
|
+
},
|
|
491
|
+
button: {
|
|
492
|
+
backgroundColor: '#DDDDDD',
|
|
493
|
+
padding: 10,
|
|
494
|
+
marginVertical: 5,
|
|
495
|
+
borderRadius: 5,
|
|
496
|
+
},
|
|
497
|
+
buttonText: {
|
|
498
|
+
color: '#000000',
|
|
499
|
+
textAlign: 'center',
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
## Inspiración
|
|
505
|
+
|
|
506
|
+
https://github.com/goldfire/howler.js
|
|
507
|
+
El json generado también funciona con new Howl({
|
|
508
|
+
sprite: {
|
|
509
|
+
key1: [offset, duration, (loop)]
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
## Contribuciones
|
|
514
|
+
|
|
515
|
+
- [Flujo de trabajo de desarrollo](CONTRIBUTING.md#development-workflow)
|
|
516
|
+
- [Enviar una pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
517
|
+
- [Código de conducta](CODE_OF_CONDUCT.md)
|
|
518
|
+
|
|
519
|
+
## Licencia
|
|
520
|
+
|
|
521
|
+
MIT
|
|
522
|
+
|
|
523
|
+
## Créditos
|
|
524
|
+
|
|
525
|
+
[Shaker, Woda, Conga, Bongo, Templeblock.wav](https://freesound.org/people/kwazi/sounds/34115/) por [kwazi](https://freesound.org/people/kwazi/) | Licencia: [Atribución 3.0](http://creativecommons.org/licenses/by/3.0/)
|
|
526
|
+
|
|
527
|
+
Hecho con [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
528
|
+
|
|
529
|
+
## Russian
|
|
530
|
+
|
|
531
|
+

|
|
532
|
+
|
|
533
|
+
# react-native-audiosprites
|
|
534
|
+
|
|
535
|
+
Универсальный проигрыватель для аудио-спрайтов, созданных с помощью инструмента 'audiosprite'.
|
|
536
|
+
Поддерживает одновременное воспроизведение нескольких звуков!
|
|
537
|
+
|
|
538
|
+
## Установка
|
|
539
|
+
|
|
540
|
+
```sh
|
|
541
|
+
npm install react-native-audiosprites
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
```sh
|
|
545
|
+
yarn add react-native-audiosprites
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
## Использование
|
|
549
|
+
|
|
550
|
+
Сначала вам нужно создать аудио-спрайт и файл манифеста JSON с помощью инструмента `audiosprite`.
|
|
551
|
+
|
|
552
|
+
Предполагая, что у вас глобально установлен [`audiosprite`](https://www.npmjs.com/package/audiosprite):
|
|
553
|
+
|
|
554
|
+
```sh
|
|
555
|
+
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
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Эта команда создаст `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a` и `mygameaudio.ac3` в каталоге `src/__tests__/sounds/`.
|
|
559
|
+
|
|
560
|
+
### Зацикленные звуки
|
|
561
|
+
|
|
562
|
+
Вы можете создавать зацикленные звуки, используя опцию `--loop` с командой `audiosprite`. Значением опции `--loop` должно быть имя звука, который вы хотите зациклить.
|
|
563
|
+
|
|
564
|
+
Например, чтобы зациклить звук `bg_music`, вы должны использовать следующую команду:
|
|
565
|
+
|
|
566
|
+
```sh
|
|
567
|
+
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
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
Когда вы воспроизводите зацикленный звук, он будет воспроизводиться непрерывно, пока вы не остановите его с помощью метода `player.stop()`. Функция зацикливания поддерживается как на веб-, так и на мобильных платформах.
|
|
571
|
+
|
|
572
|
+
Затем вы можете использовать `AudioSpritePlayer` для воспроизведения звуков из спрайта.
|
|
573
|
+
|
|
574
|
+
### Среда браузера
|
|
575
|
+
|
|
576
|
+
```typescript
|
|
577
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
578
|
+
|
|
579
|
+
const player = new AudioSpritePlayer({
|
|
580
|
+
platform: 'web',
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
async function playSound(soundName: string) {
|
|
584
|
+
try {
|
|
585
|
+
// Загрузите манифест аудио-спрайта и аудиофайлы
|
|
586
|
+
// Укажите правильный путь к вашему файлу audiosprite.json
|
|
587
|
+
await player.load('./src/__tests__/sounds/mygameaudio.json');
|
|
588
|
+
console.log('Аудио-спрайт успешно загружен.');
|
|
589
|
+
|
|
590
|
+
// Воспроизведите звук из spritemap
|
|
591
|
+
player.play(soundName);
|
|
592
|
+
console.log(`Воспроизведение звука: ${soundName}`);
|
|
593
|
+
} catch (error) {
|
|
594
|
+
console.error('Ошибка воспроизведения звука:', error);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function stopSound() {
|
|
599
|
+
player.stop();
|
|
600
|
+
console.log('Зацикленный звук остановлен.');
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Пример использования:
|
|
604
|
+
playSound('Sound_1');
|
|
605
|
+
// playSound('Sound_2');
|
|
606
|
+
// Чтобы остановить зацикленный звук:
|
|
607
|
+
// stopSound();
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### Среда React Native
|
|
611
|
+
|
|
612
|
+
Для React Native вам понадобятся `react-native-audio-api` и `expo-asset` для обработки воспроизведения аудио и загрузки ресурсов.
|
|
613
|
+
|
|
614
|
+
Сначала установите зависимости:
|
|
615
|
+
|
|
616
|
+
```sh
|
|
617
|
+
npm install react-native-audio-api expo-asset expo-file-system
|
|
618
|
+
# или
|
|
619
|
+
yarn add react-native-audio-api expo-asset expo-file-system
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
Измените `metro.config.js` в соответствии с документацией `react-native-audio-api`: https://docs.swmansion.com/react-native-audio-api/docs/fundamentals/getting-started
|
|
623
|
+
|
|
624
|
+
```js
|
|
625
|
+
module.exports = wrapWithAudioAPIMetroConfig(config);
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Затем вы можете использовать его в своем компоненте:
|
|
629
|
+
|
|
630
|
+
```typescript
|
|
631
|
+
import { StyleSheet, View, Text, Platform, TouchableOpacity } from 'react-native';
|
|
632
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
633
|
+
import { AudioManager, AudioContext } from 'react-native-audio-api';
|
|
634
|
+
import { useEffect, useState, useRef } from 'react';
|
|
635
|
+
import { Asset } from 'expo-asset';
|
|
636
|
+
import { fetch } from 'expo/fetch';
|
|
637
|
+
import manifest from '../assets/mygameaudio.json';
|
|
638
|
+
|
|
639
|
+
// Импортируйте аудио-ресурс
|
|
640
|
+
const audioAsset = require('../assets/mygameaudio.mp3');
|
|
641
|
+
|
|
642
|
+
export default function App() {
|
|
643
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
644
|
+
const playerRef = useRef<AudioSpritePlayer | null>(null);
|
|
645
|
+
|
|
646
|
+
useEffect(() => {
|
|
647
|
+
const loadPlayer = async () => {
|
|
648
|
+
const asset = Asset.fromModule(audioAsset);
|
|
649
|
+
await asset.downloadAsync();
|
|
650
|
+
const audioUri = asset.localUri || asset.uri;
|
|
651
|
+
|
|
652
|
+
if (!audioUri) {
|
|
653
|
+
console.error('Не удалось получить URI аудио.');
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (Platform.OS === 'ios') {
|
|
658
|
+
try {
|
|
659
|
+
await AudioManager.setAudioSessionOptions({
|
|
660
|
+
iosCategory: 'playback',
|
|
661
|
+
iosOptions: ['mixWithOthers'],
|
|
662
|
+
});
|
|
663
|
+
await AudioManager.setAudioSessionActivity(true);
|
|
664
|
+
} catch (e) {
|
|
665
|
+
console.error('Не удалось настроить параметры AudioSession:', e);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const audioContext = new AudioContext();
|
|
670
|
+
const audioPlayer = new AudioSpritePlayer({
|
|
671
|
+
audioContext,
|
|
672
|
+
fetch: fetch.bind(globalThis),
|
|
673
|
+
platform: Platform.OS,
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
await audioPlayer.load(manifest, audioUri);
|
|
678
|
+
playerRef.current = audioPlayer;
|
|
679
|
+
setIsLoaded(true);
|
|
680
|
+
console.log('Аудио-спрайт успешно загружен.');
|
|
681
|
+
} catch (error) {
|
|
682
|
+
console.error('Не удалось загрузить аудио-спрайт:', error);
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
loadPlayer();
|
|
687
|
+
}, []);
|
|
688
|
+
|
|
689
|
+
const playSound = (soundName: string) => {
|
|
690
|
+
const player = playerRef.current;
|
|
691
|
+
if (player && isLoaded) {
|
|
692
|
+
player.play(soundName);
|
|
693
|
+
console.log(`Воспроизведение звука: ${soundName}`);
|
|
694
|
+
} else {
|
|
695
|
+
console.warn('Проигрыватель еще не загружен.');
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
const stopBGM = () => {
|
|
700
|
+
const player = playerRef.current;
|
|
701
|
+
if (player) {
|
|
702
|
+
player.stop();
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
return (
|
|
707
|
+
<View style={styles.container}>
|
|
708
|
+
<Text>Пример AudioSprite Player</Text>
|
|
709
|
+
<TouchableOpacity
|
|
710
|
+
onPress={() => loadPlayer()}
|
|
711
|
+
style={styles.button}
|
|
712
|
+
disabled={!isLoaded}
|
|
713
|
+
>
|
|
714
|
+
<Text style={styles.buttonText}>Загрузить проигрыватель</Text>
|
|
715
|
+
</TouchableOpacity>
|
|
716
|
+
<TouchableOpacity
|
|
717
|
+
onPress={() => playSound('Sound_1')}
|
|
718
|
+
style={styles.button}
|
|
719
|
+
disabled={!isLoaded}
|
|
720
|
+
>
|
|
721
|
+
<Text style={styles.buttonText}>Воспроизвести звук 1</Text>
|
|
722
|
+
</TouchableOpacity>
|
|
723
|
+
<TouchableOpacity
|
|
724
|
+
onPress={() => playSound('Sound_2')}
|
|
725
|
+
style={styles.button}
|
|
726
|
+
disabled={!isLoaded}
|
|
727
|
+
>
|
|
728
|
+
<Text style={styles.buttonText}>Воспроизвести звук 2</Text>
|
|
729
|
+
</TouchableOpacity>
|
|
730
|
+
<TouchableOpacity
|
|
731
|
+
onPress={() => playSound('bg_loop')}
|
|
732
|
+
style={styles.button}
|
|
733
|
+
disabled={!isLoaded}
|
|
734
|
+
>
|
|
735
|
+
<Text style={styles.buttonText}>Воспроизвести фоновый цикл</Text>
|
|
736
|
+
</TouchableOpacity>
|
|
737
|
+
<TouchableOpacity
|
|
738
|
+
onPress={stopBGM}
|
|
739
|
+
style={styles.button}
|
|
740
|
+
disabled={!isLoaded}
|
|
741
|
+
>
|
|
742
|
+
<Text style={styles.buttonText}>Остановить фоновую музыку</Text>
|
|
743
|
+
</TouchableOpacity>
|
|
744
|
+
</View>
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const styles = StyleSheet.create({
|
|
749
|
+
container: {
|
|
750
|
+
flex: 1,
|
|
751
|
+
alignItems: 'center',
|
|
752
|
+
justifyContent: 'center',
|
|
753
|
+
},
|
|
754
|
+
button: {
|
|
755
|
+
backgroundColor: '#DDDDDD',
|
|
756
|
+
padding: 10,
|
|
757
|
+
marginVertical: 5,
|
|
758
|
+
borderRadius: 5,
|
|
759
|
+
},
|
|
760
|
+
buttonText: {
|
|
761
|
+
color: '#000000',
|
|
762
|
+
textAlign: 'center',
|
|
763
|
+
},
|
|
764
|
+
});
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
## Вдохновение
|
|
768
|
+
|
|
769
|
+
https://github.com/goldfire/howler.js
|
|
770
|
+
Сгенерированный json также работает с new Howl({
|
|
771
|
+
sprite: {
|
|
772
|
+
key1: [offset, duration, (loop)]
|
|
773
|
+
},
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
## Участие
|
|
777
|
+
|
|
778
|
+
- [Рабочий процесс разработки](CONTRIBUTING.md#development-workflow)
|
|
779
|
+
- [Отправка pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
780
|
+
- [Кодекс поведения](CODE_OF_CONDUCT.md)
|
|
781
|
+
|
|
782
|
+
## Лицензия
|
|
783
|
+
|
|
784
|
+
MIT
|
|
785
|
+
|
|
786
|
+
## Кредиты
|
|
787
|
+
|
|
788
|
+
[Shaker, Woda, Conga, Bongo, Templeblock.wav](https://freesound.org/people/kwazi/sounds/34115/) от [kwazi](https://freesound.org/people/kwazi/) | Лицензия: [Attribution 3.0](http://creativecommons.org/licenses/by/3.0/)
|
|
789
|
+
|
|
790
|
+
Сделано с помощью [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
791
|
+
|
|
792
|
+
## Hindi
|
|
793
|
+
|
|
794
|
+

|
|
795
|
+
|
|
796
|
+
# react-native-audiosprites
|
|
797
|
+
|
|
798
|
+
'ऑडियोस्प्राइट' टूल द्वारा उत्पन्न ऑडियो स्प्राइट्स के लिए एक सार्वभौमिक खिलाड़ी।
|
|
799
|
+
एक ही समय में कई ध्वनियाँ बजाने का समर्थन करता है!
|
|
800
|
+
|
|
801
|
+
## स्थापना
|
|
802
|
+
|
|
803
|
+
```sh
|
|
804
|
+
npm install react-native-audiosprites
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
```sh
|
|
808
|
+
yarn add react-native-audiosprites
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
## उपयोग
|
|
812
|
+
|
|
813
|
+
सबसे पहले, आपको `audiosprite` टूल का उपयोग करके एक ऑडियो स्प्राइट और एक JSON मैनिफ़ेस्ट फ़ाइल उत्पन्न करने की आवश्यकता है।
|
|
814
|
+
|
|
815
|
+
मान लें कि आपके पास विश्व स्तर पर [`audiosprite`](https://www.npmjs.com/package/audiosprite) स्थापित है:
|
|
816
|
+
|
|
817
|
+
```sh
|
|
818
|
+
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
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
यह कमांड `src/__tests__/sounds/` डायरेक्टरी में `mygameaudio.json`, `mygameaudio.mp3`, `mygameaudio.ogg`, `mygameaudio.m4a`, और `mygameaudio.ac3` उत्पन्न करेगा।
|
|
822
|
+
|
|
823
|
+
### लूपिंग ध्वनियाँ
|
|
824
|
+
|
|
825
|
+
आप `audiosprite` कमांड के साथ `--loop` विकल्प का उपयोग करके लूपिंग ध्वनियाँ बना सकते हैं। `--loop` विकल्प का मान उस ध्वनि का नाम होना चाहिए जिसे आप लूप करना चाहते हैं।
|
|
826
|
+
|
|
827
|
+
उदाहरण के लिए, `bg_music` ध्वनि को लूप करने के लिए, आप निम्न कमांड का उपयोग करेंगे:
|
|
828
|
+
|
|
829
|
+
```sh
|
|
830
|
+
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
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
जब आप एक लूपिंग ध्वनि बजाते हैं, तो यह तब तक लगातार बजेगी जब तक आप इसे `player.stop()` विधि का उपयोग करके रोक नहीं देते। लूपिंग कार्यक्षमता वेब और मोबाइल दोनों प्लेटफार्मों पर समर्थित है।
|
|
834
|
+
|
|
835
|
+
फिर, आप स्प्राइट से ध्वनियों को चलाने के लिए `AudioSpritePlayer` का उपयोग कर सकते हैं।
|
|
836
|
+
|
|
837
|
+
### ब्राउज़र पर्यावरण
|
|
838
|
+
|
|
839
|
+
```typescript
|
|
840
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
841
|
+
|
|
842
|
+
const player = new AudioSpritePlayer({
|
|
843
|
+
platform: 'web',
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
async function playSound(soundName: string) {
|
|
847
|
+
try {
|
|
848
|
+
// ऑडियो स्प्राइट मैनिफ़ेस्ट और ऑडियो फ़ाइलें लोड करें
|
|
849
|
+
// अपनी audiosprite.json फ़ाइल का पथ समायोजित करें
|
|
850
|
+
await player.load('./src/__tests__/sounds/mygameaudio.json');
|
|
851
|
+
console.log('ऑडियो स्प्राइट सफलतापूर्वक लोड हो गया।');
|
|
852
|
+
|
|
853
|
+
// स्प्राइटमैप से एक ध्वनि चलाएं
|
|
854
|
+
player.play(soundName);
|
|
855
|
+
console.log(`ध्वनि बज रही है: ${soundName}`);
|
|
856
|
+
} catch (error) {
|
|
857
|
+
console.error('ध्वनि बजाने में त्रुटि:', error);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
function stopSound() {
|
|
862
|
+
player.stop();
|
|
863
|
+
console.log('लूपिंग ध्वनि बंद हो गई।');
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// उदाहरण उपयोग:
|
|
867
|
+
playSound('Sound_1');
|
|
868
|
+
// playSound('Sound_2');
|
|
869
|
+
// एक लूपिंग ध्वनि को रोकने के लिए:
|
|
870
|
+
// stopSound();
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### रिएक्ट नेटिव पर्यावरण
|
|
874
|
+
|
|
875
|
+
रिएक्ट नेटिव के लिए, आपको ऑडियो प्लेबैक और एसेट लोडिंग को संभालने के लिए `react-native-audio-api` और `expo-asset` की आवश्यकता होगी।
|
|
876
|
+
|
|
877
|
+
सबसे पहले, निर्भरताएँ स्थापित करें:
|
|
878
|
+
|
|
879
|
+
```sh
|
|
880
|
+
npm install react-native-audio-api expo-asset expo-file-system
|
|
881
|
+
# या
|
|
882
|
+
yarn add react-native-audio-api expo-asset expo-file-system
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
`react-native-audio-api` दस्तावेज़ीकरण के अनुसार `metro.config.js` बदलें: https://docs.swmansion.com/react-native-audio-api/docs/fundamentals/getting-started
|
|
886
|
+
|
|
887
|
+
```js
|
|
888
|
+
module.exports = wrapWithAudioAPIMetroConfig(config);
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
फिर, आप इसे अपने घटक में उपयोग कर सकते हैं:
|
|
892
|
+
|
|
893
|
+
```typescript
|
|
894
|
+
import { StyleSheet, View, Text, Platform, TouchableOpacity } from 'react-native';
|
|
895
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
896
|
+
import { AudioManager, AudioContext } from 'react-native-audio-api';
|
|
897
|
+
import { useEffect, useState, useRef } from 'react';
|
|
898
|
+
import { Asset } from 'expo-asset';
|
|
899
|
+
import { fetch } from 'expo/fetch';
|
|
900
|
+
import manifest from '../assets/mygameaudio.json';
|
|
901
|
+
|
|
902
|
+
// ऑडियो एसेट आयात करें
|
|
903
|
+
const audioAsset = require('../assets/mygameaudio.mp3');
|
|
904
|
+
|
|
905
|
+
export default function App() {
|
|
906
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
907
|
+
const playerRef = useRef<AudioSpritePlayer | null>(null);
|
|
908
|
+
|
|
909
|
+
useEffect(() => {
|
|
910
|
+
const loadPlayer = async () => {
|
|
911
|
+
const asset = Asset.fromModule(audioAsset);
|
|
912
|
+
await asset.downloadAsync();
|
|
913
|
+
const audioUri = asset.localUri || asset.uri;
|
|
914
|
+
|
|
915
|
+
if (!audioUri) {
|
|
916
|
+
console.error('ऑडियो URI प्राप्त करने में विफल।');
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (Platform.OS === 'ios') {
|
|
921
|
+
try {
|
|
922
|
+
await AudioManager.setAudioSessionOptions({
|
|
923
|
+
iosCategory: 'playback',
|
|
924
|
+
iosOptions: ['mixWithOthers'],
|
|
925
|
+
});
|
|
926
|
+
await AudioManager.setAudioSessionActivity(true);
|
|
927
|
+
} catch (e) {
|
|
928
|
+
console.error('ऑडियो सत्र विकल्प कॉन्फ़िगर करने में विफल:', e);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const audioContext = new AudioContext();
|
|
933
|
+
const audioPlayer = new AudioSpritePlayer({
|
|
934
|
+
audioContext,
|
|
935
|
+
fetch: fetch.bind(globalThis),
|
|
936
|
+
platform: Platform.OS,
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
try {
|
|
940
|
+
await audioPlayer.load(manifest, audioUri);
|
|
941
|
+
playerRef.current = audioPlayer;
|
|
942
|
+
setIsLoaded(true);
|
|
943
|
+
console.log('ऑडियो स्प्राइट सफलतापूर्वक लोड हो गया।');
|
|
944
|
+
} catch (error) {
|
|
945
|
+
console.error('ऑडियो स्प्राइट लोड करने में विफल:', error);
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
loadPlayer();
|
|
950
|
+
}, []);
|
|
951
|
+
|
|
952
|
+
const playSound = (soundName: string) => {
|
|
953
|
+
const player = playerRef.current;
|
|
954
|
+
if (player && isLoaded) {
|
|
955
|
+
player.play(soundName);
|
|
956
|
+
console.log(`ध्वनि बज रही है: ${soundName}`);
|
|
957
|
+
} else {
|
|
958
|
+
console.warn('खिलाड़ी अभी तक लोड नहीं हुआ है।');
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
|
|
962
|
+
const stopBGM = () => {
|
|
963
|
+
const player = playerRef.current;
|
|
964
|
+
if (player) {
|
|
965
|
+
player.stop();
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
return (
|
|
970
|
+
<View style={styles.container}>
|
|
971
|
+
<Text>ऑडियोस्प्राइट प्लेयर उदाहरण</Text>
|
|
972
|
+
<TouchableOpacity
|
|
973
|
+
onPress={() => loadPlayer()}
|
|
974
|
+
style={styles.button}
|
|
975
|
+
disabled={!isLoaded}
|
|
976
|
+
>
|
|
977
|
+
<Text style={styles.buttonText}>खिलाड़ी लोड करें</Text>
|
|
978
|
+
</TouchableOpacity>
|
|
979
|
+
<TouchableOpacity
|
|
980
|
+
onPress={() => playSound('Sound_1')}
|
|
981
|
+
style={styles.button}
|
|
982
|
+
disabled={!isLoaded}
|
|
983
|
+
>
|
|
984
|
+
<Text style={styles.buttonText}>ध्वनि 1 चलाएं</Text>
|
|
985
|
+
</TouchableOpacity>
|
|
986
|
+
<TouchableOpacity
|
|
987
|
+
onPress={() => playSound('Sound_2')}
|
|
988
|
+
style={styles.button}
|
|
989
|
+
disabled={!isLoaded}
|
|
990
|
+
>
|
|
991
|
+
<Text style={styles.buttonText}>ध्वनि 2 चलाएं</Text>
|
|
992
|
+
</TouchableOpacity>
|
|
993
|
+
<TouchableOpacity
|
|
994
|
+
onPress={() => playSound('bg_loop')}
|
|
995
|
+
style={styles.button}
|
|
996
|
+
disabled={!isLoaded}
|
|
997
|
+
>
|
|
998
|
+
<Text style={styles.buttonText}>पृष्ठभूमि लूप चलाएं</Text>
|
|
999
|
+
</TouchableOpacity>
|
|
1000
|
+
<TouchableOpacity
|
|
1001
|
+
onPress={stopBGM}
|
|
1002
|
+
style={styles.button}
|
|
1003
|
+
disabled={!isLoaded}
|
|
1004
|
+
>
|
|
1005
|
+
<Text style={styles.buttonText}>बीजीएम रोकें</Text>
|
|
1006
|
+
</TouchableOpacity>
|
|
1007
|
+
</View>
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
const styles = StyleSheet.create({
|
|
1012
|
+
container: {
|
|
1013
|
+
flex: 1,
|
|
1014
|
+
alignItems: 'center',
|
|
1015
|
+
justifyContent: 'center',
|
|
1016
|
+
},
|
|
1017
|
+
button: {
|
|
1018
|
+
backgroundColor: '#DDDDDD',
|
|
1019
|
+
padding: 10,
|
|
1020
|
+
marginVertical: 5,
|
|
1021
|
+
borderRadius: 5,
|
|
1022
|
+
},
|
|
1023
|
+
buttonText: {
|
|
1024
|
+
color: '#000000',
|
|
1025
|
+
textAlign: 'center',
|
|
1026
|
+
},
|
|
1027
|
+
});
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
## प्रेरणा
|
|
1031
|
+
|
|
1032
|
+
https://github.com/goldfire/howler.js
|
|
1033
|
+
उत्पन्न json new Howl({
|
|
1034
|
+
sprite: {
|
|
1035
|
+
key1: [offset, duration, (loop)]
|
|
1036
|
+
},
|
|
1037
|
+
}); के साथ भी काम करता है।
|
|
1038
|
+
|
|
1039
|
+
## योगदान
|
|
1040
|
+
|
|
1041
|
+
- [विकास कार्यप्रवाह](CONTRIBUTING.md#development-workflow)
|
|
1042
|
+
- [एक पुल अनुरोध भेजना](CONTRIBUTING.md#sending-a-pull-request)
|
|
1043
|
+
- [आचार संहिता](CODE_OF_CONDUCT.md)
|
|
1044
|
+
|
|
1045
|
+
## लाइसेंस
|
|
1046
|
+
|
|
1047
|
+
एमआईटी
|
|
1048
|
+
|
|
1049
|
+
## क्रेडिट
|
|
1050
|
+
|
|
1051
|
+
[kwazi](https://freesound.org/people/kwazi/) द्वारा [शकर, वोडा, कोंगा, बोंगो, टेम्पलब्लॉक.wav](https://freesound.org/people/kwazi/sounds/34115/) | लाइसेंस: [एट्रिब्यूशन 3.0](http://creativecommons.org/licenses/by/3.0/)
|
|
1052
|
+
|
|
1053
|
+
[create-react-native-library](https://github.com/callstack/react-native-builder-bob) के साथ बनाया गया
|
|
1054
|
+
|
|
1055
|
+
## Chinese
|
|
1056
|
+
|
|
1057
|
+

|
|
1058
|
+
|
|
1059
|
+
# react-native-audiosprites
|
|
1060
|
+
|
|
1061
|
+
一个用于播放由“audiosprite”工具生成的音频精灵的通用播放器。
|
|
1062
|
+
支持同时播放多种声音!
|
|
1063
|
+
|
|
1064
|
+
## 安装
|
|
1065
|
+
|
|
1066
|
+
```sh
|
|
1067
|
+
npm install react-native-audiosprites
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
```sh
|
|
1071
|
+
yarn add react-native-audiosprites
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
## 用法
|
|
1075
|
+
|
|
1076
|
+
首先,您需要使用 `audiosprite` 工具生成一个音频精灵和一个 JSON 清单文件。
|
|
1077
|
+
|
|
1078
|
+
假设您已全局安装 [`audiosprite`](https://www.npmjs.com/package/audiosprite):
|
|
1079
|
+
|
|
1080
|
+
```sh
|
|
1081
|
+
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
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
此命令将在 `src/__tests__/sounds/` 目录中生成 `mygameaudio.json`、`mygameaudio.mp3`、`mygameaudio.ogg`、`mygameaudio.m4a` 和 `mygameaudio.ac3`。
|
|
1085
|
+
|
|
1086
|
+
### 循环声音
|
|
1087
|
+
|
|
1088
|
+
您可以使用 `audiosprite` 命令的 `--loop` 选项创建循环声音。`--loop` 选项的值应该是您想要循环的声音的名称。
|
|
1089
|
+
|
|
1090
|
+
例如,要循环 `bg_music` 声音,您将使用以下命令:
|
|
1091
|
+
|
|
1092
|
+
```sh
|
|
1093
|
+
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
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
当您播放循环声音时,它将连续播放,直到您使用 `player.stop()` 方法停止它。循环功能在 Web 和移动平台上都受支持。
|
|
1097
|
+
|
|
1098
|
+
然后,您可以使用 `AudioSpritePlayer` 播放精灵中的声音。
|
|
1099
|
+
|
|
1100
|
+
### 浏览器环境
|
|
1101
|
+
|
|
1102
|
+
```typescript
|
|
1103
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
1104
|
+
|
|
1105
|
+
const player = new AudioSpritePlayer({
|
|
1106
|
+
platform: 'web',
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
async function playSound(soundName: string) {
|
|
1110
|
+
try {
|
|
1111
|
+
// 加载音频精灵清单和音频文件
|
|
1112
|
+
// 调整到您的 audiosprite.json 文件的路径
|
|
1113
|
+
await player.load('./src/__tests__/sounds/mygameaudio.json');
|
|
1114
|
+
console.log('音频精灵已成功加载。');
|
|
1115
|
+
|
|
1116
|
+
// 从 spritemap 播放声音
|
|
1117
|
+
player.play(soundName);
|
|
1118
|
+
console.log(`正在播放声音: ${soundName}`);
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
console.error('播放声音时出错:', error);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
function stopSound() {
|
|
1125
|
+
player.stop();
|
|
1126
|
+
console.log('已停止循环声音。');
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// 用法示例:
|
|
1130
|
+
playSound('Sound_1');
|
|
1131
|
+
// playSound('Sound_2');
|
|
1132
|
+
// 停止循环声音:
|
|
1133
|
+
// stopSound();
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
### React Native 环境
|
|
1137
|
+
|
|
1138
|
+
对于 React Native,您需要 `react-native-audio-api` 和 `expo-asset` 来处理音频播放和资产加载。
|
|
1139
|
+
|
|
1140
|
+
首先,安装依赖项:
|
|
1141
|
+
|
|
1142
|
+
```sh
|
|
1143
|
+
npm install react-native-audio-api expo-asset expo-file-system
|
|
1144
|
+
# 或
|
|
1145
|
+
yarn add react-native-audio-api expo-asset expo-file-system
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
根据 `react-native-audio-api` 文档更改 `metro.config.js`:https://docs.swmansion.com/react-native-audio-api/docs/fundamentals/getting-started
|
|
1149
|
+
|
|
1150
|
+
```js
|
|
1151
|
+
module.exports = wrapWithAudioAPIMetroConfig(config);
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
然后,您可以在您的组件中使用它:
|
|
1155
|
+
|
|
1156
|
+
```typescript
|
|
1157
|
+
import { StyleSheet, View, Text, Platform, TouchableOpacity } from 'react-native';
|
|
1158
|
+
import { AudioSpritePlayer } from 'react-native-audiosprites';
|
|
1159
|
+
import { AudioManager, AudioContext } from 'react-native-audio-api';
|
|
1160
|
+
import { useEffect, useState, useRef } from 'react';
|
|
1161
|
+
import { Asset } from 'expo-asset';
|
|
1162
|
+
import { fetch } from 'expo/fetch';
|
|
1163
|
+
import manifest from '../assets/mygameaudio.json';
|
|
1164
|
+
|
|
1165
|
+
// 导入音频资产
|
|
1166
|
+
const audioAsset = require('../assets/mygameaudio.mp3');
|
|
1167
|
+
|
|
1168
|
+
export default function App() {
|
|
1169
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
1170
|
+
const playerRef = useRef<AudioSpritePlayer | null>(null);
|
|
1171
|
+
|
|
1172
|
+
useEffect(() => {
|
|
1173
|
+
const loadPlayer = async () => {
|
|
1174
|
+
const asset = Asset.fromModule(audioAsset);
|
|
1175
|
+
await asset.downloadAsync();
|
|
1176
|
+
const audioUri = asset.localUri || asset.uri;
|
|
1177
|
+
|
|
1178
|
+
if (!audioUri) {
|
|
1179
|
+
console.error('无法获取音频 URI。');
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
if (Platform.OS === 'ios') {
|
|
1184
|
+
try {
|
|
1185
|
+
await AudioManager.setAudioSessionOptions({
|
|
1186
|
+
iosCategory: 'playback',
|
|
1187
|
+
iosOptions: ['mixWithOthers'],
|
|
1188
|
+
});
|
|
1189
|
+
await AudioManager.setAudioSessionActivity(true);
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
console.error('配置 AudioSession 选项失败:', e);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
const audioContext = new AudioContext();
|
|
1196
|
+
const audioPlayer = new AudioSpritePlayer({
|
|
1197
|
+
audioContext,
|
|
1198
|
+
fetch: fetch.bind(globalThis),
|
|
1199
|
+
platform: Platform.OS,
|
|
1200
|
+
});
|
|
1201
|
+
|
|
1202
|
+
try {
|
|
1203
|
+
await audioPlayer.load(manifest, audioUri);
|
|
1204
|
+
playerRef.current = audioPlayer;
|
|
1205
|
+
setIsLoaded(true);
|
|
1206
|
+
console.log('音频精灵已成功加载。');
|
|
1207
|
+
} catch (error) {
|
|
1208
|
+
console.error('加载音频精灵失败:', error);
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
loadPlayer();
|
|
1213
|
+
}, []);
|
|
1214
|
+
|
|
1215
|
+
const playSound = (soundName: string) => {
|
|
1216
|
+
const player = playerRef.current;
|
|
1217
|
+
if (player && isLoaded) {
|
|
1218
|
+
player.play(soundName);
|
|
1219
|
+
console.log(`正在播放声音: ${soundName}`);
|
|
1220
|
+
} else {
|
|
1221
|
+
console.warn('播放器尚未加载。');
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
const stopBGM = () => {
|
|
1226
|
+
const player = playerRef.current;
|
|
1227
|
+
if (player) {
|
|
1228
|
+
player.stop();
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
return (
|
|
1233
|
+
<View style={styles.container}>
|
|
1234
|
+
<Text>AudioSprite 播放器示例</Text>
|
|
1235
|
+
<TouchableOpacity
|
|
1236
|
+
onPress={() => loadPlayer()}
|
|
1237
|
+
style={styles.button}
|
|
1238
|
+
disabled={!isLoaded}
|
|
1239
|
+
>
|
|
1240
|
+
<Text style={styles.buttonText}>加载播放器</Text>
|
|
1241
|
+
</TouchableOpacity>
|
|
1242
|
+
<TouchableOpacity
|
|
1243
|
+
onPress={() => playSound('Sound_1')}
|
|
1244
|
+
style={styles.button}
|
|
1245
|
+
disabled={!isLoaded}
|
|
1246
|
+
>
|
|
1247
|
+
<Text style={styles.buttonText}>播放声音 1</Text>
|
|
1248
|
+
</TouchableOpacity>
|
|
1249
|
+
<TouchableOpacity
|
|
1250
|
+
onPress={() => playSound('Sound_2')}
|
|
1251
|
+
style={styles.button}
|
|
1252
|
+
disabled={!isLoaded}
|
|
1253
|
+
>
|
|
1254
|
+
<Text style={styles.buttonText}>播放声音 2</Text>
|
|
1255
|
+
</TouchableOpacity>
|
|
1256
|
+
<TouchableOpacity
|
|
1257
|
+
onPress={() => playSound('bg_loop')}
|
|
1258
|
+
style={styles.button}
|
|
1259
|
+
disabled={!isLoaded}
|
|
1260
|
+
>
|
|
1261
|
+
<Text style={styles.buttonText}>播放背景循环</Text>
|
|
1262
|
+
</TouchableOpacity>
|
|
1263
|
+
<TouchableOpacity
|
|
1264
|
+
onPress={stopBGM}
|
|
1265
|
+
style={styles.button}
|
|
1266
|
+
disabled={!isLoaded}
|
|
1267
|
+
>
|
|
1268
|
+
<Text style={styles.buttonText}>停止背景音乐</Text>
|
|
1269
|
+
</TouchableOpacity>
|
|
1270
|
+
</View>
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
const styles = StyleSheet.create({
|
|
1275
|
+
container: {
|
|
1276
|
+
flex: 1,
|
|
1277
|
+
alignItems: 'center',
|
|
1278
|
+
justifyContent: 'center',
|
|
1279
|
+
},
|
|
1280
|
+
button: {
|
|
1281
|
+
backgroundColor: '#DDDDDD',
|
|
1282
|
+
padding: 10,
|
|
1283
|
+
marginVertical: 5,
|
|
1284
|
+
borderRadius: 5,
|
|
1285
|
+
},
|
|
1286
|
+
buttonText: {
|
|
1287
|
+
color: '#000000',
|
|
1288
|
+
textAlign: 'center',
|
|
1289
|
+
},
|
|
1290
|
+
});
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
## 灵感
|
|
1294
|
+
|
|
1295
|
+
https://github.com/goldfire/howler.js
|
|
1296
|
+
生成的 json 也适用于 new Howl({
|
|
1297
|
+
sprite: {
|
|
1298
|
+
key1: [offset, duration, (loop)]
|
|
1299
|
+
},
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
## 贡献
|
|
1303
|
+
|
|
1304
|
+
- [开发工作流程](CONTRIBUTING.md#development-workflow)
|
|
1305
|
+
- [发送拉取请求](CONTRIBUTING.md#sending-a-pull-request)
|
|
1306
|
+
- [行为准则](CODE_OF_CONDUCT.md)
|
|
1307
|
+
|
|
1308
|
+
## 执照
|
|
1309
|
+
|
|
1310
|
+
麻省理工学院
|
|
1311
|
+
|
|
1312
|
+
## 学分
|
|
1313
|
+
|
|
1314
|
+
[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
|
+
|
|
1316
|
+
使用 [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 制作
|