Module: wine
Branch: master
Commit: 215a55d603bdaf501aae1df1db328131a314b443
URL:
https://gitlab.winehq.org/wine/wine/-/commit/215a55d603bdaf501aae1df1db3281…
Author: Rémi Bernon <rbernon(a)codeweavers.com>
Date: Thu Sep 21 09:05:55 2023 +0200
dmusic: Implement SoundFont2 wave sample parsing.
---
dlls/dmusic/collection.c | 23 +++++++++++++
dlls/dmusic/dmusic_private.h | 2 ++
dlls/dmusic/wave.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 105 insertions(+)
diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c
index feda1cbf8a9..a7d9d666e6c 100644
--- a/dlls/dmusic/collection.c
+++ b/dlls/dmusic/collection.c
@@ -580,6 +580,29 @@ static HRESULT parse_sfbk_chunk(struct collection *This, IStream
*stream, struct
}
}
+ if (SUCCEEDED(hr))
+ {
+ UINT size = offsetof(struct pool, cues[soundfont.sample_count]);
+ if (!(This->pool = calloc(1, size))) return E_OUTOFMEMORY;
+ This->pool->table.cbSize = sizeof(This->pool->table);
+ }
+
+ for (i = 0; SUCCEEDED(hr) && i < soundfont.sample_count; i++)
+ {
+ struct wave_entry *entry;
+
+ if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY;
+ hr = wave_create_from_soundfont(&soundfont, i, &entry->wave);
+ if (FAILED(hr)) free(entry);
+ else
+ {
+ entry->offset = i;
+ This->pool->table.cCues++;
+ This->pool->cues[i].ulOffset = i;
+ list_add_tail(&This->waves, &entry->entry);
+ }
+ }
+
free(soundfont.phdr);
free(soundfont.pbag);
free(soundfont.pmod);
diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h
index 0b000fb6f1c..232bbcd0c94 100644
--- a/dlls/dmusic/dmusic_private.h
+++ b/dlls/dmusic/dmusic_private.h
@@ -91,12 +91,14 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID,
LPVOID* ppobj,
extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface);
+struct soundfont;
extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry
*parent,
struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument
**ret_iface);
extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface,
IDirectMusicPortDownload *port,
IDirectMusicDownloadedInstrument **downloaded);
extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface,
IDirectMusicPortDownload *port);
+extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index,
IUnknown **out);
extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent,
IUnknown **out);
extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port,
DWORD *id);
diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c
index 6637612596a..40a8c9e129f 100644
--- a/dlls/dmusic/wave.c
+++ b/dlls/dmusic/wave.c
@@ -17,6 +17,7 @@
*/
#include "dmusic_private.h"
+#include "soundfont.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
@@ -216,6 +217,85 @@ HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry
*parent, IUnk
return S_OK;
}
+HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown
**ret_iface)
+{
+ struct sf_sample *sf_sample = soundfont->shdr + index;
+ struct sample *sample = NULL;
+ WAVEFORMATEX *format = NULL;
+ HRESULT hr = E_OUTOFMEMORY;
+ UINT data_size, offset;
+ struct wave *This;
+ void *data = NULL;
+ IUnknown *iface;
+
+ TRACE("(%p, %u, %p)\n", soundfont, index, ret_iface);
+
+ if (sf_sample->sample_link) FIXME("Stereo sample not supported\n");
+
+ if (!(format = calloc(1, sizeof(*format)))) goto failed;
+ format->wFormatTag = WAVE_FORMAT_PCM;
+ format->nChannels = 1;
+ format->wBitsPerSample = 16;
+ format->nSamplesPerSec = sf_sample->sample_rate;
+ format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8;
+ format->nAvgBytesPerSec = format->nBlockAlign * format->nSamplesPerSec;
+
+ if (!(sample = calloc(1, offsetof(struct sample, loops[1])))) goto failed;
+ sample->head.cbSize = sizeof(sample->head);
+ sample->head.cSampleLoops = 1;
+ sample->loops[0].ulStart = sf_sample->start_loop - sf_sample->start;
+ sample->loops[0].ulLength = sf_sample->end_loop - sf_sample->start_loop;
+
+ data_size = sf_sample->end - sf_sample->start;
+ if (!(data = malloc(data_size * format->nBlockAlign))) goto failed;
+ offset = sf_sample->start * format->nBlockAlign / format->nChannels;
+ memcpy(data, soundfont->sdta + offset, data_size);
+
+ if (FAILED(hr = wave_create(&iface))) goto failed;
+
+ This = impl_from_IUnknown(iface);
+ This->format = format;
+ This->sample = sample;
+ This->data_size = data_size;
+ This->data = data;
+
+ if (TRACE_ON(dmusic))
+ {
+ UINT i;
+
+ TRACE("*** Created DirectMusicWave %p\n", This);
+ TRACE(" - format: %p\n", This->format);
+ if (This->format)
+ {
+ TRACE(" - wFormatTag: %u\n", This->format->wFormatTag);
+ TRACE(" - nChannels: %u\n", This->format->nChannels);
+ TRACE(" - nSamplesPerSec: %lu\n",
This->format->nSamplesPerSec);
+ TRACE(" - nAvgBytesPerSec: %lu\n",
This->format->nAvgBytesPerSec);
+ TRACE(" - nBlockAlign: %u\n",
This->format->nBlockAlign);
+ TRACE(" - wBitsPerSample: %u\n",
This->format->wBitsPerSample);
+ TRACE(" - cbSize: %u\n", This->format->cbSize);
+ }
+
+ TRACE(" - sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation:
%ld, options: %#lx, loops: %lu}\n",
+ This->sample->head.cbSize, This->sample->head.usUnityNote,
+ This->sample->head.sFineTune,
This->sample->head.lAttenuation,
+ This->sample->head.fulOptions,
This->sample->head.cSampleLoops);
+ for (i = 0; i < This->sample->head.cSampleLoops; i++)
+ TRACE(" - loops[%u]: {size: %lu, type: %lu, start: %lu, length:
%lu}\n", i,
+ This->sample->loops[i].cbSize,
This->sample->loops[i].ulType,
+ This->sample->loops[i].ulStart,
This->sample->loops[i].ulLength);
+ }
+
+ *ret_iface = iface;
+ return S_OK;
+
+failed:
+ free(data);
+ free(sample);
+ free(format);
+ return hr;
+}
+
HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD
*id)
{
struct download_buffer