[PATCH 0/6] MR4076: dmsynth: Implement some MIDI events in the synth.
From: Rémi Bernon <rbernon(a)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"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
From: Rémi Bernon <rbernon(a)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) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
From: Rémi Bernon <rbernon(a)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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
From: Rémi Bernon <rbernon(a)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, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
From: Rémi Bernon <rbernon(a)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; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
From: Rémi Bernon <rbernon(a)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) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
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. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4076
participants (3)
-
Marvin -
Michael Stefaniuc (@mstefani) -
Rémi Bernon