mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-30 05:31:39 +00:00
dmusic: Implement SoundFont2 collection parsing.
This commit is contained in:
parent
182338bab2
commit
b733a46ada
|
@ -3546,7 +3546,7 @@ static void test_band_track_play(void)
|
|||
&IID_IDirectMusicLoader8, (void **)&loader);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicLoader_SetObject(loader, &desc);
|
||||
todo_wine ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
hr = test_loader_stream_create(stream, loader, &loader_stream);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "dmusic_private.h"
|
||||
#include "soundfont.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
|
||||
|
||||
|
@ -353,6 +354,246 @@ static HRESULT parse_dls_chunk(struct collection *This, IStream *stream, struct
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT parse_sdta_list(struct collection *This, IStream *stream, struct chunk_entry *parent,
|
||||
struct soundfont *soundfont)
|
||||
{
|
||||
struct chunk_entry chunk = {.parent = parent};
|
||||
HRESULT hr;
|
||||
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (MAKE_IDTYPE(chunk.id, chunk.type))
|
||||
{
|
||||
case mmioFOURCC('s','m','p','l'):
|
||||
if (soundfont->sdta) return E_INVALIDARG;
|
||||
if (!(soundfont->sdta = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->sdta, chunk.size);
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) break;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT parse_pdta_list(struct collection *This, IStream *stream, struct chunk_entry *parent,
|
||||
struct soundfont *soundfont)
|
||||
{
|
||||
struct chunk_entry chunk = {.parent = parent};
|
||||
HRESULT hr;
|
||||
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (MAKE_IDTYPE(chunk.id, chunk.type))
|
||||
{
|
||||
case mmioFOURCC('p','h','d','r'):
|
||||
if (soundfont->phdr) return E_INVALIDARG;
|
||||
if (!(soundfont->phdr = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->phdr, chunk.size);
|
||||
soundfont->preset_count = chunk.size / sizeof(*soundfont->phdr) - 1;
|
||||
break;
|
||||
|
||||
case mmioFOURCC('p','b','a','g'):
|
||||
if (soundfont->pbag) return E_INVALIDARG;
|
||||
if (!(soundfont->pbag = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->pbag, chunk.size);
|
||||
break;
|
||||
|
||||
case mmioFOURCC('p','m','o','d'):
|
||||
if (soundfont->pmod) return E_INVALIDARG;
|
||||
if (!(soundfont->pmod = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->pmod, chunk.size);
|
||||
break;
|
||||
|
||||
case mmioFOURCC('p','g','e','n'):
|
||||
if (soundfont->pgen) return E_INVALIDARG;
|
||||
if (!(soundfont->pgen = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->pgen, chunk.size);
|
||||
break;
|
||||
|
||||
case mmioFOURCC('i','n','s','t'):
|
||||
if (soundfont->inst) return E_INVALIDARG;
|
||||
if (!(soundfont->inst = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->inst, chunk.size);
|
||||
soundfont->instrument_count = chunk.size / sizeof(*soundfont->inst) - 1;
|
||||
break;
|
||||
|
||||
case mmioFOURCC('i','b','a','g'):
|
||||
if (soundfont->ibag) return E_INVALIDARG;
|
||||
if (!(soundfont->ibag = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->ibag, chunk.size);
|
||||
break;
|
||||
|
||||
case mmioFOURCC('i','m','o','d'):
|
||||
if (soundfont->imod) return E_INVALIDARG;
|
||||
if (!(soundfont->imod = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->imod, chunk.size);
|
||||
break;
|
||||
|
||||
case mmioFOURCC('i','g','e','n'):
|
||||
if (soundfont->igen) return E_INVALIDARG;
|
||||
if (!(soundfont->igen = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->igen, chunk.size);
|
||||
break;
|
||||
|
||||
case mmioFOURCC('s','h','d','r'):
|
||||
if (soundfont->shdr) return E_INVALIDARG;
|
||||
if (!(soundfont->shdr = malloc(chunk.size))) return E_OUTOFMEMORY;
|
||||
hr = stream_chunk_get_data(stream, &chunk, soundfont->shdr, chunk.size);
|
||||
soundfont->sample_count = chunk.size / sizeof(*soundfont->shdr) - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) break;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT parse_sfbk_chunk(struct collection *This, IStream *stream, struct chunk_entry *parent)
|
||||
{
|
||||
struct chunk_entry chunk = {.parent = parent};
|
||||
struct soundfont soundfont = {0};
|
||||
UINT i, j, k;
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
|
||||
DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID))
|
||||
|| FAILED(hr = stream_reset_chunk_data(stream, parent)))
|
||||
return hr;
|
||||
|
||||
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
|
||||
{
|
||||
switch (MAKE_IDTYPE(chunk.id, chunk.type))
|
||||
{
|
||||
case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INFO_LIST):
|
||||
/* already parsed by dmobj_parsedescriptor */
|
||||
break;
|
||||
|
||||
case MAKE_IDTYPE(FOURCC_LIST, mmioFOURCC('s','d','t','a')):
|
||||
hr = parse_sdta_list(This, stream, &chunk, &soundfont);
|
||||
break;
|
||||
|
||||
case MAKE_IDTYPE(FOURCC_LIST, mmioFOURCC('p','d','t','a')):
|
||||
hr = parse_pdta_list(This, stream, &chunk, &soundfont);
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) break;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
TRACE("presets:\n");
|
||||
for (i = 0; i < soundfont.preset_count; i++)
|
||||
{
|
||||
struct sf_preset *preset = soundfont.phdr + i;
|
||||
|
||||
TRACE("preset[%u]:\n", i);
|
||||
TRACE(" - name: %s\n", debugstr_a(preset->name));
|
||||
TRACE(" - preset: %u\n", preset->preset);
|
||||
TRACE(" - bank: %u\n", preset->bank);
|
||||
TRACE(" - preset_bag_ndx: %u\n", preset->bag_ndx);
|
||||
TRACE(" - library: %lu\n", preset->library);
|
||||
TRACE(" - genre: %lu\n", preset->genre);
|
||||
TRACE(" - morphology: %#lx\n", preset->morphology);
|
||||
|
||||
for (j = preset->bag_ndx; j < (preset + 1)->bag_ndx; j++)
|
||||
{
|
||||
struct sf_bag *bag = soundfont.pbag + j;
|
||||
TRACE(" - bag[%u]:\n", j);
|
||||
TRACE(" - gen_ndx: %u\n", bag->gen_ndx);
|
||||
TRACE(" - mod_ndx: %u\n", bag->mod_ndx);
|
||||
|
||||
for (k = bag->gen_ndx; k < (bag + 1)->gen_ndx; k++)
|
||||
{
|
||||
struct sf_gen *gen = soundfont.pgen + k;
|
||||
TRACE(" - gen[%u]: %s\n", k, debugstr_sf_gen(gen));
|
||||
}
|
||||
|
||||
for (k = bag->mod_ndx; k < (bag + 1)->mod_ndx; k++)
|
||||
{
|
||||
struct sf_mod *mod = soundfont.pmod + k;
|
||||
TRACE(" - mod[%u]: %s\n", k, debugstr_sf_mod(mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("instruments:\n");
|
||||
for (i = 0; i < soundfont.instrument_count; i++)
|
||||
{
|
||||
struct sf_instrument *instrument = soundfont.inst + i;
|
||||
TRACE("instrument[%u]:\n", i);
|
||||
TRACE(" - name: %s\n", debugstr_a(instrument->name));
|
||||
TRACE(" - bag_ndx: %u\n", instrument->bag_ndx);
|
||||
|
||||
for (j = instrument->bag_ndx; j < (instrument + 1)->bag_ndx; j++)
|
||||
{
|
||||
struct sf_bag *bag = soundfont.ibag + j;
|
||||
TRACE(" - bag[%u]:\n", j);
|
||||
TRACE(" - wGenNdx: %u\n", bag->gen_ndx);
|
||||
TRACE(" - wModNdx: %u\n", bag->mod_ndx);
|
||||
|
||||
for (k = bag->gen_ndx; k < (bag + 1)->gen_ndx; k++)
|
||||
{
|
||||
struct sf_gen *gen = soundfont.igen + k;
|
||||
TRACE(" - gen[%u]: %s\n", k, debugstr_sf_gen(gen));
|
||||
}
|
||||
|
||||
for (k = bag->mod_ndx; k < (bag + 1)->mod_ndx; k++)
|
||||
{
|
||||
struct sf_mod *mod = soundfont.imod + k;
|
||||
TRACE(" - mod[%u]: %s\n", k, debugstr_sf_mod(mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("samples:\n");
|
||||
for (i = 0; i < soundfont.sample_count; i++)
|
||||
{
|
||||
struct sf_sample *sample = soundfont.shdr + i;
|
||||
|
||||
TRACE("sample[%u]:\n", i);
|
||||
TRACE(" - name: %s\n", debugstr_a(sample->name));
|
||||
TRACE(" - start: %lu\n", sample->start);
|
||||
TRACE(" - end: %lu\n", sample->end);
|
||||
TRACE(" - start_loop: %lu\n", sample->start_loop);
|
||||
TRACE(" - end_loop: %lu\n", sample->end_loop);
|
||||
TRACE(" - sample_rate: %lu\n", sample->sample_rate);
|
||||
TRACE(" - original_key: %u\n", sample->original_key);
|
||||
TRACE(" - correction: %d\n", sample->correction);
|
||||
TRACE(" - sample_link: %#x\n", sample->sample_link);
|
||||
TRACE(" - sample_type: %#x\n", sample->sample_type);
|
||||
}
|
||||
}
|
||||
|
||||
free(soundfont.phdr);
|
||||
free(soundfont.pbag);
|
||||
free(soundfont.pmod);
|
||||
free(soundfont.pgen);
|
||||
free(soundfont.inst);
|
||||
free(soundfont.ibag);
|
||||
free(soundfont.imod);
|
||||
free(soundfont.igen);
|
||||
free(soundfont.shdr);
|
||||
free(soundfont.sdta);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface,
|
||||
IStream *stream, DMUS_OBJECTDESC *desc)
|
||||
{
|
||||
|
@ -366,7 +607,7 @@ static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *ifac
|
|||
|
||||
if ((hr = stream_get_chunk(stream, &riff)) != S_OK)
|
||||
return hr;
|
||||
if (riff.id != FOURCC_RIFF || riff.type != FOURCC_DLS) {
|
||||
if (riff.id != FOURCC_RIFF || (riff.type != FOURCC_DLS && riff.type != mmioFOURCC('s','f','b','k'))) {
|
||||
TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff));
|
||||
stream_skip_chunk(stream, &riff);
|
||||
return DMUS_E_NOTADLSCOL;
|
||||
|
@ -410,6 +651,10 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str
|
|||
hr = parse_dls_chunk(This, stream, &chunk);
|
||||
break;
|
||||
|
||||
case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('s','f','b','k')):
|
||||
hr = parse_sfbk_chunk(This, stream, &chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN("Invalid collection chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
|
||||
hr = DMUS_E_UNSUPPORTED_STREAM;
|
||||
|
@ -439,7 +684,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str
|
|||
}
|
||||
|
||||
TRACE(" - cues:\n");
|
||||
for (i = 0; i < This->pool->table.cCues; i++)
|
||||
for (i = 0; This->pool && i < This->pool->table.cCues; i++)
|
||||
TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset);
|
||||
|
||||
TRACE(" - waves:\n");
|
||||
|
|
323
dlls/dmusic/soundfont.h
Normal file
323
dlls/dmusic/soundfont.h
Normal file
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* Copyright 2023 Rémi Bernon for CodeWeavers
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "stdarg.h"
|
||||
#include "stddef.h"
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
/* SoundFont 2.04 data structures, from http://www.synthfont.com/sfspec24.pdf */
|
||||
|
||||
struct sf_range
|
||||
{
|
||||
BYTE low;
|
||||
BYTE high;
|
||||
};
|
||||
|
||||
union sf_amount
|
||||
{
|
||||
struct sf_range range;
|
||||
WORD value;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(union sf_amount) == 2);
|
||||
|
||||
enum
|
||||
{
|
||||
SF_SAMPLE_MONO = 1,
|
||||
SF_SAMPLE_RIGHT = 2,
|
||||
SF_SAMPLE_LEFT = 4,
|
||||
SF_SAMPLE_LINKED = 8,
|
||||
SF_SAMPLE_ROM_MONO = 0x8001,
|
||||
SF_SAMPLE_ROM_RIGHT = 0x8002,
|
||||
SF_SAMPLE_ROM_LEFT = 0x8004,
|
||||
SF_SAMPLE_ROM_LINKED = 0x8008,
|
||||
};
|
||||
typedef WORD sf_sample_type;
|
||||
|
||||
enum
|
||||
{
|
||||
SF_GEN_START_ADDRS_OFFSET = 0,
|
||||
SF_GEN_END_ADDRS_OFFSET = 1,
|
||||
SF_GEN_STARTLOOP_ADDRS_OFFSET = 2,
|
||||
SF_GEN_ENDLOOP_ADDRS_OFFSET = 3,
|
||||
SF_GEN_START_ADDRS_COARSE_OFFSET = 4,
|
||||
SF_GEN_MOD_LFO_TO_PITCH = 5,
|
||||
SF_GEN_VIB_LFO_TO_PITCH = 6,
|
||||
SF_GEN_MOD_ENV_TO_PITCH = 7,
|
||||
SF_GEN_INITIAL_FILTER_FC = 8,
|
||||
SF_GEN_INITIAL_FILTER_Q = 9,
|
||||
SF_GEN_MOD_LFO_TO_FILTER_FC = 10,
|
||||
SF_GEN_MOD_ENV_TO_FILTER_FC = 11,
|
||||
SF_GEN_END_ADDRS_COARSE_OFFSET = 12,
|
||||
SF_GEN_MOD_LFO_TO_VOLUME = 13,
|
||||
|
||||
SF_GEN_CHORUS_EFFECTS_SEND = 15,
|
||||
SF_GEN_REVERB_EFFECTS_SEND = 16,
|
||||
SF_GEN_PAN = 17,
|
||||
|
||||
SF_GEN_DELAY_MOD_LFO = 21,
|
||||
SF_GEN_FREQ_MOD_LFO = 22,
|
||||
SF_GEN_DELAY_VIB_LFO = 23,
|
||||
SF_GEN_FREQ_VIB_LFO = 24,
|
||||
SF_GEN_DELAY_MOD_ENV = 25,
|
||||
SF_GEN_ATTACK_MOD_ENV = 26,
|
||||
SF_GEN_HOLD_MOD_ENV = 27,
|
||||
SF_GEN_DECAY_MOD_ENV = 28,
|
||||
SF_GEN_SUSTAIN_MOD_ENV = 29,
|
||||
SF_GEN_RELEASE_MOD_ENV = 30,
|
||||
SF_GEN_KEYNUM_TO_MOD_ENV_HOLD = 31,
|
||||
SF_GEN_KEYNUM_TO_MOD_ENV_DECAY = 32,
|
||||
SF_GEN_DELAY_VOL_ENV = 33,
|
||||
SF_GEN_ATTACK_VOL_ENV = 34,
|
||||
SF_GEN_HOLD_VOL_ENV = 35,
|
||||
SF_GEN_DECAY_VOL_ENV = 36,
|
||||
SF_GEN_SUSTAIN_VOL_ENV = 37,
|
||||
SF_GEN_RELEASE_VOL_ENV = 38,
|
||||
SF_GEN_KEYNUM_TO_VOL_ENV_HOLD = 39,
|
||||
SF_GEN_KEYNUM_TO_VOL_ENV_DECAY = 40,
|
||||
SF_GEN_INSTRUMENT = 41,
|
||||
|
||||
SF_GEN_KEY_RANGE = 43,
|
||||
SF_GEN_VEL_RANGE = 44,
|
||||
SF_GEN_STARTLOOP_ADDRS_COARSE_OFFSET = 45,
|
||||
SF_GEN_KEYNUM = 46,
|
||||
SF_GEN_VELOCITY = 47,
|
||||
SF_GEN_INITIAL_ATTENUATION = 48,
|
||||
|
||||
SF_GEN_ENDLOOP_ADDRS_COARSE_OFFSET = 50,
|
||||
SF_GEN_COARSE_TUNE = 51,
|
||||
SF_GEN_FINE_TUNE = 52,
|
||||
SF_GEN_SAMPLE_ID = 53,
|
||||
SF_GEN_SAMPLE_MODES = 54,
|
||||
|
||||
SF_GEN_SCALE_TUNING = 56,
|
||||
SF_GEN_EXCLUSIVE_CLASS = 57,
|
||||
SF_GEN_OVERRIDING_ROOT_KEY = 58,
|
||||
|
||||
SF_GEN_END_OPER = 60,
|
||||
};
|
||||
typedef WORD sf_generator;
|
||||
|
||||
static inline const char *debugstr_sf_generator(sf_generator oper)
|
||||
{
|
||||
switch (oper)
|
||||
{
|
||||
case SF_GEN_START_ADDRS_OFFSET: return "start_addrs_offset";
|
||||
case SF_GEN_END_ADDRS_OFFSET: return "end_addrs_offset";
|
||||
case SF_GEN_STARTLOOP_ADDRS_OFFSET: return "startloop_addrs_offset";
|
||||
case SF_GEN_ENDLOOP_ADDRS_OFFSET: return "endloop_addrs_offset";
|
||||
case SF_GEN_START_ADDRS_COARSE_OFFSET: return "start_addrs_coarse_offset";
|
||||
case SF_GEN_MOD_LFO_TO_PITCH: return "mod_lfo_to_pitch";
|
||||
case SF_GEN_VIB_LFO_TO_PITCH: return "vib_lfo_to_pitch";
|
||||
case SF_GEN_MOD_ENV_TO_PITCH: return "mod_env_to_pitch";
|
||||
case SF_GEN_INITIAL_FILTER_FC: return "initial_filter_fc";
|
||||
case SF_GEN_INITIAL_FILTER_Q: return "initial_filter_q";
|
||||
case SF_GEN_MOD_LFO_TO_FILTER_FC: return "mod_lfo_to_filter_fc";
|
||||
case SF_GEN_MOD_ENV_TO_FILTER_FC: return "mod_env_to_filter_fc";
|
||||
case SF_GEN_END_ADDRS_COARSE_OFFSET: return "end_addrs_coarse_offset";
|
||||
case SF_GEN_MOD_LFO_TO_VOLUME: return "mod_lfo_to_volume";
|
||||
case SF_GEN_CHORUS_EFFECTS_SEND: return "chorus_effects_send";
|
||||
case SF_GEN_REVERB_EFFECTS_SEND: return "reverb_effects_send";
|
||||
case SF_GEN_PAN: return "pan";
|
||||
case SF_GEN_DELAY_MOD_LFO: return "delay_mod_lfo";
|
||||
case SF_GEN_FREQ_MOD_LFO: return "freq_mod_lfo";
|
||||
case SF_GEN_DELAY_VIB_LFO: return "delay_vib_lfo";
|
||||
case SF_GEN_FREQ_VIB_LFO: return "freq_vib_lfo";
|
||||
case SF_GEN_DELAY_MOD_ENV: return "delay_mod_env";
|
||||
case SF_GEN_ATTACK_MOD_ENV: return "attack_mod_env";
|
||||
case SF_GEN_HOLD_MOD_ENV: return "hold_mod_env";
|
||||
case SF_GEN_DECAY_MOD_ENV: return "decay_mod_env";
|
||||
case SF_GEN_SUSTAIN_MOD_ENV: return "sustain_mod_env";
|
||||
case SF_GEN_RELEASE_MOD_ENV: return "release_mod_env";
|
||||
case SF_GEN_KEYNUM_TO_MOD_ENV_HOLD: return "keynum_to_mod_env_hold";
|
||||
case SF_GEN_KEYNUM_TO_MOD_ENV_DECAY: return "keynum_to_mod_env_decay";
|
||||
case SF_GEN_DELAY_VOL_ENV: return "delay_vol_env";
|
||||
case SF_GEN_ATTACK_VOL_ENV: return "attack_vol_env";
|
||||
case SF_GEN_HOLD_VOL_ENV: return "hold_vol_env";
|
||||
case SF_GEN_DECAY_VOL_ENV: return "decay_vol_env";
|
||||
case SF_GEN_SUSTAIN_VOL_ENV: return "sustain_vol_env";
|
||||
case SF_GEN_RELEASE_VOL_ENV: return "release_vol_env";
|
||||
case SF_GEN_KEYNUM_TO_VOL_ENV_HOLD: return "keynum_to_vol_env_hold";
|
||||
case SF_GEN_KEYNUM_TO_VOL_ENV_DECAY: return "keynum_to_vol_env_decay";
|
||||
case SF_GEN_INSTRUMENT: return "instrument";
|
||||
case SF_GEN_KEY_RANGE: return "key_range";
|
||||
case SF_GEN_VEL_RANGE: return "vel_range";
|
||||
case SF_GEN_STARTLOOP_ADDRS_COARSE_OFFSET: return "startloop_addrs_coarse_offset";
|
||||
case SF_GEN_KEYNUM: return "keynum";
|
||||
case SF_GEN_VELOCITY: return "velocity";
|
||||
case SF_GEN_INITIAL_ATTENUATION: return "initial_attenuation";
|
||||
case SF_GEN_ENDLOOP_ADDRS_COARSE_OFFSET: return "endloop_addrs_coarse_offset";
|
||||
case SF_GEN_COARSE_TUNE: return "coarse_tune";
|
||||
case SF_GEN_FINE_TUNE: return "fine_tune";
|
||||
case SF_GEN_SAMPLE_ID: return "sample_id";
|
||||
case SF_GEN_SAMPLE_MODES: return "sample_modes";
|
||||
case SF_GEN_SCALE_TUNING: return "scale_tuning";
|
||||
case SF_GEN_EXCLUSIVE_CLASS: return "exclusive_class";
|
||||
case SF_GEN_OVERRIDING_ROOT_KEY: return "overriding_root_key";
|
||||
case SF_GEN_END_OPER: return "end_oper";
|
||||
}
|
||||
|
||||
return wine_dbg_sprintf("%u", oper);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
/* sf_modulator is a set of flags ored together */
|
||||
|
||||
SF_MOD_CTRL_GEN_NONE = 0,
|
||||
SF_MOD_CTRL_GEN_VELOCITY = 0x2,
|
||||
SF_MOD_CTRL_GEN_KEY = 0x3,
|
||||
SF_MOD_CTRL_GEN_POLY_PRESSURE = 0xa,
|
||||
SF_MOD_CTRL_GEN_CHAN_PRESSURE = 0xd,
|
||||
SF_MOD_CTRL_GEN_PITCH_WHEEL = 0xe,
|
||||
SF_MOD_CTRL_GEN_PITCH_WHEEL_SENSITIVITY = 0x10,
|
||||
SF_MOD_CTRL_GEN_LINK = 0x7f,
|
||||
|
||||
SF_MOD_CTRL_GEN = 0 << 7,
|
||||
SF_MOD_CTRL_MIDI = 1 << 7, /* with LSB: MIDI CC */
|
||||
|
||||
SF_MOD_DIR_INCREASING = 0 << 8,
|
||||
SF_MOD_DIR_DECREASING = 1 << 8,
|
||||
|
||||
SF_MOD_POL_UNIPOLAR = 0 << 9,
|
||||
SF_MOD_POL_BIPOLAR = 1 << 9,
|
||||
|
||||
SF_MOD_SRC_LINEAR = 0 << 10,
|
||||
SF_MOD_SRC_CONCAVE = 1 << 10,
|
||||
SF_MOD_SRC_CONVEX = 2 << 10,
|
||||
SF_MOD_SRC_SWITCH = 3 << 10,
|
||||
};
|
||||
typedef WORD sf_modulator;
|
||||
|
||||
enum
|
||||
{
|
||||
SF_TRAN_LINEAR = 0,
|
||||
SF_TRAN_ABSOLUTE = 2,
|
||||
};
|
||||
typedef WORD sf_transform;
|
||||
|
||||
struct sf_preset /* <phdr-rec> */
|
||||
{
|
||||
char name[20];
|
||||
WORD preset;
|
||||
WORD bank;
|
||||
WORD bag_ndx;
|
||||
DWORD library;
|
||||
DWORD genre;
|
||||
DWORD morphology;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct sf_preset) == 38);
|
||||
|
||||
struct sf_bag /* <pbag-rec> / <ibag-rec> */
|
||||
{
|
||||
WORD gen_ndx;
|
||||
WORD mod_ndx;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct sf_bag) == 4);
|
||||
|
||||
struct sf_mod /* <pmod-rec> / <imod-rec> */
|
||||
{
|
||||
sf_modulator src_mod;
|
||||
sf_generator dest_gen;
|
||||
SHORT amount;
|
||||
sf_modulator amount_src_mod;
|
||||
sf_transform transform;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct sf_mod) == 10);
|
||||
|
||||
static inline const char *debugstr_sf_mod(struct sf_mod *mod)
|
||||
{
|
||||
const char *dest_name = debugstr_sf_generator(mod->dest_gen);
|
||||
return wine_dbg_sprintf("%#x x %#x -> %s: %d (%#x)", mod->src_mod, mod->amount_src_mod, dest_name, mod->amount, mod->transform);
|
||||
}
|
||||
|
||||
struct sf_gen /* <pgen-rec> / <igen-rec> */
|
||||
{
|
||||
sf_generator oper;
|
||||
union sf_amount amount;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct sf_gen) == 4);
|
||||
|
||||
static inline const char *debugstr_sf_gen(struct sf_gen *gen)
|
||||
{
|
||||
const char *name = debugstr_sf_generator(gen->oper);
|
||||
|
||||
switch (gen->oper)
|
||||
{
|
||||
case SF_GEN_KEY_RANGE:
|
||||
case SF_GEN_VEL_RANGE:
|
||||
return wine_dbg_sprintf("%s: %u-%u", name, gen->amount.range.low, gen->amount.range.high);
|
||||
default:
|
||||
return wine_dbg_sprintf("%s: %u", name, gen->amount.value);
|
||||
}
|
||||
}
|
||||
|
||||
struct sf_instrument /* <inst-rec> */
|
||||
{
|
||||
char name[20];
|
||||
WORD bag_ndx;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct sf_instrument) == 22);
|
||||
|
||||
struct sf_sample /* <shdr-rec> */
|
||||
{
|
||||
char name[20];
|
||||
DWORD start;
|
||||
DWORD end;
|
||||
DWORD start_loop;
|
||||
DWORD end_loop;
|
||||
DWORD sample_rate;
|
||||
BYTE original_key;
|
||||
char correction;
|
||||
WORD sample_link;
|
||||
sf_sample_type sample_type;
|
||||
};
|
||||
|
||||
C_ASSERT(sizeof(struct sf_sample) == 46);
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
struct soundfont
|
||||
{
|
||||
UINT preset_count;
|
||||
struct sf_preset *phdr;
|
||||
struct sf_bag *pbag;
|
||||
struct sf_mod *pmod;
|
||||
struct sf_gen *pgen;
|
||||
|
||||
UINT instrument_count;
|
||||
struct sf_instrument *inst;
|
||||
struct sf_bag *ibag;
|
||||
struct sf_mod *imod;
|
||||
struct sf_gen *igen;
|
||||
|
||||
UINT sample_count;
|
||||
struct sf_sample *shdr;
|
||||
BYTE *sdta;
|
||||
};
|
|
@ -1608,7 +1608,7 @@ static void test_default_gm_collection(void)
|
|||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicCollection, (void **)&collection);
|
||||
todo_wine ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
for (i = 0; hr == S_OK && i < ARRAY_SIZE(results); i++)
|
||||
{
|
||||
|
@ -1618,7 +1618,7 @@ static void test_default_gm_collection(void)
|
|||
results[i].name, ARRAY_SIZE(results[i].name));
|
||||
}
|
||||
if (hr == S_FALSE) i--;
|
||||
todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
|
||||
ok(hr == S_FALSE, "got %#lx\n", hr);
|
||||
todo_wine ok(i > 0, "got %lu\n", i);
|
||||
todo_wine ok(i == ARRAY_SIZE(expected), "got %lu\n", i);
|
||||
|
||||
|
@ -1633,7 +1633,7 @@ static void test_default_gm_collection(void)
|
|||
winetest_pop_context();
|
||||
}
|
||||
|
||||
if (hr == S_FALSE) IDirectMusicCollection_Release(collection);
|
||||
IDirectMusicCollection_Release(collection);
|
||||
IDirectMusicLoader_Release(loader);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue