dmsynth/tests: Test DirectMusicSynth class in isolation.
And more specifically how generating samples with Render works.
This commit is contained in:
parent
a2dac48f6c
commit
ce40b4d8fc
1 changed files with 543 additions and 0 deletions
|
@ -608,6 +608,548 @@ static void test_COM_synthsink(void)
|
|||
IDirectMusicSynthSink_Release(dmss);
|
||||
}
|
||||
|
||||
struct test_sink
|
||||
{
|
||||
IDirectMusicSynthSink IDirectMusicSynthSink_iface;
|
||||
IReferenceClock IReferenceClock_iface;
|
||||
LONG refcount;
|
||||
|
||||
IReferenceClock *clock;
|
||||
IDirectMusicSynth *synth;
|
||||
REFERENCE_TIME activate_time;
|
||||
REFERENCE_TIME latency_time;
|
||||
DWORD written;
|
||||
};
|
||||
|
||||
static HRESULT WINAPI test_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI test_sink_AddRef(IDirectMusicSynthSink *iface)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
return InterlockedIncrement(&sink->refcount);
|
||||
}
|
||||
|
||||
static ULONG WINAPI test_sink_Release(IDirectMusicSynthSink *iface)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
ULONG ref = InterlockedDecrement(&sink->refcount);
|
||||
if (!ref) free(sink);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
sink->synth = synth;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_SetMasterClock(IDirectMusicSynthSink *iface, IReferenceClock *clock)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
if (sink->clock)
|
||||
IReferenceClock_Release(sink->clock);
|
||||
if ((sink->clock = clock))
|
||||
IReferenceClock_AddRef(sink->clock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_GetLatencyClock(IDirectMusicSynthSink *iface, IReferenceClock **clock)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
*clock = &sink->IReferenceClock_iface;
|
||||
IReferenceClock_AddRef(*clock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_Activate(IDirectMusicSynthSink *iface, BOOL enable)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
|
||||
if (!sink->clock)
|
||||
return DMUS_E_NO_MASTER_CLOCK;
|
||||
|
||||
IReferenceClock_GetTime(sink->clock, &sink->activate_time);
|
||||
sink->latency_time = sink->activate_time;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample, REFERENCE_TIME *time)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
WAVEFORMATEX format;
|
||||
DWORD format_size = sizeof(format);
|
||||
HRESULT hr;
|
||||
|
||||
hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
*time = sink->activate_time + ((sample * 10000) / format.nSamplesPerSec) * 1000;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME time, LONGLONG *sample)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
WAVEFORMATEX format;
|
||||
DWORD format_size = sizeof(format);
|
||||
HRESULT hr;
|
||||
|
||||
hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
*sample = (((time - sink->activate_time) / 1000) * format.nSamplesPerSec) / 10000;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_SetDirectSound(IDirectMusicSynthSink *iface, IDirectSound *dsound,
|
||||
IDirectSoundBuffer *dsound_buffer)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface, DWORD *size)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IDirectMusicSynthSinkVtbl test_sink_vtbl =
|
||||
{
|
||||
test_sink_QueryInterface,
|
||||
test_sink_AddRef,
|
||||
test_sink_Release,
|
||||
test_sink_Init,
|
||||
test_sink_SetMasterClock,
|
||||
test_sink_GetLatencyClock,
|
||||
test_sink_Activate,
|
||||
test_sink_SampleToRefTime,
|
||||
test_sink_RefTimeToSample,
|
||||
test_sink_SetDirectSound,
|
||||
test_sink_GetDesiredBufferSize,
|
||||
};
|
||||
|
||||
static HRESULT WINAPI test_sink_latency_clock_QueryInterface(IReferenceClock *iface, REFIID iid, void **out)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI test_sink_latency_clock_AddRef(IReferenceClock *iface)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface);
|
||||
return IDirectMusicSynthSink_AddRef(&sink->IDirectMusicSynthSink_iface);
|
||||
}
|
||||
|
||||
static ULONG WINAPI test_sink_latency_clock_Release(IReferenceClock *iface)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface);
|
||||
return IDirectMusicSynthSink_Release(&sink->IDirectMusicSynthSink_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TIME *time)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface);
|
||||
*time = sink->latency_time;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_latency_clock_AdviseTime(IReferenceClock *iface,
|
||||
REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_latency_clock_AdvisePeriodic(IReferenceClock *iface,
|
||||
REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_sink_latency_clock_Unadvise(IReferenceClock *iface, DWORD cookie)
|
||||
{
|
||||
ok(0, "unexpected %s\n", __func__);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const IReferenceClockVtbl test_sink_latency_clock_vtbl =
|
||||
{
|
||||
test_sink_latency_clock_QueryInterface,
|
||||
test_sink_latency_clock_AddRef,
|
||||
test_sink_latency_clock_Release,
|
||||
test_sink_latency_clock_GetTime,
|
||||
test_sink_latency_clock_AdviseTime,
|
||||
test_sink_latency_clock_AdvisePeriodic,
|
||||
test_sink_latency_clock_Unadvise,
|
||||
};
|
||||
|
||||
static HRESULT test_sink_create(IDirectMusicSynthSink **out)
|
||||
{
|
||||
struct test_sink *sink;
|
||||
|
||||
*out = NULL;
|
||||
if (!(sink = calloc(1, sizeof(*sink)))) return E_OUTOFMEMORY;
|
||||
sink->IDirectMusicSynthSink_iface.lpVtbl = &test_sink_vtbl;
|
||||
sink->IReferenceClock_iface.lpVtbl = &test_sink_latency_clock_vtbl;
|
||||
sink->refcount = 1;
|
||||
|
||||
*out = &sink->IDirectMusicSynthSink_iface;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void test_sink_render(IDirectMusicSynthSink *iface, void *buffer, DWORD buffer_size, HANDLE output)
|
||||
{
|
||||
struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface);
|
||||
DWORD written, format_size;
|
||||
WAVEFORMATEX format;
|
||||
HRESULT hr;
|
||||
|
||||
format_size = sizeof(format);
|
||||
hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
memset(buffer, 0, buffer_size);
|
||||
hr = IDirectMusicSynth_Render(sink->synth, buffer, buffer_size / format.nBlockAlign, sink->written / format.nBlockAlign);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
sink->written += buffer_size;
|
||||
|
||||
hr = IDirectMusicSynthSink_SampleToRefTime(iface, sink->written / format.nBlockAlign, &sink->latency_time);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
if (output)
|
||||
{
|
||||
BOOL ret = WriteFile(output, buffer, buffer_size, &written, NULL);
|
||||
ok(!!ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
static void test_IDirectMusicSynth(void)
|
||||
{
|
||||
static const UINT RENDER_ITERATIONS = 8;
|
||||
|
||||
struct wave_download
|
||||
{
|
||||
DMUS_DOWNLOADINFO info;
|
||||
ULONG offsets[2];
|
||||
DMUS_WAVE wave;
|
||||
union
|
||||
{
|
||||
DMUS_WAVEDATA wave_data;
|
||||
struct
|
||||
{
|
||||
ULONG size;
|
||||
BYTE samples[256];
|
||||
};
|
||||
};
|
||||
} wave_download =
|
||||
{
|
||||
.info =
|
||||
{
|
||||
.dwDLType = DMUS_DOWNLOADINFO_WAVE,
|
||||
.dwDLId = 1,
|
||||
.dwNumOffsetTableEntries = 2,
|
||||
.cbSize = sizeof(struct wave_download),
|
||||
},
|
||||
.offsets =
|
||||
{
|
||||
offsetof(struct wave_download, wave),
|
||||
offsetof(struct wave_download, wave_data),
|
||||
},
|
||||
.wave =
|
||||
{
|
||||
.ulWaveDataIdx = 1,
|
||||
.WaveformatEx =
|
||||
{
|
||||
.wFormatTag = WAVE_FORMAT_PCM,
|
||||
.nChannels = 1,
|
||||
.wBitsPerSample = 8,
|
||||
.nSamplesPerSec = 44100,
|
||||
.nAvgBytesPerSec = 44100,
|
||||
.nBlockAlign = 1,
|
||||
},
|
||||
},
|
||||
.wave_data =
|
||||
{
|
||||
.cbSize = sizeof(wave_download.samples),
|
||||
},
|
||||
};
|
||||
struct instrument_download
|
||||
{
|
||||
DMUS_DOWNLOADINFO info;
|
||||
ULONG offsets[4];
|
||||
DMUS_INSTRUMENT instrument;
|
||||
DMUS_REGION region;
|
||||
DMUS_ARTICULATION articulation;
|
||||
DMUS_ARTICPARAMS artic_params;
|
||||
} instrument_download =
|
||||
{
|
||||
.info =
|
||||
{
|
||||
.dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT,
|
||||
.dwDLId = 2,
|
||||
.dwNumOffsetTableEntries = 4,
|
||||
.cbSize = sizeof(struct instrument_download),
|
||||
},
|
||||
.offsets =
|
||||
{
|
||||
offsetof(struct instrument_download, instrument),
|
||||
offsetof(struct instrument_download, region),
|
||||
offsetof(struct instrument_download, articulation),
|
||||
offsetof(struct instrument_download, artic_params),
|
||||
},
|
||||
.instrument =
|
||||
{
|
||||
.ulPatch = 0,
|
||||
.ulFirstRegionIdx = 1,
|
||||
.ulGlobalArtIdx = 2,
|
||||
},
|
||||
.region =
|
||||
{
|
||||
.RangeKey = {.usLow = 0, .usHigh = 127},
|
||||
.RangeVelocity = {.usLow = 0, .usHigh = 127},
|
||||
.fusOptions = F_RGN_OPTION_SELFNONEXCLUSIVE,
|
||||
.WaveLink = {.ulChannel = 1, .ulTableIndex = 1},
|
||||
.WSMP = {.cbSize = sizeof(WSMPL), .usUnityNote = 60, .fulOptions = F_WSMP_NO_TRUNCATION},
|
||||
.WLOOP[0] = {.cbSize = sizeof(WLOOP), .ulType = WLOOP_TYPE_FORWARD},
|
||||
},
|
||||
.articulation = {.ulArt1Idx = 3},
|
||||
.artic_params =
|
||||
{
|
||||
.VolEG = {.tcAttack = 32768u << 16, .tcDecay = 32768u << 16, .ptSustain = 10000 << 16, .tcRelease = 32768u << 16},
|
||||
},
|
||||
};
|
||||
DMUS_BUFFERDESC buffer_desc =
|
||||
{
|
||||
.dwSize = sizeof(DMUS_BUFFERDESC),
|
||||
.cbBuffer = 4096,
|
||||
};
|
||||
DMUS_PORTPARAMS port_params =
|
||||
{
|
||||
.dwSize = sizeof(DMUS_PORTPARAMS),
|
||||
.dwValidParams = DMUS_PORTPARAMS_AUDIOCHANNELS | DMUS_PORTPARAMS_SAMPLERATE,
|
||||
.dwAudioChannels = 2,
|
||||
.dwSampleRate = 44100,
|
||||
};
|
||||
WCHAR temp_path[MAX_PATH], temp_file[MAX_PATH];
|
||||
IReferenceClock *latency_clock;
|
||||
IDirectMusicSynthSink *sink;
|
||||
IDirectMusicBuffer *buffer;
|
||||
DWORD format_size, written;
|
||||
IDirectMusicSynth *synth;
|
||||
HANDLE wave_file, handle;
|
||||
IReferenceClock *clock;
|
||||
BOOL can_free = FALSE;
|
||||
REFERENCE_TIME time;
|
||||
WAVEFORMATEX format;
|
||||
IDirectMusic *music;
|
||||
short samples[256];
|
||||
ULONG i, ref;
|
||||
HRESULT hr;
|
||||
DWORD len;
|
||||
BYTE *raw;
|
||||
BOOL ret;
|
||||
|
||||
hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IDirectMusic, (void **)&music);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusic_GetMasterClock(music, NULL, &clock);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
hr = test_sink_create(&sink);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
|
||||
hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IDirectMusicSynth, (void **)&synth);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
/* SetNumChannelGroups needs Open */
|
||||
hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1);
|
||||
todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
|
||||
/* GetFormat needs Open */
|
||||
hr = IDirectMusicSynth_GetFormat(synth, NULL, NULL);
|
||||
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size);
|
||||
ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
|
||||
|
||||
/* Open / Close don't need a sink */
|
||||
hr = IDirectMusicSynth_Open(synth, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Open(synth, NULL);
|
||||
ok(hr == DMUS_E_ALREADYOPEN, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
format_size = sizeof(format);
|
||||
hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ok(format_size == sizeof(format), "got %lu\n", format_size);
|
||||
hr = IDirectMusicSynth_Close(synth);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Close(synth);
|
||||
ok(hr == DMUS_E_ALREADYCLOSED, "got %#lx\n", hr);
|
||||
|
||||
/* GetLatencyClock needs a sink */
|
||||
hr = IDirectMusicSynth_GetLatencyClock(synth, NULL);
|
||||
ok(hr == E_POINTER, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock);
|
||||
ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr);
|
||||
|
||||
/* Activate needs a sink, synth to be open, and a master clock on the sink */
|
||||
hr = IDirectMusicSynth_Open(synth, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Activate(synth, TRUE);
|
||||
ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Activate(synth, FALSE);
|
||||
todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
|
||||
|
||||
hr = IDirectMusicSynth_SetSynthSink(synth, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_SetSynthSink(synth, sink);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ref = get_refcount(sink);
|
||||
todo_wine ok(ref == 2, "got %lu\n", ref);
|
||||
hr = IDirectMusicSynth_Activate(synth, TRUE);
|
||||
todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
|
||||
|
||||
/* SetMasterClock does nothing */
|
||||
hr = IDirectMusicSynth_SetMasterClock(synth, NULL);
|
||||
todo_wine ok(hr == E_POINTER, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_SetMasterClock(synth, clock);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ref = get_refcount(clock);
|
||||
todo_wine ok(ref == 1, "got %lu\n", ref);
|
||||
hr = IDirectMusicSynth_Activate(synth, TRUE);
|
||||
todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
|
||||
|
||||
/* SetMasterClock needs to be called on the sink */
|
||||
hr = IDirectMusicSynthSink_SetMasterClock(sink, clock);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Activate(synth, TRUE);
|
||||
todo_wine ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Activate(synth, TRUE);
|
||||
todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
|
||||
|
||||
/* Close is fine while active */
|
||||
hr = IDirectMusicSynth_Close(synth);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
/* Removing the sink is fine while active */
|
||||
hr = IDirectMusicSynth_SetSynthSink(synth, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ref = get_refcount(sink);
|
||||
ok(ref == 1, "got %lu\n", ref);
|
||||
|
||||
/* but Activate might fail then */
|
||||
hr = IDirectMusicSynth_Activate(synth, FALSE);
|
||||
todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_Activate(synth, FALSE);
|
||||
todo_wine ok(hr == S_FALSE, "got %#lx\n", hr);
|
||||
|
||||
|
||||
/* Test generating some samples */
|
||||
hr = IDirectMusicSynth_Open(synth, &port_params);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
format_size = sizeof(format);
|
||||
hr = IDirectMusicSynth_GetFormat(synth, &format, &format_size);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_SetSynthSink(synth, sink);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ref = get_refcount(sink);
|
||||
todo_wine ok(ref == 2, "got %lu\n", ref);
|
||||
hr = IDirectMusicSynth_Activate(synth, TRUE);
|
||||
todo_wine ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
GetTempPathW(MAX_PATH, temp_path);
|
||||
GetTempFileNameW(temp_path, L"synth", 0, temp_file);
|
||||
wave_file = CreateFileW(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
|
||||
ok(wave_file != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu.\n", GetLastError());
|
||||
ret = WriteFile(wave_file, "RIFF", 4, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
format_size = (RENDER_ITERATIONS + 1) * sizeof(samples) + sizeof(format) + 20;
|
||||
ret = WriteFile(wave_file, &format_size, 4, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
ret = WriteFile(wave_file, "WAVEfmt ", 8, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
format_size = sizeof(format);
|
||||
ret = WriteFile(wave_file, &format_size, 4, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
ret = WriteFile(wave_file, &format, format_size, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
ret = WriteFile(wave_file, "data", 4, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
format_size = (RENDER_ITERATIONS + 1) * sizeof(samples);
|
||||
ret = WriteFile(wave_file, &format_size, 4, &written, NULL);
|
||||
ok(ret, "WriteFile failed, error %lu.\n", GetLastError());
|
||||
|
||||
/* native needs to render at least once before producing samples */
|
||||
test_sink_render(sink, samples, sizeof(samples), wave_file);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wave_download.samples); i++)
|
||||
wave_download.samples[i] = i;
|
||||
|
||||
can_free = 0xdeadbeef;
|
||||
handle = (HANDLE)0xdeadbeef;
|
||||
hr = IDirectMusicSynth_Download(synth, &handle, &wave_download, &can_free);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ok(handle != 0, "got %p\n", handle);
|
||||
todo_wine ok(can_free == FALSE, "got %u\n", can_free);
|
||||
|
||||
can_free = 0xdeadbeef;
|
||||
handle = (HANDLE)0xdeadbeef;
|
||||
hr = IDirectMusicSynth_Download(synth, &handle, &instrument_download, &can_free);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ok(handle != 0, "got %p\n", handle);
|
||||
todo_wine ok(can_free == TRUE, "got %u\n", can_free);
|
||||
|
||||
/* add a MIDI note to a buffer and play it */
|
||||
hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusic_CreateMusicBuffer(music, &buffer_desc, &buffer, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
/* status = 0x90 (NOTEON / channel 0), key = 0x27 (39), vel = 0x78 (120) */
|
||||
hr = IDirectMusicBuffer_PackStructured(buffer, 0, 1, 0x782790);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IReferenceClock_GetTime(latency_clock, &time);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicBuffer_GetRawBufferPtr(buffer, (BYTE **)&raw);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicBuffer_GetUsedBytes(buffer, &len);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_PlayBuffer(synth, time, (BYTE *)raw, len);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
IDirectMusicBuffer_Release(buffer);
|
||||
IReferenceClock_Release(latency_clock);
|
||||
|
||||
for (i = 0; i < RENDER_ITERATIONS; i++)
|
||||
test_sink_render(sink, samples, sizeof(samples), wave_file);
|
||||
|
||||
CloseHandle(wave_file);
|
||||
trace("Rendered samples to %s\n", debugstr_w(temp_file));
|
||||
|
||||
hr = IDirectMusicSynth_Activate(synth, FALSE);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicSynth_SetSynthSink(synth, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
ref = get_refcount(sink);
|
||||
ok(ref == 1, "got %lu\n", ref);
|
||||
hr = IDirectMusicSynth_Close(synth);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
IDirectMusicSynth_Release(synth);
|
||||
|
||||
|
||||
if (strcmp(winetest_platform, "wine")) IDirectMusicSynthSink_Release(sink);
|
||||
IReferenceClock_Release(clock);
|
||||
IDirectMusic_Release(music);
|
||||
}
|
||||
|
||||
static void test_IDirectMusicSynthSink(void)
|
||||
{
|
||||
IReferenceClock *latency_clock;
|
||||
|
@ -796,6 +1338,7 @@ START_TEST(dmsynth)
|
|||
test_dmsynth();
|
||||
test_COM();
|
||||
test_COM_synthsink();
|
||||
test_IDirectMusicSynth();
|
||||
test_IDirectMusicSynthSink();
|
||||
|
||||
CoUninitialize();
|
||||
|
|
Loading…
Add table
Reference in a new issue