レイテンシを修正していました。当方のAndroidManifest.xmlを確認しましたところ、このあたりが関係しそうです。
<attribution android:tag="audioPlayback" android:label="@string/description" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-feature android:name="android.hardware.audio.low_latency" android:required="false" />
<uses-feature android:name="android.software.midi" android:required="false" />
FluidSynthのオプションは、以下です。
共通
Javaで、フレーム数とサンプルレートを取得しています。
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
String sampleRateStr = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
int sampleRate = Integer.parseInt(sampleRateStr);
String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
int frame = Integer.parseInt(framesPerBuffer);
int x = frame / 8;
if (x < 64) {
x = 64;
}
if (x > 256) {
x = 256;
}
if (sampleRate >= 48000) {
sampleRate = 48000;
}
//取得できた場合のみ
fluid_settings_setnum(handle->settings, "synth.sample-rate", sampleRate);
//スレッド1つがスレッド同期が不要になっていいかなと
fluid_settings_setint(handle->settings, "synth.threadsafe-api", 0);
//同上
fluid_settings_setint(handle->settings, "synth.cpu-cores", 1);
//これは低レイテンシでもそれ以外でも使っています
fluid_settings_setstr(handle->settings, "audio.oboe.sharing-mode", "Exclusive");
//ロックさせないように配慮しています(効果があるかはわかりません
fluid_settings_setint(handle->settings, "audio.periods", 2);
fluid_settings_setint(handle->settings, "audio.period-size", x);
fluid_settings_setint(handle->settings, "synth.audio-channels", 1);
fluid_settings_setint(handle->settings, "audio.realtime-prio", 90);
fluid_settings_setstr(handle->settings, "player.timing-source", "sample");
通常オーディオ
fluid_settings_setstr(handle->settings, "audio.oboe.performance-mode", "None");
fluid_settings_setstr(handle->settings, "audio.oboe.sample-rate-conversion-quality","Fastest");
ローレテンシー(日本語にすると低遅延)です
fluid_settings_setstr(handle->settings, "audio.oboe.performance-mode", "LowLatency");
fluid_settings_setstr(handle->settings, "audio.oboe.sample-rate-conversion-quality","Medium");
ローレイテンシの、Gameモードだとよりレイテンシをつめられるそうですが、音質が不安らしいです。デフォルトのlibfluidsynth.soにはそのオプションはございません。
こちらのサイトさま(スクリーンリーダーも途切れずはっきり‼︎話題の「低遅延モード」とは?)が関連しそうな気がします。
Android16あたりで、かなりレイテンシを詰められるのですが、FluidSynthデフォルトでは、フレーム処理(短くなる)が間に合わないことがあるので。アプリから最大同時発音数を変更可能にしています。
fluid_synth_set_polyphony(handle->synth, polyphony);
以下は、ためしてみたところ、効果があったのですが、アンサンブルの時、音が飛ぶとか、連打したとき、プチプチいうとか、バランスの問題で結局使わないことにしたのが、下記の3行です。
//fluid_settings_setint(handle->settings, "synth.note-cut", 2);
//fluid_settings_setnum(handle->settings, "synth.overflow.sustained", 0);
//fluid_settings_setnum(handle->settings, "synth.overflow.age", -1);
みんな大好きレゾナンス。は、以下の様に収まりました。
参考サイト:https://github.com/FluidSynth/fluidsynth/wiki/FluidFeatures
private int fit(int y) {
if (y < 0) return 0;
if (y > 16383) return 16383;
return y;
}
private int swap(int x) {
int h = (x >> 7) & 0x7f;
int l = x & 0x7f;
return (l << 7) | h;
}
private int squared0(int x) {
if (x >= 0x70) {
x ++;
}
int y = x * x;
return fit(y);
}
private int square64(int x) {
int pos = x - 64; // -64 to 63
if (pos > 40) pos ++;
int pos2 = pos < 0 ? - pos : pos;
int squared = pos * pos2 * 2; // +-64*64*2 = +-8192
int newpos = 8192 + squared;
if (newpos > 8000) newpos --;
return fit(newpos);
}
private int half64(int x) {
int pos = x;
int pos2 = pos;
if (pos == 0) {
pos2 = 1;
}
int newpos = pos2 + 4095 - 128;
return fit(newpos);
}
/** アプリでメッセージをハンドリングしています。耳で確認する限りいい感じ?です。
*/
if (command == MXMidiStatic.COMMAND_CH_CONTROLCHANGE) { //0xb0
int x = -1;
int y = data2;
if (data1 == MXMidiStatic.DATA1_CC_SOUND_RESONANCE) { //71
x = 22;
y = squared0(data2);
}
if (data1 == MXMidiStatic.DATA1_CC_SOUND_BLIGHTNESS) { //74
x = 21;
y = square64(data2);
}
if (data1 == MXMidiStatic.DATA1_CC_SOUND_ATTACKTIME) { //73
x = 11;
y = half64(data2);
}
if (data1 == MXMidiStatic.DATA1_CC_SOUND_RELEASETIME) { //72
x = 15;
y = half64(data2);
}
if (x >= 0) {
int channel = status & 0x0f;
int cc = MXMidiStatic.COMMAND_CH_CONTROLCHANGE + channel;
sendShortMessage(cc, MXMidiStatic.DATA1_CC_NRPN_MSB, 127);
sendShortMessage(cc, MXMidiStatic.DATA1_CC_NRPN_LSB, x);
sendShortMessage(cc, MXMidiStatic.DATA1_CC_DATAENTRY, y & 0x7f);
sendShortMessage(cc, MXMidiStatic.DATA1_CC_DATAENTRY2, (y>>7) & 0x7f);
return true;
}
sendOneMessage(one);
return true;
}
広告を表示しています。
- サウンドフォント関連
- RecyclerView関連
- フォアグランドサービス関連
- ジェスチャー関連
- AndroidのBluetoothの実装サンプルにどうぞ
- Android StudioでFluidsynthをビルド

