soundfont_kit 1.0.2 copy "soundfont_kit: ^1.0.2" to clipboard
soundfont_kit: ^1.0.2 copied to clipboard

A high-performance SoundFont (SF2, SF3, SFZ) reader and playback engine for Flutter.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_soloud/flutter_soloud.dart';
import 'package:soundfont_kit/soundfont_kit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const SimpleSoundFontApp());
}

class SimpleSoundFontApp extends StatelessWidget {
  const SimpleSoundFontApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: SimpleSoundFontHomePage());
  }
}

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

  @override
  State<SimpleSoundFontHomePage> createState() =>
      _SimpleSoundFontHomePageState();
}

class _SimpleSoundFontHomePageState extends State<SimpleSoundFontHomePage> {
  final List<String> _bundledAssets = [
    'assets/Celesta_minimal.sf3',
    'assets/SFX_StarWars_ships.SF2.zip',
    'assets/SFX_StarWars_weapons.SF2',
    'assets/TerribleDanger.sf2',
    'assets/RatAttack.sf2',
    'assets/1115_PassingJet.sf2.zip',
    'assets/Pac-Man-W2_.sf2.zip',
  ];

  late String _selectedAsset;
  bool _isLoading = true;
  String? _errorMessage;

  SoundFontFile? _soundFont;
  SoundFontPlayer? _player;
  Preset? _selectedPreset;

  final SoundFontGlobalFilters _filters = const SoundFontGlobalFilters();

  @override
  void initState() {
    super.initState();
    _selectedAsset = _bundledAssets.first;
    _initEngineAndLoad(_selectedAsset);
  }

  @override
  void dispose() {
    _player?.dispose();
    super.dispose();
  }

  Future<void> _initEngineAndLoad(String assetPath) async {
    setState(() {
      _isLoading = true;
      _errorMessage = null;
    });

    try {
      if (!SoLoud.instance.isInitialized) {
        await SoLoud.instance.init();
      }

      final byteData = await rootBundle.load(assetPath);
      final bytes = byteData.buffer.asUint8List(
        byteData.offsetInBytes,
        byteData.lengthInBytes,
      );

      final sf = await SoundFontFile.fromBytes(bytes);
      final player = sf.createPlayer();

      setState(() {
        _soundFont = sf;
        _player = player;
        _selectedPreset = sf.presets.isNotEmpty ? sf.presets.first : null;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _errorMessage = 'Error loading SoundFont: $e';
        _isLoading = false;
      });
    }
  }

  Future<void> _playNote(int midiKey) async {
    final player = _player;
    final preset = _selectedPreset;
    if (player == null || preset == null) return;
    try {
      await player.playPreset(preset, key: midiKey, velocity: 100);
    } catch (e) {
      debugPrint('Playback error: $e');
    }
  }

  Future<void> _playChord(List<int> midiKeys) async {
    final player = _player;
    final preset = _selectedPreset;
    if (player == null || preset == null) return;
    try {
      for (final key in midiKeys) {
        await player.playPreset(preset, key: key, velocity: 95);
      }
    } catch (e) {
      debugPrint('Chord playback error: $e');
    }
  }

  Future<void> _stopAll() async {
    await _player?.stopMixerOutput();
  }

  @override
  Widget build(BuildContext context) {
    final sf = _soundFont;

    return Scaffold(
      appBar: AppBar(title: const Text('SoundFont Reader Simple Example')),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : SingleChildScrollView(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    'Run lib/main_full.dart for the full interactive demonstration.',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 16),
                  if (_errorMessage != null) ...[
                    Text(
                      _errorMessage!,
                      style: const TextStyle(color: Colors.red),
                    ),
                    const SizedBox(height: 16),
                  ],
                  if (sf != null) ...[
                    const Text('Select SoundFont:'),
                    DropdownButton<String>(
                      value: _selectedAsset,
                      isExpanded: true,
                      items: _bundledAssets.map((asset) {
                        return DropdownMenuItem(
                          value: asset,
                          child: Text(asset),
                        );
                      }).toList(),
                      onChanged: (newAsset) {
                        if (newAsset != null && newAsset != _selectedAsset) {
                          setState(() => _selectedAsset = newAsset);
                          _initEngineAndLoad(newAsset);
                        }
                      },
                    ),
                    const SizedBox(height: 16),
                    const Text('Audition Notes:'),
                    const SizedBox(height: 8),
                    Wrap(
                      spacing: 8,
                      runSpacing: 8,
                      children: [
                        ElevatedButton(
                          onPressed: () => _playNote(60),
                          child: const Text('Play C4'),
                        ),
                        ElevatedButton(
                          onPressed: () => _playNote(64),
                          child: const Text('Play E4'),
                        ),
                        ElevatedButton(
                          onPressed: () => _playNote(67),
                          child: const Text('Play G4'),
                        ),
                        ElevatedButton(
                          onPressed: () => _playNote(79),
                          child: const Text('Play G5'),
                        ),
                        ElevatedButton(
                          onPressed: () => _playChord([60, 64, 67, 79]),
                          child: const Text('Play Chord'),
                        ),
                        ElevatedButton(
                          onPressed: _stopAll,
                          child: const Text('Stop All'),
                        ),
                      ],
                    ),
                    const SizedBox(height: 24),
                    const Text('Filters:'),
                    const SizedBox(height: 8),
                    Wrap(
                      spacing: 16,
                      runSpacing: 8,
                      children: SoundFontFilterType.values.map((type) {
                        final active = _filters.isActive(type);
                        return Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Checkbox(
                              value: active,
                              onChanged: (checked) {
                                setState(() {
                                  _filters.toggle(type, checked ?? false);
                                });
                              },
                            ),
                            Text(type.label),
                          ],
                        );
                      }).toList(),
                    ),
                  ],
                ],
              ),
            ),
    );
  }
}
1
likes
160
points
121
downloads
screenshot

Documentation

API reference

Publisher

verified publishermarcobavagnoli.com

Weekly Downloads

A high-performance SoundFont (SF2, SF3, SFZ) reader and playback engine for Flutter.

Repository (GitHub)
View/report issues

Topics

#soundfont #sf2 #sf3 #sfz #midi

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

archive, flutter, flutter_soloud, http, path

More

Packages that depend on soundfont_kit