Flutter MIDI控制器插件midi_controller的使用

Flutter MIDI控制器插件midi_controller的使用

midi_controller 是一个用于 Dart 的 MIDI 控制器包。它可以发送和接收 MIDI 消息,并连接到网络 MIDI 会话。

完整示例Demo

以下是一个完整的示例代码,展示了如何使用 midi_controller 插件来创建一个简单的 MIDI 设备列表视图。

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:midi_controller/midi_command.dart';

import 'controller.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  StreamSubscription<String>? _setupSubscription;
  final MidiCommand _midiCommand = MidiCommand();

  bool _virtualDeviceActivated = false;
  bool _iOSNetworkSessionEnabled = false;

  [@override](/user/override)
  void initState() {
    super.initState();

    _setupSubscription = _midiCommand.onMidiSetupChanged?.listen((data) async {
      if (kDebugMode) {
        print("setup changed $data");
      }
      setState(() {});
    });

    _updateNetworkSessionState();
  }

  [@override](/user/override)
  void dispose() {
    _setupSubscription?.cancel();
    super.dispose();
  }

  _updateNetworkSessionState() async {
    var nse = await _midiCommand.isNetworkSessionEnabled;
    if (nse != null) {
      setState(() {
        _iOSNetworkSessionEnabled = nse;
      });
    }
  }

  IconData _deviceIconForType(String type) {
    switch (type) {
      case "native":
        return Icons.devices;
      case "network":
        return Icons.language;
      case "BLE":
        return Icons.bluetooth;
      default:
        return Icons.device_unknown;
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
    ]);
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
            title: const Text('FlutterMidiCommand Example'),
            actions: <Widget>[
              Switch(
                  value: _iOSNetworkSessionEnabled,
                  onChanged: (newValue) {
                    _midiCommand.setNetworkSessionEnabled(newValue);
                    setState(() {
                      _iOSNetworkSessionEnabled = newValue;
                    });
                  }),
              Switch(
                  value: _virtualDeviceActivated,
                  onChanged: (newValue) {
                    setState(() {
                      _virtualDeviceActivated = newValue;
                    });
                    if (newValue) {
                      _midiCommand.addVirtualDevice(
                          name: "Flutter MIDI Command");
                    } else {
                      _midiCommand.removeVirtualDevice(
                          name: "Flutter MIDI Command");
                    }
                  })
            ]),
        bottomNavigationBar: Container(
          padding: const EdgeInsets.all(24.0),
          child: const Text(
            "Tap to connect/disconnect, long press to control.",
            textAlign: TextAlign.center,
          ),
        ),
        body: Center(
          child: FutureBuilder(
            future: _midiCommand.devices,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.hasData && snapshot.data != null) {
                var devices = snapshot.data as List<MidiDevice>;
                return ListView.builder(
                  itemCount: devices.length,
                  itemBuilder: (context, index) {
                    MidiDevice device = devices[index];

                    return ListTile(
                      title: Text(
                        device.name,
                        style: Theme.of(context).textTheme.headlineSmall,
                      ),
                      subtitle: Text(
                          "ins:${device.inputPorts.length} outs:${device.outputPorts.length}, ${device.id}, ${device.type}"),
                      leading: Icon(device.connected
                          ? Icons.radio_button_on
                          : Icons.radio_button_off),
                      trailing: Icon(_deviceIconForType(device.type)),
                      onLongPress: () {
                        Navigator.of(context)
                            .push(MaterialPageRoute<void>(
                          builder: (_) => ControllerPage(device),
                        ))
                            .then((value) {
                          setState(() {});
                        });
                      },
                      onTap: () {
                        if (device.connected) {
                          if (kDebugMode) {
                            print("disconnect");
                          }
                          _midiCommand.disconnectDevice(device);
                        } else {
                          if (kDebugMode) {
                            print("connect");
                          }
                          _midiCommand.connectToDevice(device).then((_) {
                            if (kDebugMode) {
                              print("device connected async");
                            }
                          }).catchError((err) {
                            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                                content: Text(
                                    "Error: ${(err as PlatformException?)?.message}")));
                          });
                        }
                      },
                    );
                  },
                );
              } else {
                return const CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }
}

更多关于Flutter MIDI控制器插件midi_controller的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter MIDI控制器插件midi_controller的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


midi_controller 是一个用于在 Flutter 应用中与 MIDI 设备进行交互的插件。它允许你监听 MIDI 设备的输入,例如键盘、鼓机或其他 MIDI 控制器,并在你的 Flutter 应用中处理这些事件。

以下是如何使用 midi_controller 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 midi_controller 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  midi_controller: ^0.0.1  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

2. 导入插件

在你的 Dart 文件中导入 midi_controller 插件:

import 'package:midi_controller/midi_controller.dart';

3. 初始化 MIDI 控制器

在使用 MIDI 控制器之前,你需要初始化它。通常,你可以在 initState 方法中进行初始化:

class MyMidiApp extends StatefulWidget {
  [@override](/user/override)
  _MyMidiAppState createState() => _MyMidiAppState();
}

class _MyMidiAppState extends State<MyMidiApp> {
  MidiController _midiController;

  [@override](/user/override)
  void initState() {
    super.initState();
    _midiController = MidiController();
    _midiController.init();
  }

  [@override](/user/override)
  void dispose() {
    _midiController.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MIDI Controller Example'),
      ),
      body: Center(
        child: Text('Press a MIDI key'),
      ),
    );
  }
}

4. 监听 MIDI 事件

你可以通过监听 MidiControlleronMidiMessage 流来接收 MIDI 事件:

[@override](/user/override)
void initState() {
  super.initState();
  _midiController = MidiController();
  _midiController.init();

  _midiController.onMidiMessage.listen((MidiMessage message) {
    print('MIDI Message: ${message.toString()}');
    // 你可以在这里处理 MIDI 消息
  });
}

MidiMessage 通常包含以下信息:

  • status: MIDI 状态字节(例如,音符开/关、控制变化等)。
  • data1: 第一个数据字节(例如,音符编号或控制编号)。
  • data2: 第二个数据字节(例如,音符力度或控制值)。

5. 处理 MIDI 事件

根据你的应用需求,你可以处理不同类型的 MIDI 事件。例如,如果你正在处理音符事件,你可以检查 status 字节来确定是音符开还是音符关事件,然后使用 data1data2 来获取音符编号和力度。

_midiController.onMidiMessage.listen((MidiMessage message) {
  if (message.status == 0x90) { // 音符开事件
    int note = message.data1;
    int velocity = message.data2;
    print('Note On: Note=$note, Velocity=$velocity');
  } else if (message.status == 0x80) { // 音符关事件
    int note = message.data1;
    print('Note Off: Note=$note');
  }
});

6. 发送 MIDI 消息(可选)

某些 MIDI 控制器插件还允许你发送 MIDI 消息到设备。你可以使用 MidiControllersendMidiMessage 方法来发送 MIDI 消息:

_midiController.sendMidiMessage(MidiMessage(status: 0x90, data1: 60, data2: 127));

7. 处理错误

在使用 MIDI 控制器时,可能会遇到错误(例如,设备未连接或初始化失败)。你可以通过监听 onError 流来处理这些错误:

_midiController.onError.listen((error) {
  print('MIDI Error: $error');
});

8. 释放资源

在应用关闭或不再需要 MIDI 控制器时,确保释放资源:

[@override](/user/override)
void dispose() {
  _midiController.dispose();
  super.dispose();
}
回到顶部