From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 945889efb6f..b208a0a0736 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -442,7 +442,7 @@ static HRESULT synth_download_articulation2(struct synth *This, ULONG *offsets, { articulation_info = (DMUS_ARTICULATION2 *)(data + offsets[index]); list = (CONNECTIONLIST *)(data + offsets[articulation_info->ulArtIdx]); - connections = (CONNECTION *)list + 1; + connections = (CONNECTION *)(list + 1);
if (TRACE_ON(dmsynth)) dump_connectionlist(list); if (articulation_info->ulFirstExtCkIdx) FIXME("Articulation extensions not implemented\n");
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 91 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 8 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index b208a0a0736..06e576f3919 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -25,11 +25,93 @@ #include "dmksctrl.h"
#include "dmsynth_private.h" +#include "dls2.h"
#include <fluidsynth.h>
WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
+#define CONN_SRC_CC2 0x0082 +#define CONN_SRC_RPN0 0x0100 + +static const char *debugstr_conn_src(UINT src) +{ + switch (src) + { + case CONN_SRC_NONE: return "SRC_NONE"; + case CONN_SRC_LFO: return "SRC_LFO"; + case CONN_SRC_KEYONVELOCITY: return "SRC_KEYONVELOCITY"; + case CONN_SRC_KEYNUMBER: return "SRC_KEYNUMBER"; + case CONN_SRC_EG1: return "SRC_EG1"; + case CONN_SRC_EG2: return "SRC_EG2"; + case CONN_SRC_PITCHWHEEL: return "SRC_PITCHWHEEL"; + case CONN_SRC_CC1: return "SRC_CC1"; + case CONN_SRC_CC7: return "SRC_CC7"; + case CONN_SRC_CC10: return "SRC_CC10"; + case CONN_SRC_CC11: return "SRC_CC11"; + case CONN_SRC_POLYPRESSURE: return "SRC_POLYPRESSURE"; + case CONN_SRC_CHANNELPRESSURE: return "SRC_CHANNELPRESSURE"; + case CONN_SRC_VIBRATO: return "SRC_VIBRATO"; + case CONN_SRC_MONOPRESSURE: return "SRC_MONOPRESSURE"; + case CONN_SRC_CC91: return "SRC_CC91"; + case CONN_SRC_CC93: return "SRC_CC93"; + + case CONN_SRC_CC2: return "SRC_CC2"; + case CONN_SRC_RPN0: return "SRC_RPN0"; + } + + return wine_dbg_sprintf("%#x", src); +} + +static const char *debugstr_conn_dst(UINT dst) +{ + switch (dst) + { + case CONN_DST_NONE: return "DST_NONE"; + /* case CONN_DST_ATTENUATION: return "DST_ATTENUATION"; Same as CONN_DST_GAIN */ + case CONN_DST_PITCH: return "DST_PITCH"; + case CONN_DST_PAN: return "DST_PAN"; + case CONN_DST_LFO_FREQUENCY: return "DST_LFO_FREQUENCY"; + case CONN_DST_LFO_STARTDELAY: return "DST_LFO_STARTDELAY"; + case CONN_DST_EG1_ATTACKTIME: return "DST_EG1_ATTACKTIME"; + case CONN_DST_EG1_DECAYTIME: return "DST_EG1_DECAYTIME"; + case CONN_DST_EG1_RELEASETIME: return "DST_EG1_RELEASETIME"; + case CONN_DST_EG1_SUSTAINLEVEL: return "DST_EG1_SUSTAINLEVEL"; + case CONN_DST_EG2_ATTACKTIME: return "DST_EG2_ATTACKTIME"; + case CONN_DST_EG2_DECAYTIME: return "DST_EG2_DECAYTIME"; + case CONN_DST_EG2_RELEASETIME: return "DST_EG2_RELEASETIME"; + case CONN_DST_EG2_SUSTAINLEVEL: return "DST_EG2_SUSTAINLEVEL"; + case CONN_DST_GAIN: return "DST_GAIN"; + case CONN_DST_KEYNUMBER: return "DST_KEYNUMBER"; + case CONN_DST_LEFT: return "DST_LEFT"; + case CONN_DST_RIGHT: return "DST_RIGHT"; + case CONN_DST_CENTER: return "DST_CENTER"; + case CONN_DST_LEFTREAR: return "DST_LEFTREAR"; + case CONN_DST_RIGHTREAR: return "DST_RIGHTREAR"; + case CONN_DST_LFE_CHANNEL: return "DST_LFE_CHANNEL"; + case CONN_DST_CHORUS: return "DST_CHORUS"; + case CONN_DST_REVERB: return "DST_REVERB"; + case CONN_DST_VIB_FREQUENCY: return "DST_VIB_FREQUENCY"; + case CONN_DST_VIB_STARTDELAY: return "DST_VIB_STARTDELAY"; + case CONN_DST_EG1_DELAYTIME: return "DST_EG1_DELAYTIME"; + case CONN_DST_EG1_HOLDTIME: return "DST_EG1_HOLDTIME"; + case CONN_DST_EG1_SHUTDOWNTIME: return "DST_EG1_SHUTDOWNTIME"; + case CONN_DST_EG2_DELAYTIME: return "DST_EG2_DELAYTIME"; + case CONN_DST_EG2_HOLDTIME: return "DST_EG2_HOLDTIME"; + case CONN_DST_FILTER_CUTOFF: return "DST_FILTER_CUTOFF"; + case CONN_DST_FILTER_Q: return "DST_FILTER_Q"; + } + + return wine_dbg_sprintf("%#x", dst); +} + +static const char *debugstr_connection(const CONNECTION *conn) +{ + return wine_dbg_sprintf("%s (%#x) x %s (%#x) -> %s (%#x): %ld", debugstr_conn_src(conn->usSource), + (conn->usTransform >> 10) & 0x3f, debugstr_conn_src(conn->usControl), (conn->usTransform >> 4) & 0x3f, + debugstr_conn_dst(conn->usDestination), (conn->usTransform & 0xf), conn->lScale); +} + static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) { TRACE("DMUS_INSTRUMENT:\n"); @@ -85,14 +167,7 @@ static void dump_connectionlist(CONNECTIONLIST *list) TRACE(" - cConnections = %lu\n", list->cConnections);
for (i = 0; i < list->cConnections; i++) - { - TRACE("- CONNECTION[%u]:\n", i); - TRACE(" - usSource = %u\n", connections[i].usSource); - TRACE(" - usControl = %u\n", connections[i].usControl); - TRACE(" - usDestination = %u\n", connections[i].usDestination); - TRACE(" - usTransform = %u\n", connections[i].usTransform); - TRACE(" - lScale = %lu\n", connections[i].lScale); - } + TRACE("- CONNECTION[%u]: %s\n", i, debugstr_connection(connections + i)); }
static void dump_dmus_wave(DMUS_WAVE *wave)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 45 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 06e576f3919..ad5e2e75c09 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -303,6 +303,7 @@ struct synth BOOL open; IDirectMusicSynthSink *sink;
+ CRITICAL_SECTION cs; struct list instruments; struct list waves;
@@ -384,6 +385,10 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) delete_fluid_sfont(This->fluid_sfont); This->fluid_sfont = NULL; delete_fluid_settings(This->fluid_settings); + + This->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->cs); + free(This); }
@@ -411,11 +416,21 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par
TRACE("(%p, %p)\n", This, params);
- if (This->open) return DMUS_E_ALREADYOPEN; + EnterCriticalSection(&This->cs); + if (This->open) + { + LeaveCriticalSection(&This->cs); + return DMUS_E_ALREADYOPEN; + }
if (params) { - if (params->dwSize < sizeof(DMUS_PORTPARAMS7)) return E_INVALIDARG; + if (params->dwSize < sizeof(DMUS_PORTPARAMS7)) + { + LeaveCriticalSection(&This->cs); + return E_INVALIDARG; + } + if (size > params->dwSize) size = params->dwSize;
if ((params->dwValidParams & DMUS_PORTPARAMS_VOICES) && params->dwVoices) @@ -473,6 +488,7 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par
This->params = actual; This->open = TRUE; + LeaveCriticalSection(&This->cs);
return modified ? S_FALSE : S_OK; } @@ -483,13 +499,18 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface)
TRACE("(%p)\n", This);
+ EnterCriticalSection(&This->cs); if (!This->open) + { + LeaveCriticalSection(&This->cs); return DMUS_E_ALREADYCLOSED; + }
fluid_synth_remove_sfont(This->fluid_synth, This->fluid_sfont); delete_fluid_synth(This->fluid_synth); This->fluid_synth = NULL; This->open = FALSE; + LeaveCriticalSection(&This->cs);
return S_OK; } @@ -549,14 +570,17 @@ static struct wave *synth_find_wave_from_id(struct synth *This, DWORD id) { struct wave *wave;
+ EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(wave, &This->waves, struct wave, entry) { if (wave->id == id) { wave_addref(wave); + LeaveCriticalSection(&This->cs); return wave; } } + LeaveCriticalSection(&This->cs);
WARN("Failed to find wave with id %#lx\n", id); return NULL; @@ -627,9 +651,11 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * instrument_info->ulGlobalArtIdx, &instrument->articulations))) goto error;
+ EnterCriticalSection(&This->cs); list_add_tail(&This->instruments, &instrument->entry); - *ret_handle = instrument; + LeaveCriticalSection(&This->cs);
+ *ret_handle = instrument; return S_OK;
error: @@ -693,9 +719,11 @@ static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, } }
+ EnterCriticalSection(&This->cs); list_add_tail(&This->waves, &wave->entry); - *ret_handle = wave; + LeaveCriticalSection(&This->cs);
+ *ret_handle = wave; return S_OK; }
@@ -757,11 +785,14 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, TRACE("(%p)->(%p, %p, %p)\n", This, handle, callback, user_data); if (callback) FIXME("Unload callbacks not implemented\n");
+ EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(instrument, &This->instruments, struct instrument, entry) { if (instrument == handle) { list_remove(&instrument->entry); + LeaveCriticalSection(&This->cs); + instrument_release(instrument); return S_OK; } @@ -772,10 +803,13 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, if (wave == handle) { list_remove(&wave->entry); + LeaveCriticalSection(&This->cs); + wave_release(wave); return S_OK; } } + LeaveCriticalSection(&This->cs);
return E_FAIL; } @@ -1217,6 +1251,9 @@ HRESULT synth_create(IUnknown **ret_iface) goto failed; fluid_sfont_set_data(obj->fluid_sfont, obj);
+ InitializeCriticalSection(&obj->cs); + obj->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; return S_OK;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 56 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index ad5e2e75c09..e6a6944bbc6 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -31,6 +31,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
+#define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) + #define CONN_SRC_CC2 0x0082 #define CONN_SRC_RPN0 0x0100
@@ -291,6 +293,13 @@ static void instrument_release(struct instrument *instrument) } }
+struct event +{ + struct list entry; + LONGLONG position; + BYTE midi[3]; +}; + struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; @@ -306,6 +315,7 @@ struct synth CRITICAL_SECTION cs; struct list instruments; struct list waves; + struct list events;
fluid_settings_t *fluid_settings; fluid_sfont_t *fluid_sfont; @@ -366,6 +376,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) if (!ref) { struct instrument *instrument; + struct event *event; struct wave *wave; void *next;
@@ -381,6 +392,12 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) wave_release(wave); }
+ LIST_FOR_EACH_ENTRY_SAFE(event, next, &This->events, struct event, entry) + { + list_remove(&event->entry); + free(event); + } + fluid_sfont_set_data(This->fluid_sfont, NULL); delete_fluid_sfont(This->fluid_sfont); This->fluid_sfont = NULL; @@ -815,11 +832,45 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, }
static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, - REFERENCE_TIME rt, BYTE *buffer, DWORD size) + REFERENCE_TIME time, BYTE *buffer, DWORD size) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + DMUS_EVENTHEADER *head = (DMUS_EVENTHEADER *)buffer; + BYTE *end = buffer + size, *data; + HRESULT hr; + + TRACE("(%p, %I64d, %p, %lu)\n", This, time, buffer, size); + + while ((data = (BYTE *)(head + 1)) < end) + { + DMUS_EVENTHEADER *next = ROUND_ADDR(data + head->cbEvent + 7, 7); + struct event *event, *next_event; + LONGLONG position; + + if ((BYTE *)next > end) return E_INVALIDARG; + if (FAILED(hr = IDirectMusicSynthSink_RefTimeToSample(This->sink, + time + head->rtDelta, &position))) + return hr; + + if (!(head->dwFlags & DMUS_EVENT_STRUCTURED)) + FIXME("Unstructured events not implemeted\n"); + else if (head->cbEvent > 3) + FIXME("Unexpected MIDI event size %lu\n", head->cbEvent); + else + { + if (!(event = calloc(1, sizeof(*event)))) return E_OUTOFMEMORY; + memcpy(event->midi, data, head->cbEvent); + event->position = position; + + EnterCriticalSection(&This->cs); + LIST_FOR_EACH_ENTRY(next_event, &This->events, struct event, entry) + if (next_event->position >= event->position) break; + list_add_before(&next_event->entry, &event->entry); + LeaveCriticalSection(&This->cs); + }
- FIXME("(%p, 0x%s, %p, %lu): stub\n", This, wine_dbgstr_longlong(rt), buffer, size); + head = next; + }
return S_OK; } @@ -1244,6 +1295,7 @@ HRESULT synth_create(IUnknown **ret_iface)
list_init(&obj->instruments); list_init(&obj->waves); + list_init(&obj->events);
if (!(obj->fluid_settings = new_fluid_settings())) goto failed; if (!(obj->fluid_sfont = new_fluid_sfont(synth_sfont_get_name, synth_sfont_get_preset,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index e6a6944bbc6..f1719944e51 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -979,9 +979,52 @@ static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + struct event *event, *next;
- FIXME("(%p, %p, %ld, 0x%s): stub\n", This, buffer, length, wine_dbgstr_longlong(position)); + TRACE("(%p, %p, %ld, %I64d)\n", This, buffer, length, position);
+ EnterCriticalSection(&This->cs); + LIST_FOR_EACH_ENTRY_SAFE(event, next, &This->events, struct event, entry) + { + BYTE status = event->midi[0] & 0xf0, chan = event->midi[0] & 0x0f; + LONGLONG offset = event->position - position; + + if (offset >= length) break; + if (offset > 0) + { + fluid_synth_write_s16(This->fluid_synth, offset, buffer, 0, 2, buffer, 1, 2); + buffer += offset * 2; + position += offset; + length -= offset; + } + + TRACE("status %#x chan %#x midi %#x %#x\n", status, chan, event->midi[1], event->midi[2]); + + switch (status) + { + case 0x80: + fluid_synth_noteoff(This->fluid_synth, chan, event->midi[1]); + break; + case 0x90: + fluid_synth_noteon(This->fluid_synth, chan, event->midi[1], event->midi[2]); + break; + case 0xb0: + fluid_synth_cc(This->fluid_synth, chan, event->midi[1], event->midi[2]); + break; + case 0xc0: + fluid_synth_program_change(This->fluid_synth, chan, event->midi[1]); + break; + default: + FIXME("MIDI event not implemented: %#x %#x %#x\n", event->midi[0], event->midi[1], event->midi[2]); + break; + } + + list_remove(&event->entry); + free(event); + } + LeaveCriticalSection(&This->cs); + + if (length) fluid_synth_write_s16(This->fluid_synth, length, buffer, 0, 2, buffer, 1, 2); return S_OK; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dmsynth/synth.c | 302 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 299 insertions(+), 3 deletions(-)
diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index f1719944e51..b7174000e20 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -36,6 +36,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); #define CONN_SRC_CC2 0x0082 #define CONN_SRC_RPN0 0x0100
+#define CONN_TRN_BIPOLAR (1<<4) +#define CONN_TRN_INVERT (1<<5) + static const char *debugstr_conn_src(UINT src) { switch (src) @@ -267,6 +270,11 @@ struct instrument struct synth *synth; };
+static void instrument_addref(struct instrument *instrument) +{ + InterlockedIncrement(&instrument->ref); +} + static void instrument_release(struct instrument *instrument) { ULONG ref = InterlockedDecrement(&instrument->ref); @@ -1274,6 +1282,277 @@ static const IKsControlVtbl synth_control_vtbl = synth_control_KsEvent, };
+static const char *synth_preset_get_name(fluid_preset_t *fluid_preset) +{ + return "DirectMusicSynth"; +} + +static int synth_preset_get_bank(fluid_preset_t *fluid_preset) +{ + TRACE("(%p)\n", fluid_preset); + return 0; +} + +static int synth_preset_get_num(fluid_preset_t *fluid_preset) +{ + struct instrument *instrument = fluid_preset_get_data(fluid_preset); + + TRACE("(%p)\n", fluid_preset); + + if (!instrument) return 0; + return instrument->patch; +} + +static BOOL fluid_gen_from_connection(CONNECTION *conn, UINT *gen) +{ + switch (conn->usDestination) + { + case CONN_DST_FILTER_CUTOFF: *gen = GEN_FILTERFC; return TRUE; + case CONN_DST_FILTER_Q: *gen = GEN_FILTERQ; return TRUE; + case CONN_DST_CHORUS: *gen = GEN_CHORUSSEND; return TRUE; + case CONN_DST_REVERB: *gen = GEN_REVERBSEND; return TRUE; + case CONN_DST_PAN: *gen = GEN_PAN; return TRUE; + case CONN_DST_LFO_STARTDELAY: *gen = GEN_MODLFODELAY; return TRUE; + case CONN_DST_LFO_FREQUENCY: *gen = GEN_MODLFOFREQ; return TRUE; + case CONN_DST_VIB_STARTDELAY: *gen = GEN_VIBLFODELAY; return TRUE; + case CONN_DST_VIB_FREQUENCY: *gen = GEN_VIBLFOFREQ; return TRUE; + case CONN_DST_EG2_DELAYTIME: *gen = GEN_MODENVDELAY; return TRUE; + case CONN_DST_EG2_ATTACKTIME: *gen = GEN_MODENVATTACK; return TRUE; + case CONN_DST_EG2_HOLDTIME: *gen = GEN_MODENVHOLD; return TRUE; + case CONN_DST_EG2_DECAYTIME: *gen = GEN_MODENVDECAY; return TRUE; + case CONN_DST_EG2_SUSTAINLEVEL: *gen = GEN_MODENVSUSTAIN; return TRUE; + case CONN_DST_EG2_RELEASETIME: *gen = GEN_MODENVRELEASE; return TRUE; + case CONN_DST_EG1_DELAYTIME: *gen = GEN_VOLENVDELAY; return TRUE; + case CONN_DST_EG1_ATTACKTIME: *gen = GEN_VOLENVATTACK; return TRUE; + case CONN_DST_EG1_HOLDTIME: *gen = GEN_VOLENVHOLD; return TRUE; + case CONN_DST_EG1_DECAYTIME: *gen = GEN_VOLENVDECAY; return TRUE; + case CONN_DST_EG1_SUSTAINLEVEL: *gen = GEN_VOLENVSUSTAIN; return TRUE; + case CONN_DST_EG1_RELEASETIME: *gen = GEN_VOLENVRELEASE; return TRUE; + case CONN_DST_GAIN: *gen = GEN_ATTENUATION; return TRUE; + case CONN_DST_PITCH: *gen = GEN_PITCH; return TRUE; + default: FIXME("Unsupported connection %s\n", debugstr_connection(conn)); return FALSE; + } +} + +static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn) +{ + UINT gen; + + if (conn->usControl != CONN_SRC_NONE) return FALSE; + if (conn->usTransform != CONN_TRN_NONE) return FALSE; + + if (conn->usSource == CONN_SRC_NONE) + { + if (!fluid_gen_from_connection(conn, &gen)) return FALSE; + } + if (conn->usSource == CONN_SRC_KEYNUMBER) + { + switch (conn->usDestination) + { + case CONN_DST_EG2_HOLDTIME: gen = GEN_KEYTOMODENVHOLD; break; + case CONN_DST_EG2_DECAYTIME: gen = GEN_KEYTOMODENVDECAY; break; + case CONN_DST_EG1_HOLDTIME: gen = GEN_KEYTOVOLENVHOLD; break; + case CONN_DST_EG1_DECAYTIME: gen = GEN_KEYTOVOLENVDECAY; break; + default: return FALSE; + } + } + else if (conn->usSource == CONN_SRC_LFO) + { + switch (conn->usDestination) + { + case CONN_DST_PITCH: gen = GEN_MODLFOTOPITCH; break; + case CONN_DST_FILTER_CUTOFF: gen = GEN_MODLFOTOFILTERFC; break; + case CONN_DST_GAIN: gen = GEN_MODLFOTOVOL; break; + default: return FALSE; + } + } + else if (conn->usSource == CONN_SRC_EG2) + { + switch (conn->usDestination) + { + case CONN_DST_PITCH: gen = GEN_MODENVTOPITCH; break; + case CONN_DST_FILTER_CUTOFF: gen = GEN_MODENVTOFILTERFC; break; + default: return FALSE; + } + } + else if (conn->usSource == CONN_SRC_VIBRATO) + { + switch (conn->usDestination) + { + case CONN_DST_PITCH: gen = GEN_VIBLFOTOPITCH; break; + default: return FALSE; + } + } + else + { + return FALSE; + } + + fluid_voice_gen_set(fluid_voice, gen, conn->lScale); + return TRUE; +} + +static BOOL fluid_source_from_connection(USHORT source, USHORT transform, UINT *fluid_source, UINT *fluid_flags) +{ + UINT flags = FLUID_MOD_GC; + if (source >= CONN_SRC_CC1 && source <= CONN_SRC_CC1 + 0x7f) + { + *fluid_source = source; + flags = FLUID_MOD_CC; + } + else switch (source) + { + case CONN_SRC_NONE: *fluid_source = FLUID_MOD_NONE; break; + case CONN_SRC_KEYONVELOCITY: *fluid_source = FLUID_MOD_VELOCITY; break; + case CONN_SRC_KEYNUMBER: *fluid_source = FLUID_MOD_KEY; break; + case CONN_SRC_PITCHWHEEL: *fluid_source = FLUID_MOD_PITCHWHEEL; break; + case CONN_SRC_POLYPRESSURE: *fluid_source = FLUID_MOD_KEYPRESSURE; break; + case CONN_SRC_CHANNELPRESSURE: *fluid_source = FLUID_MOD_CHANNELPRESSURE; break; + case CONN_SRC_RPN0: *fluid_source = FLUID_MOD_PITCHWHEELSENS; break; + default: return FALSE; + } + + if (transform & CONN_TRN_INVERT) flags |= FLUID_MOD_NEGATIVE; + if (transform & CONN_TRN_BIPOLAR) flags |= FLUID_MOD_BIPOLAR; + switch (transform & CONN_TRN_SWITCH) + { + case CONN_TRN_NONE: flags |= FLUID_MOD_LINEAR; break; + case CONN_TRN_CONCAVE: flags |= FLUID_MOD_CONCAVE; break; + case CONN_TRN_CONVEX: flags |= FLUID_MOD_CONVEX; break; + case CONN_TRN_SWITCH: flags |= FLUID_MOD_SWITCH; break; + } + + *fluid_flags = flags; + return TRUE; +} + +static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn, UINT src1, UINT flags1, + UINT src2, UINT flags2) +{ + fluid_mod_t *mod; + UINT gen = -1; + + switch (MAKELONG(conn->usSource, conn->usDestination)) + { + case MAKELONG(CONN_SRC_LFO, CONN_DST_PITCH): gen = GEN_MODLFOTOPITCH; break; + case MAKELONG(CONN_SRC_VIBRATO, CONN_DST_PITCH): gen = GEN_VIBLFOTOPITCH; break; + case MAKELONG(CONN_SRC_EG2, CONN_DST_PITCH): gen = GEN_MODENVTOPITCH; break; + case MAKELONG(CONN_SRC_LFO, CONN_DST_FILTER_CUTOFF): gen = GEN_MODLFOTOFILTERFC; break; + case MAKELONG(CONN_SRC_EG2, CONN_DST_FILTER_CUTOFF): gen = GEN_MODENVTOFILTERFC; break; + case MAKELONG(CONN_SRC_LFO, CONN_DST_GAIN): gen = GEN_MODLFOTOVOL; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG2_HOLDTIME): gen = GEN_KEYTOMODENVHOLD; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG2_DECAYTIME): gen = GEN_KEYTOMODENVDECAY; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG1_HOLDTIME): gen = GEN_KEYTOVOLENVHOLD; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG1_DECAYTIME): gen = GEN_KEYTOVOLENVDECAY; break; + } + + if (conn->usControl != CONN_SRC_NONE && gen != -1) + { + src1 = src2; + flags1 = flags2; + src2 = 0; + flags2 = 0; + } + + if (gen == -1 && !fluid_gen_from_connection(conn, &gen)) return FALSE; + + if (!(mod = new_fluid_mod())) return FALSE; + fluid_mod_set_source1(mod, src1, flags1); + fluid_mod_set_source2(mod, src2, flags2); + fluid_mod_set_dest(mod, gen); + fluid_mod_set_amount(mod, conn->lScale); + fluid_voice_add_mod(fluid_voice, mod, FLUID_VOICE_OVERWRITE); + + return TRUE; +} + +static void fluid_voice_add_articulation(fluid_voice_t *fluid_voice, struct articulation *articulation) +{ + UINT i; + + for (i = 0; i < articulation->list.cConnections; i++) + { + UINT src1 = FLUID_MOD_NONE, flags1 = 0, src2 = FLUID_MOD_NONE, flags2 = 0; + CONNECTION *conn = articulation->connections + i; + + if (set_gen_from_connection(fluid_voice, conn)) continue; + + if (!fluid_source_from_connection(conn->usSource, (conn->usTransform >> 10) & 0x3f, + &src1, &flags1)) + continue; + if (!fluid_source_from_connection(conn->usControl, (conn->usControl >> 4) & 0x3f, + &src2, &flags2)) + continue; + add_mod_from_connection(fluid_voice, conn, src1, flags1, src2, flags2); + } +} + +static void fluid_voice_add_articulations(fluid_voice_t *fluid_voice, struct list *list) +{ + struct articulation *articulation; + + LIST_FOR_EACH_ENTRY(articulation, list, struct articulation, entry) + fluid_voice_add_articulation(fluid_voice, articulation); +} + +static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *fluid_synth, int chan, int key, int vel) +{ + struct instrument *instrument = fluid_preset_get_data(fluid_preset); + struct synth *synth = instrument->synth; + fluid_sample_t *fluid_sample; + fluid_voice_t *fluid_voice; + struct region *region; + + TRACE("(%p, %p, %u, %u, %u)\n", fluid_preset, fluid_synth, chan, key, vel); + + if (!instrument) return FLUID_FAILED; + + LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) + { + struct wave *wave = region->wave; + + if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; + if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue; + + if (!(fluid_sample = new_fluid_sample())) + { + WARN("Failed to allocate FluidSynth sample\n"); + return FLUID_FAILED; + } + + fluid_sample_set_sound_data(fluid_sample, wave->samples, NULL, wave->sample_count, + wave->format.nSamplesPerSec, TRUE); + if (region->wave_sample.cSampleLoops) + { + WLOOP *loop = region->wave_loops; + fluid_sample_set_loop(fluid_sample, loop->ulStart, loop->ulStart + loop->ulLength); + } + fluid_sample_set_pitch(fluid_sample, region->wave_sample.usUnityNote, region->wave_sample.sFineTune); + + if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, fluid_sample, chan, key, vel))) + { + WARN("Failed to allocate FluidSynth voice\n"); + delete_fluid_sample(fluid_sample); + return FLUID_FAILED; + } + + fluid_voice_add_articulations(fluid_voice, &instrument->articulations); + fluid_voice_add_articulations(fluid_voice, ®ion->articulations); + fluid_synth_start_voice(synth->fluid_synth, fluid_voice); + return FLUID_OK; + } + + WARN("Failed to find instrument matching note / velocity\n"); + return FLUID_FAILED; +} + +static void synth_preset_free(fluid_preset_t *fluid_preset) +{ + struct instrument *instrument = fluid_preset_get_data(fluid_preset); + fluid_preset_set_data(fluid_preset, NULL); + if (instrument) instrument_release(instrument); +} + static const char *synth_sfont_get_name(fluid_sfont_t *fluid_sfont) { return "DirectMusicSynth"; @@ -1283,17 +1562,34 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba { struct synth *synth = fluid_sfont_get_data(fluid_sfont); struct instrument *instrument; + fluid_preset_t *fluid_preset;
TRACE("(%p, %d, %d)\n", fluid_sfont, bank, patch);
if (!synth) return NULL;
+ EnterCriticalSection(&synth->cs); + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) if (instrument->patch == patch) break; - if (&instrument->entry == &synth->instruments) return NULL;
- FIXME("Preset not implemented yet\n"); - return NULL; + if (&instrument->entry == &synth->instruments) + { + fluid_preset = NULL; + WARN("Could not find instrument with patch %#x\n", patch); + } + else if ((fluid_preset = new_fluid_preset(fluid_sfont, synth_preset_get_name, synth_preset_get_bank, + synth_preset_get_num, synth_preset_noteon, synth_preset_free))) + { + fluid_preset_set_data(fluid_preset, instrument); + instrument_addref(instrument); + + TRACE("Created fluid_preset %p for instrument %p\n", fluid_preset, instrument); + } + + LeaveCriticalSection(&synth->cs); + + return fluid_preset; }
static void synth_sfont_iter_start(fluid_sfont_t *fluid_sfont)
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=138672
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/dmsynth/synth.c:303 error: patch failed: dlls/dmsynth/synth.c:31 error: patch failed: dlls/dmsynth/synth.c:979 error: patch failed: dlls/dmsynth/synth.c:36 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/dmsynth/synth.c:303 error: patch failed: dlls/dmsynth/synth.c:31 error: patch failed: dlls/dmsynth/synth.c:979 error: patch failed: dlls/dmsynth/synth.c:36 Task: Patch failed to apply
=== debian11b (build log) ===
error: patch failed: dlls/dmsynth/synth.c:303 error: patch failed: dlls/dmsynth/synth.c:31 error: patch failed: dlls/dmsynth/synth.c:979 error: patch failed: dlls/dmsynth/synth.c:36 Task: Patch failed to apply
This merge request was approved by Michael Stefaniuc.