问题描述
我对音乐技术非常陌生,请多多包涵。
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,1);
jChannel
是Midi通道号(1-16)。我不确定自己是否做对了。
有人可以告诉我如何将1个Midi通道准确转换为wav吗?上面的代码会转换单个频道吗?
预先感谢
解决方法
对于后代,以下是在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);
}