如何使用流体合成器将单个 midi 通道导出为 wav?

Posted

技术标签:

【中文标题】如何使用流体合成器将单个 midi 通道导出为 wav?【英文标题】:How to export a single midi channel to wav with fluidsynth? 【发布时间】:2020-10-23 16:12:40 【问题描述】:

我对音乐技术很陌生,所以请耐心等待。

一个 MIDI 文件中有 16 个通道。我正在尝试仅将 1 个频道从 midi 文件转换为 wav。

现在是这样的:

extern "C" JNIEXPORT void JNICALL Java_com_test_MainActivity_convertMidiToWav(JNIEnv* env, jobject, jstring jSoundfontPath, jstring jOutputWavPath, jstring jMidiPath, jint jChannel) 
    fluid_settings_t* settings;
    fluid_synth_t* synth;
    fluid_player_t* player;
    fluid_file_renderer_t* renderer;

    settings = new_fluid_settings();

    // specify the file to store the audio to
    const char* outputWavPath = env->GetStringUTFChars(jOutputWavPath, nullptr);
    fluid_settings_setstr(settings, "audio.file.name", outputWavPath);

    // since this is a non-realtime scenario, there is no need to pin the sample data
    fluid_settings_setint(settings, "synth.lock-memory", 0);

    synth = new_fluid_synth(settings);

    // set basic channel
    fluid_synth_reset_basic_channel(synth, -1);
    fluid_synth_set_basic_channel(synth, jChannel, FLUID_CHANNEL_MODE_OMNION_MONO, 1);

    // Load sample soundfont
    const char* soundfontPath = env->GetStringUTFChars(jSoundfontPath, nullptr);
    fluid_synth_sfload(synth, soundfontPath, 1);

    const char* midiPath = env->GetStringUTFChars(jMidiPath, nullptr);
    player = new_fluid_player(synth);
    fluid_player_add(player, midiPath);
    fluid_player_play(player);

    renderer = new_fluid_file_renderer (synth);
    while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING)
    
        if (fluid_file_renderer_process_block(renderer) != FLUID_OK)
        
            break;
        
    

    // just for sure: stop the playback explicitly and wait until finished
    fluid_player_stop(player);
    fluid_player_join(player);

    delete_fluid_file_renderer(renderer);
    delete_fluid_player(player);
    delete_fluid_synth(synth);
    delete_fluid_settings(settings);

注意这两行:

fluid_synth_reset_basic_channel(synth, -1);
fluid_synth_set_basic_channel(synth, jChannel, FLUID_CHANNEL_MODE_OMNION_MONO, 1);

jChannel 是 MIDI 通道号(1-16)。我不确定我是否做得对。

有人能告诉我如何将 1 个 midi 通道转换为 wav 吗?上面的代码是转换单通道吗?

提前致谢

【问题讨论】:

那不是C代码,请不要这样标记。另请阅读您应用的标签的说明。 【参考方案1】:

为了后代,这里是如何在 android 上将单个 midi 通道转换为 wav:

#include <jni.h>
#include <string>
#include <fluidsynth.h>
#include <unistd.h>

// default channel to export
int channelToExport = 0;

int handle_midi_event(void* data, fluid_midi_event_t* event)

    // successfully handles midi event from player to synthesizer only if midi event is in the exported channel
    return fluid_midi_event_get_channel(event) == channelToExport ? fluid_synth_handle_midi_event(data, event) : FLUID_FAILED;


extern "C" JNIEXPORT void JNICALL Java_com_ryzhak_midi2wavconverter_MainActivity_convertMidiToWav(JNIEnv* env, jobject, jstring jSoundfontPath, jstring jOutputWavPath, jstring jMidiPath, jint jChannel) 
    fluid_settings_t* settings;
    fluid_synth_t* synth;
    fluid_player_t* player;
    fluid_file_renderer_t* renderer;

    settings = new_fluid_settings();

    // specify the file to store the audio to
    const char* outputWavPath = env->GetStringUTFChars(jOutputWavPath, nullptr);
    fluid_settings_setstr(settings, "audio.file.name", outputWavPath);

    // since this is a non-realtime scenario, there is no need to pin the sample data
    fluid_settings_setint(settings, "synth.lock-memory", 0);

    synth = new_fluid_synth(settings);

    // Load sample soundfont
    const char* soundfontPath = env->GetStringUTFChars(jSoundfontPath, nullptr);
    fluid_synth_sfload(synth, soundfontPath, 1);

    // create a new player
    const char* midiPath = env->GetStringUTFChars(jMidiPath, nullptr);
    player = new_fluid_player(synth);
    fluid_player_add(player, midiPath);
    fluid_player_play(player);

    // set basic channel to export
    channelToExport = jChannel;
    fluid_player_set_playback_callback(player, handle_midi_event , synth);

    // start conversion
    renderer = new_fluid_file_renderer (synth);
    while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING)
    
        if (fluid_file_renderer_process_block(renderer) != FLUID_OK)
        
            break;
        
    

    // just for sure: stop the playback explicitly and wait until finished
    fluid_player_stop(player);
    fluid_player_join(player);

    delete_fluid_file_renderer(renderer);
    delete_fluid_player(player);
    delete_fluid_synth(synth);
    delete_fluid_settings(settings);

【讨论】:

以上是关于如何使用流体合成器将单个 midi 通道导出为 wav?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用流体合成器从 C# 中的声音字体生成声音

MIDI 通道轨道相关

播放(不是录制/导出)多个 MIDI 轨道

PyGame 更改预设声音字体

使用软件合成器将 MIDI 文件转换为原始音频

如何将midi从java程序发送到OSX上的IAC总线