Skip to content

Commit

Permalink
migrate to flutter 3 and add velocity parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
tplkn committed May 12, 2022
1 parent c71a7e7 commit 15c7105
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.history
.svn/
.vscode
.fvm

# IntelliJ related
*.iml
Expand Down
11 changes: 8 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
## 0.1.0
## 0.2.0

* Initial release.
* Flutter 3.0.0 support
* velocity parameter for playing notes

## 0.1.1

* Fix android ndk targets
* Fix android ndk targets

## 0.1.0

* Initial release.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# midi_player

A Flutter Plugin to Play midi on iOS and Android uses SoundFont (.sf2) files.
A Flutter plugin to play midi on iOS and Android uses SoundFont (.sf2) files.

## Important notes

Expand All @@ -18,13 +18,15 @@ assets:
- Load the sound

``` ruby
_midiPlayer.load('assets/FlorestanPiano.sf2');
_midiPlayer.load('assets/Piano.sf2');
```

- Play midi note

``` ruby
_midiPlayer.playNote(60);
_midiPlayer.playNote(note: 60);
or
_midiPlayer.playNote(note: 62, velocity: 0.5);
```

- Dispose after usage
Expand Down
4 changes: 2 additions & 2 deletions android/src/main/cpp/native-lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ extern "C" JNIEXPORT void JNICALL Java_me_teplyakov_midiplayer_MidiPlayerPlugin_
fluid_synth_sfload(synthSingleton, soundfontPath, 1);
}

extern "C" JNIEXPORT void JNICALL Java_me_teplyakov_midiplayer_MidiPlayerPlugin_fluidsynthPlayNote(JNIEnv* env, jobject, jint note) {
fluid_synth_noteon(synthSingleton, 0, note, 127);
extern "C" JNIEXPORT void JNICALL Java_me_teplyakov_midiplayer_MidiPlayerPlugin_fluidsynthPlayNote(JNIEnv* env, jobject, jint note, jint velocity) {
fluid_synth_noteon(synthSingleton, 0, note, velocity);
}

extern "C" JNIEXPORT void JNICALL Java_me_teplyakov_midiplayer_MidiPlayerPlugin_fluidsynthUnload(JNIEnv* env, jobject) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class MidiPlayerPlugin: FlutterPlugin, MethodCallHandler {
private external fun fluidsynthInit(path: String)

@JvmStatic
private external fun fluidsynthPlayNote(note: Int)
private external fun fluidsynthPlayNote(note: Int, velocity: Int)

@JvmStatic
private external fun fluidsynthUnload()
Expand All @@ -38,10 +38,17 @@ class MidiPlayerPlugin: FlutterPlugin, MethodCallHandler {

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "load") {
val path = call.arguments() as String
fluidsynthInit(path)
val path = call.arguments() as? String
if (path != null) {
fluidsynthInit(path)
}
} else if (call.method == "play_note") {
fluidsynthPlayNote(call.arguments() as Int)
val args = call.arguments() as? Map<String, Any?>
val note = args?.get("note") as? Int
val velocity = args?.get("velocity") as? Int
if (note != null && velocity != null) {
fluidsynthPlayNote(note, velocity)
}
} else if (call.method == "dispose") {
fluidsynthUnload()
} else {
Expand Down
2 changes: 2 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
8 changes: 7 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ class _MyAppState extends State<MyApp> {
),
ElevatedButton(
onPressed: () {
_midiPlayer.playNote(60);
_midiPlayer.playNote(note: 60);
},
child: const Text('Play'),
),
ElevatedButton(
onPressed: () {
_midiPlayer.playNote(note: 62, velocity: 0.5);
},
child: const Text('Play'),
),
Expand Down
8 changes: 5 additions & 3 deletions ios/Classes/AudioUnitMIDISynth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ class AudioUnitMIDISynth: NSObject {
componentType: OSType(kAudioUnitType_Output),
componentSubType: OSType(kAudioUnitSubType_RemoteIO),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0, componentFlagsMask: 0)
componentFlags: 0,
componentFlagsMask: 0
)
let status = AUGraphAddNode(self.processingGraph!, &cd, &ioNode)
AudioUtils.CheckError(status)
}
Expand Down Expand Up @@ -204,7 +206,7 @@ class AudioUnitMIDISynth: NSObject {
}

/// Send a note on message using patch2 on channel 0
func playPitch(midi: Int) {
func playPitch(midi: Int, velocity: Int) {

let channel = UInt32(0)
let noteCommand = UInt32(0x90 | channel)
Expand All @@ -213,7 +215,7 @@ class AudioUnitMIDISynth: NSObject {

status = MusicDeviceMIDIEvent(self.midisynthUnit!, pcCommand, patch2, 0, 0)
AudioUtils.CheckError(status)
status = MusicDeviceMIDIEvent(self.midisynthUnit!, noteCommand, UInt32(midi), 64, 0)
status = MusicDeviceMIDIEvent(self.midisynthUnit!, noteCommand, UInt32(midi), UInt32(velocity), 0)
AudioUtils.CheckError(status)
}

Expand Down
11 changes: 7 additions & 4 deletions ios/Classes/SwiftMidiPlayerPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ public class SwiftMidiPlayerPlugin: NSObject, FlutterPlugin {
let message = "Prepared Sound Font"
result(message)
case "play_note":
let midi = call.arguments as? Int
au.playPitch(midi: midi ?? 60)
let message = "Playing: \(String(describing: midi!))"
result(message)
if let args = call.arguments as? Dictionary<String, Any>,
let note = args["note"] as? Int,
let velocity = args["velocity"] as? Int {
au.playPitch(midi: note, velocity: velocity)
let message = "Playing: \(String(describing: note))"
result(message)
}
case "dispose":
result("done")
default:
Expand Down
19 changes: 17 additions & 2 deletions lib/midi_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:path_provider/path_provider.dart';
class MidiPlayer {
static const MethodChannel _channel = MethodChannel('midi_player');

/// Init engine with specific .sf2 file
Future<void> load(String path) async {
const tmpPath = "temporay_font.sf2";

Expand All @@ -22,10 +23,24 @@ class MidiPlayer {
return _channel.invokeMethod('load', file.path);
}

Future<void> playNote(int note) {
return _channel.invokeMethod('play_note', note);
/// Play the note wirh specific velocity.
/// velocity should be between 0.0 and 1.0
/// if velocity is omitted maximum value is used
Future<void> playNote({
required int note,
double? velocity,
}) {
final normalizedVelocity = 127.0 * (velocity ?? 1.0);
return _channel.invokeMethod(
'play_note',
{
'note': note,
'velocity': normalizedVelocity.toInt(),
},
);
}

/// Dispose engine
Future<void> dispose() {
return _channel.invokeMethod('dispose');
}
Expand Down
8 changes: 4 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: midi_player
description: Flutter plugin for playing midi files
version: 0.1.1
description: A Flutter plugin to play midi on iOS and Android uses SoundFont (.sf2) files
version: 0.2.0
homepage: https://github.com/tplkn/midi_player

environment:
sdk: ">=2.16.1 <3.0.0"
flutter: ">=2.5.0"
sdk: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"

dependencies:
flutter:
Expand Down

0 comments on commit 15c7105

Please sign in to comment.