SKKbySSK / coast_audio

Real-Time audio processing library written in Dart.
MIT License
97 stars 12 forks source link

Play asset wav file #11

Closed goranesine closed 1 year ago

goranesine commented 1 year ago

Hello, can you give us an example of how to play asset file in Flutter framework?

goranesine commented 1 year ago

I manage to play the asset audio file but just one time. When I first-time call outputNode.device.start() the sound is playing. On the second call - nothing ? Here is the code:

final decoder = MabAudioDecoder( dataSource: AudioFileDataSource(file: accentFile, mode: FileMode.read), outputFormat: format); final wavNode = DecoderNode(decoder: decoder); graphNode.connect(wavNode.outputBus, outputNode.inputBus); graphNode.connectEndpoint(outputNode.outputBus); outputTask.start();

outputNode.device.start()

potatosalad775 commented 1 year ago

I believe you cannot start outputNode.device again since it's already running.

Can you be more specific about what are you trying to achieve?

goranesine commented 1 year ago

I just want to play one sample from the asset multiple time. On the press of a button, I call outputNode.device.start(); The sample played nice the first time. Then I call outputNode.device.stop(); When I call outputNode.device.start(); again nothing happens. After some testing, I find that outputNode.device.availableReadFrames are empty after the first call.

SKKbySSK commented 1 year ago

Sorry for my late response. Can you provide your device info (OS, version, model name) and minimal reproducible code?

I find that outputNode.device.availableReadFrames are empty after the first call.

It seems that the device's internal audio buffer is not filled out correctly. Have you restart the outputTask when the second press of a button?

goranesine commented 1 year ago

`import 'dart:io';

import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_coast_audio_miniaudio/flutter_coast_audio_miniaudio.dart'; import 'package:path_provider/path_provider.dart';

void main() { MabLibrary.initialize(); MabDeviceContext.enableSharedInstance(backends: [ MabBackend.aaudio, MabBackend.coreAudio, ]); runApp(const MyApp()); }

class MyApp extends StatefulWidget { const MyApp({super.key});

@override State createState() => _MyAppState(); }

class _MyAppState extends State { final format = const AudioFormat(sampleRate: 48000, channels: 2); late final MabAudioPlayer audioPlayer; late final MabAudioDecoder decoder; late final DecoderNode wavNode; late AudioFileDataSource dataSource; late final outputNode = MabPlaybackDeviceNode( device: MabPlaybackDevice( context: MabDeviceContext.sharedInstance, format: format, bufferFrameSize: 4096, ), ); final graphNode = GraphNode();

late final outputTask = AudioTask( clock: AudioIntervalClock(const Duration(milliseconds: 16)), readFrameSize: 4096, endpoint: graphNode.outputBus, format: format, );

@override void initState() { super.initState(); initAccentFile(); }

void initAccentFile() async { await copyAssetToDir("accent.wav").then((value) { dataSource = AudioFileDataSource(file: value, mode: FileMode.read); decoder = MabAudioDecoder(dataSource: dataSource, outputFormat: format); wavNode = DecoderNode(decoder: decoder);

  graphNode.connect(wavNode.outputBus, outputNode.inputBus);
  graphNode.connectEndpoint(outputNode.outputBus);
  outputTask.start();
});

}

Future copyAssetToDir(String path) async { Directory tempDir = await getTemporaryDirectory(); String tempPath = tempDir.path; var filePath = "$tempPath/$path"; var file = File(filePath); if (file.existsSync()) { return file; } else { final byteData = await rootBundle.load('assets/$path'); final buffer = byteData.buffer; await file.create(recursive: true); return file.writeAsBytes( buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes)); } }

@override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Plugin example app'), ), body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () => outputNode.device.start(), child: const Text('Start'), ), const SizedBox(width: 12), ElevatedButton( onPressed: () => outputNode.device.stop(), child: const Text('Stop'), ),

        ],
      ),
    ),
  ),
);

} }

Is this a wrong approach ?`

SKKbySSK commented 1 year ago

You need to set decoder's cursor to 0 when you press the start button.

decoder.cursorInFrames = 0;
outputNode.device.start();
goranesine commented 1 year ago

The solution works, thanks.