Flutter音频处理插件csounddart的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter音频处理插件csounddart的使用

csounddart 是一个 Dart 接口,用于与 Csound API 进行交互。该项目旨在为使用 Flutter 和 Csound 创建应用程序提供统一的 API,无论目标平台是什么(如 Linux、MacOS、Windows、Web、Android、iOS 等)。

目前该项目仍在开发中。已在 Linux、MacOS、Windows 和 Android 上进行了测试。当前 Web 版本尚未正常工作。

在桌面平台上,它假定 Csound 已安装在您的计算机上。在 Android 平台上,它会下载并安装 Csound 库到应用包中。

开始使用

import 'package:csounddart/csound.dart';

// 创建 Csound 对象在一个新的 Isolate 中(类似于 Dart 线程)。
// 由于当前实现,所有与 Csound 的事务都通过向隔离区发送消息来异步执行。
Csound _cs = Csound();

// 编译 Csound CSD 文本并获取返回值
int res = await _cs.compileCsdText(_myCsdText);

// 读取一段乐谱
int res = await _cs.readScore(_myScore);

// 从路径编译
int res = await _cs.compileCsd(_myCsd);

// 编译 Orchestra
int res = await _cs.compileOrc(_orchestra);

// 多线程表演
_cs.perform();

// 暂停或重新开始表演
_cs.pause(bool);

// 设置通道值
_cs.setControlChannel("channelName", (double)value);

// 设置回调。传递的方法将在每次 k-pass 时被调用。
_cs.setControlChannelCallback("channelName",
    (double v) {
        // 在这里进行回调操作
    }
);

// 音频回调
_cs.setAudioChannelCallback("audioChannelName",
    (ConcurrentBuffer buf) {
        for(int i = 0; i < buf.length; i++) {
            double value = buf.get(i);
        }
    }
);

// 获取控制通道值
double channel = _cs.getControlChannel("channemName");

// 获取 Csound 值
int ksmps = await _cs.getKsmps();
int nchnls = await _cs.getNchnls();
int sr = await _cs.getSr();
int dbfs = await _cs.get0dbfs();

// 停止 Csound,清除所有回调内存。
_cs.stop();

// 如果正在表演,则停止表演,并销毁 Csound 实例,所有回调内存和杀死隔离区。
// 重新开始表演涉及通过调用构造函数 `Csound()` 重新创建对象。
_cs.destroy();

// 重置 Csound
_cs.reset();

待办事项

  • Android : 音频通道回调似乎已损坏。
  • 统一 ConcurrentBuffer 以便用户可以更方便地使用。

完整示例代码

示例代码

import 'dart:io';

import 'package:csounddart/csound.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:csounddart/csounddart.dart';
import 'package:oscilloscope/oscilloscope.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

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

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';

  void requestPermission() async {
    if (Platform.isAndroid) {
      Map<Permission, PermissionStatus> lst = await [Permission.storage,
        Permission.microphone, Permission.sensors].request();
    }
  }

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

  late Csound _cs;

  static const String _csd = """
<CsoundSynthesizer>
<CsOptions>
-odac
;-iadc
;-B 1024
;-b 256
</CsOptions>
; ==============================================
<CsInstruments>

sr	=	44100
ksmps	=	32
nchnls	=	2
nchnls_i = 1
0dbfs	=	1

opcode mtofi,i,i
        imid xin
        iout = 440 * exp(0.0577622645 * (imid - 69))
        xout iout
endop

instr 1	
        inote init p4
        ivel init p5
        ifq = mtofi(inote)
        kfq = k(ifq)
        iT = 1000 / ifq

        aPulse = linseg:a(1, iT/1000, 0)
                aPulse = (aPulse + (noise:a(1,0.5) * aPulse)) / 2

                aPulse = aPulse *  pow(2, ((1-((ivel-1)/126)) * -4 ))
                iff = ivel * 100 + 20
                aPulse = butterlp(aPulse, iff)
  

        ;resonr allows to  clear internal space
                alow, ahigh, ao svfilter aPulse, kfq, 500
  
                //ao = butterbp(aPulse, kfq, 1500)
                amo = ao * 15
                amo -= 3.25
 
                amo = butterlp(amo, 150)
        //ao = lowpass2:a(amo, 150, 50) 
                amo = distort1( amo, 1, 1, 0, 0)
                ; Two parallel lines 
                ;one raising, removing gain, and DC
                a1 = (pow(amo, 2)) * (-0.08)
                a1 = dcblock(a1)

  
                        
                a2 = butterhp(amo, 250) * 0.25
  
                as = limit( ((a1 * 0.0001) + a2 + ao) * 0.7  , -1, 1)
                as = dcblock(as)


        outs as, as


endin

instr 2 
  ao = oscili(0.3, linseg:k(100, p3, 400))
  
  av = vco2(0.3, linseg:k(1, p3, 10))
  chnset(av, "vco")
  ao4 = oscili(1.0, linseg:k(1000, p3, 10))
  chnset(ao4, "sine")
  outs ao,ao
  
endin

instr 3
  ;kfq init 200
  kfq = chnget:k("freq")
  printk 1, kfq
  ao = vco2(0.15, kfq) * 0.1
  chnset(ao, "audioChannel")
  ko = k(ao)
  chnset(ko, "controlChannel")
  
  ;ain = inch(1)
  ;aVoice = ain * 0.3
  ;aVoice = delay(ain, 1) * 0.2
  ,aVoice = comb(aVoice, 3.5, 0.1) * 0.1 + (ain * 0.3)
 ; outs aVoice, aVoice
  
 outs ao,ao
endin


instr 4 
  ao = oscili(0.15, 400)
   outs ao,ao
endin
</CsInstruments>
; ==============================================
<CsScore>
i 3 0 100
</CsScore>
</CsoundSynthesizer>
""";

  // 平台消息是异步的,因此我们初始化在一个异步方法中。
  Future<void> initPlatformState() async {
    print("Init Platform State");
    String platformVersion;
    // 平台消息可能会失败,所以我们使用 try/catch PlatformException。
    // 我们还处理消息可能返回 null 的情况。
    try {
      platformVersion =
          await Csounddart.platformVersion ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // 如果在异步平台消息还在飞行时小部件从树中移除,我们希望丢弃回复而不是调用
    // setState 来更新我们的不存在的外观。
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  double _sliderFreq = 200;
  List<double> _dataSet = [];

  bool _pause = false;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Csound Dart 示例'),
        ),
        body: Center(
          child: Container(
            child: SingleChildScrollView(
              child: Column(
                children: [
                  Text('运行在: $_platformVersion\n'),
                  Container(
                    height: 3,
                  ),
                  ElevatedButton(
                      onPressed: () async {
                        _cs.reset();
                      },
                      child: Text("重置")),
                  Container(
                    height: 3,
                  ),
                  ElevatedButton(
                      onPressed: () async {
                        _cs = Csound(onReady: () {
                          print("Csound Compile");
                          // print(_csd);
                          int res = _cs.compileCsdTextSync(_csd);
                          print("compile res $res");
                          // int ksmps = await _cs.getKsmps();
                          // print("ksmps = $ksmps");
                          if (res != 0) return;
                          _cs.perform();
                          _cs.setControlChannel("freq", 200.0);

                          /*
                        _cs.setControlChannelCallback("controlChannel", (double val) {
                          if (_dataSet.length > 1024) _dataSet.clear();
                         _dataSet.add(val);
                        });
                        */
                          /*
                          _cs.setAudioChannelCallback("audioChannel", (data) async {
                            if (_dataSet.length > 1024) _dataSet.clear();
                            for (int i = 0; i < data.length; i++) {
                              _dataSet.add(data.get(i));
                            }
                          });
                           */
                        },
                        onStop: () {
                          print("csound stopped callback");
                        }
                        );
                      },
                      child: Text("播放")),
                  Container(
                    height: 3,
                  ),
                  ElevatedButton(
                      onPressed: () {
                        _cs.stop();
                        print("想要停止");
                      },
                      child: Text("停止")),
                  Container(height: 5),
                  ElevatedButton(
                      onPressed: () async {
                        _cs.destroy(onDestroyed: () {
                          print("Csound Destroy callback");
                        });
                      },
                      child: Text("销毁")),
                  Container(height: 5),
                  ElevatedButton(
                      onPressed: () async {
                        _pause = !_pause;
                        _cs.pause(_pause);
                      },
                      child: Text("暂停")),
                  Container(height: 5),
                  Slider(
                    onChanged: (double v) {
                      setState(() {
                        _sliderFreq = v;
                      });
                      _cs.setControlChannel("freq", _sliderFreq);
                    },
                    value: _sliderFreq,
                    min: 100,
                    max: 500,
                  ),
                  Container(
                    width: 400,
                    height: 150,
                    child: Oscilloscope(
                      showYAxis: true,
                      yAxisColor: Colors.orange,
                      margin: EdgeInsets.all(20.0),
                      strokeWidth: 1.0,
                      backgroundColor: Colors.black,
                      traceColor: Colors.green,
                      yAxisMax: 1.0,
                      yAxisMin: -1.0,
                      dataSet: _dataSet,
                    ),
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

更多关于Flutter音频处理插件csounddart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音频处理插件csounddart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


csounddart 是一个用于在 Flutter 中处理音频的插件,它基于 Csound 音频合成系统。Csound 是一个强大的音频合成和处理工具,支持复杂的音频算法和实时音频处理。csounddart 插件允许你在 Flutter 应用中使用 Csound 的功能。

以下是如何在 Flutter 项目中使用 csounddart 插件的基本步骤:

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  csounddart: ^0.0.1  # 请使用最新版本

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

2. 初始化 Csound

在你的 Dart 代码中,首先需要初始化 Csound 实例:

import 'package:csounddart/csounddart.dart';

void main() async {
  Csound csound = Csound();
  await csound.initialize();
}

3. 编译并运行 Csound 代码

你可以通过 compileOrc 方法编译 Csound 的 .orc 文件或直接传递 Csound 代码字符串。然后使用 readScore 方法加载 .sco 文件或传递 Csound 的乐谱字符串。

void main() async {
  Csound csound = Csound();
  await csound.initialize();

  // 编译 Csound 代码
  String orcCode = '''
    instr 1
      a1 oscil 10000, 440, 1
      out a1
    endin
  ''';
  await csound.compileOrc(orcCode);

  // 加载乐谱
  String score = "i1 0 2"; // 在 0 秒开始,持续 2 秒
  await csound.readScore(score);

  // 开始音频处理
  await csound.start();
}

4. 控制音频

你可以通过 csound 实例控制音频的播放、暂停和停止:

// 暂停音频
await csound.pause();

// 恢复音频
await csound.resume();

// 停止音频
await csound.stop();

5. 清理资源

在应用结束时,记得清理 Csound 实例以释放资源:

await csound.cleanup();

6. 处理实时音频输入和输出

csounddart 也支持实时音频输入和输出。你可以通过配置 Csound 的音频设备来实现:

await csound.setOption("-odac");  // 使用默认音频输出设备
await csound.setOption("-iadc");  // 使用默认音频输入设备

7. 处理 MIDI 输入

如果你需要处理 MIDI 输入,可以通过以下方式配置:

await csound.setOption("-M0");  // 使用默认 MIDI 输入设备

8. 处理音频回调

你可以通过 csounddart 提供的回调函数来处理音频数据,例如实时音频处理或音频分析。

csound.setAudioCallback((List<double> buffer) {
  // 处理音频数据
});

9. 调试和日志

你可以启用 Csound 的调试日志来帮助调试音频处理代码:

await csound.setOption("-d");  // 启用调试日志
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!