How long will the sound play?

99 Views Asked by At

I am building an app that uses DartMeltySoundFont as a synthesizer and raw_sounds to play the sounds.

I init the synthesizer like this:

Synthesizer synthesizer = Synthesizer.loadByteData(
        bytes,
        SynthesizerSettings(
          sampleRate: 44100,
          blockSize: 980,
          maximumPolyphony: 64,
          enableReverbAndChorus: false,
        ));

Then I add a block with some MIDI instructions and the sound plays.
But I don't know how long it plays.
How can I calculate how long it plays in seconds given the variables sampleRate, blockSize and amount of blocks added?

Full example app:

import 'dart:typed_data'; // for Uint8List
import 'package:flutter/material.dart';
import 'package:raw_sound/raw_sound_player.dart';
import 'package:dart_melty_soundfont/dart_melty_soundfont.dart';
import 'package:flutter/services.dart' show rootBundle;

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // Player instance to play raw PCM (16-bit integer) audio data
  final _playerPCMF32 = RawSoundPlayer();
  bool _playing = false;

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

    //  release any initialized player instances
    _playerPCMF32
        .initialize(
      sampleRate: 44100,
      pcmType: RawSoundPCMType.PCMF32,
    )
        .then((value) {
      setState(() {
        // Trigger rebuild to update UI
      });
    });
  }

  @override
  void dispose() {
    // Finally release any initialized player instances
    _playerPCMF32.release();
    super.dispose();
  }

  Widget build(BuildContext context) {
    debugPrint('_playerPCMF32 is inited? ${_playerPCMF32.isInited}');

    if (!_playerPCMF32.isInited) {
      return Container();
    }

    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.grey,
      ),
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('Raw Sound Plugin Example App'),
        ),
        body: Column(
          children: [
            Card(
              child: Row(
                children: [
                  IconButton(
                    icon: Icon(_playerPCMF32.isPlaying ? Icons.stop : Icons.play_arrow),
                    onPressed: () {
                      _playerPCMF32.isPlaying ? _pausePCMF32() : _playPCMF32();
                    },
                  ),
                  Text('Test PCMF32'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _playPCMF32() async {
    if (_playerPCMF32.isPlaying) {
      return;
    }
    await _playerPCMF32.play();
    setState(() {
      _playing = true;
    });
    // Continuously feed the player until the playback is paused/stopped
    //final dataBlock = _genPCMF32DataBlock(nPeriods: 20);
    final dataBlock = await _getMoreSound();
    print('new sound read');
    while (_playerPCMF32.isPlaying) {
      await _playerPCMF32.feed(dataBlock);
    }
  }

  Future<void> _pausePCMF32() async {
    await _playerPCMF32.stop();
    setState(() {
      _playing = false;
    });
  }

  _getMoreSound() async {
    int sampleRate = 44100;
    int blockSize = 980;
    int blockCount = sampleRate ~/ blockSize; // =45

    // Create the synthesizer.
    ByteData bytes = await rootBundle.load('assets/Mace-Drums.sf2');

    Synthesizer synthesizer = Synthesizer.loadByteData(
        bytes,
        SynthesizerSettings(
          sampleRate: sampleRate,
          blockSize: blockSize,
          maximumPolyphony: 64,
          enableReverbAndChorus: false,
        ));

    // Define the melody.
    // A single row indicates the start timing, end timing, and pitch.
    var data = [
      //[0, 15, 0],
      [15, 30, 36],
      [30, 45, 36],
    ];

    // The output buffer.
    List<double> left = List<double>.filled(sampleRate, 0);
    List<double> right = List<double>.filled(sampleRate, 0);
    final dataBlock = <int>[];

    for (var t = 0; t < blockCount; t++) {
      // Process the melody.
      for (var row in data) {
        if (t == row[0]) synthesizer.noteOn(channel: 9, key: row[2], velocity: 100);
        if (t == row[1]) synthesizer.noteOff(channel: 9, key: row[2]);
      }

      // Render the block.
      int start = blockSize * t;
      var blockLeft = left.sublist(start, start + blockSize);
      var blockRight = right.sublist(start, start + blockSize);
      synthesizer.render(blockLeft, blockRight);

      final dataBlockPerPeriod = ByteData(blockLeft.length << 2 /* one float32 is made of 4 bytes */);
      for (int i = 0; i < blockLeft.length; i++) {
        // amplitude is in the range of -1.0 to 1.0
        final value = blockLeft[i];
        dataBlockPerPeriod.setFloat32(i << 2, value, Endian.host /* native endianness */);
      }
      // Repeat dataBlockPerPeriod nPeriods times

      dataBlock.addAll(dataBlockPerPeriod.buffer.asUint8List());
      debugPrint('dataBlock nBytes: ${dataBlock.length}');
    }

    return Uint8List.fromList(dataBlock);
  }
}



0

There are 0 best solutions below