static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DownloadInstrument(LPDIRECTMUSICPORT iface, IDirectMusicInstrument* instrument, IDirectMusicDownloadedInstrument** downloaded_instrument, DMUS_NOTERANGE* note_ranges, DWORD num_note_ranges) { SynthPortImpl *This = impl_from_SynthPortImpl_IDirectMusicPort(iface); IDirectMusicInstrumentImpl *instrument_object; HRESULT ret; BOOL free; HANDLE download; DMUS_DOWNLOADINFO *info; DMUS_OFFSETTABLE *offset_table; DMUS_INSTRUMENT *instrument_info; BYTE *data; ULONG offset; ULONG nb_regions; ULONG size; ULONG i; TRACE("(%p/%p)->(%p, %p, %p, %d)\n", iface, This, instrument, downloaded_instrument, note_ranges, num_note_ranges); if (!instrument || !downloaded_instrument || (num_note_ranges && !note_ranges)) return E_POINTER; instrument_object = impl_from_IDirectMusicInstrument(instrument); nb_regions = instrument_object->header.cRegions; size = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions) + sizeof(DMUS_INSTRUMENT) + sizeof(DMUS_REGION) * nb_regions; data = HeapAlloc(GetProcessHeap(), 0, size); if (!data) return E_OUTOFMEMORY; info = (DMUS_DOWNLOADINFO*)data; offset_table = (DMUS_OFFSETTABLE*)(data + sizeof(DMUS_DOWNLOADINFO)); offset = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions); info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2; info->dwDLId = 0; info->dwNumOffsetTableEntries = 1 + instrument_object->header.cRegions; info->cbSize = size; offset_table->ulOffsetTable[0] = offset; instrument_info = (DMUS_INSTRUMENT*)(data + offset); offset += sizeof(DMUS_INSTRUMENT); instrument_info->ulPatch = MIDILOCALE2Patch(&instrument_object->header.Locale); instrument_info->ulFirstRegionIdx = 1; instrument_info->ulGlobalArtIdx = 0; /* FIXME */ instrument_info->ulFirstExtCkIdx = 0; /* FIXME */ instrument_info->ulCopyrightIdx = 0; /* FIXME */ instrument_info->ulFlags = 0; /* FIXME */ for (i = 0; i < nb_regions; i++) { DMUS_REGION *region = (DMUS_REGION*)(data + offset); offset_table->ulOffsetTable[1 + i] = offset; offset += sizeof(DMUS_REGION); region->RangeKey = instrument_object->regions[i].header.RangeKey; region->RangeVelocity = instrument_object->regions[i].header.RangeVelocity; region->fusOptions = instrument_object->regions[i].header.fusOptions; region->usKeyGroup = instrument_object->regions[i].header.usKeyGroup; region->ulRegionArtIdx = 0; /* FIXME */ region->ulNextRegionIdx = i != (nb_regions - 1) ? (i + 2) : 0; region->ulFirstExtCkIdx = 0; /* FIXME */ region->WaveLink = instrument_object->regions[i].wave_link; region->WSMP = instrument_object->regions[i].wave_sample; region->WLOOP[0] = instrument_object->regions[i].wave_loop; } ret = IDirectMusicSynth8_Download(This->synth, &download, (VOID*)data, &free); if (SUCCEEDED(ret)) ret = DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(downloaded_instrument); if (SUCCEEDED(ret)) { IDirectMusicDownloadedInstrumentImpl *downloaded_object = impl_from_IDirectMusicDownloadedInstrument(*downloaded_instrument); downloaded_object->data = data; downloaded_object->downloaded = TRUE; } *downloaded_instrument = NULL; HeapFree(GetProcessHeap(), 0, data); return E_FAIL; }
/* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream) { IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); HRESULT hr; DMUS_PRIVATE_CHUNK chunk; ULONG i = 0; ULONG length = This->length; TRACE("(%p, %p): offset = 0x%s, length = %u)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart), This->length); if (This->loaded) return S_OK; hr = IStream_Seek(stream, This->liInstrumentPosition, STREAM_SEEK_SET, NULL); if (FAILED(hr)) { WARN("IStream_Seek failed: %08x\n", hr); return DMUS_E_UNSUPPORTED_STREAM; } This->regions = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->regions) * This->header.cRegions); if (!This->regions) return E_OUTOFMEMORY; while (length) { hr = read_from_stream(stream, &chunk, sizeof(chunk)); if (FAILED(hr)) goto error; length = subtract_bytes(length, sizeof(chunk) + chunk.dwSize); switch (chunk.fccID) { case FOURCC_INSH: case FOURCC_DLID: TRACE("Chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); /* Instrument header and id are already set so just skip */ hr = advance_stream(stream, chunk.dwSize); if (FAILED(hr)) goto error; break; case FOURCC_LIST: { DWORD size = chunk.dwSize; TRACE("LIST chunk: %u bytes\n", chunk.dwSize); hr = read_from_stream(stream, &chunk.fccID, sizeof(chunk.fccID)); if (FAILED(hr)) goto error; size = subtract_bytes(size, sizeof(chunk.fccID)); switch (chunk.fccID) { case FOURCC_LRGN: TRACE("LRGN chunk (regions list): %u bytes\n", size); while (size) { hr = read_from_stream(stream, &chunk, sizeof(chunk)); if (FAILED(hr)) goto error; if (chunk.fccID != FOURCC_LIST) { TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); goto error; } hr = read_from_stream(stream, &chunk.fccID, sizeof(chunk.fccID)); if (FAILED(hr)) goto error; if (chunk.fccID == FOURCC_RGN) { TRACE("RGN chunk (region): %u bytes\n", chunk.dwSize); hr = load_region(This, stream, &This->regions[i++], chunk.dwSize - sizeof(chunk.fccID)); } else { TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); hr = advance_stream(stream, chunk.dwSize - sizeof(chunk.fccID)); } if (FAILED(hr)) goto error; size = subtract_bytes(size, chunk.dwSize + sizeof(chunk)); } break; case FOURCC_LART: TRACE("LART chunk (articulations list): %u bytes\n", size); while (size) { hr = read_from_stream(stream, &chunk, sizeof(chunk)); if (FAILED(hr)) goto error; if (chunk.fccID == FOURCC_ART1) { TRACE("ART1 chunk (level 1 articulation): %u bytes\n", chunk.dwSize); hr = load_articulation(This, stream, chunk.dwSize); } else { TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); hr = advance_stream(stream, chunk.dwSize); } if (FAILED(hr)) goto error; size = subtract_bytes(size, chunk.dwSize + sizeof(chunk)); } break; default: TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); hr = advance_stream(stream, chunk.dwSize - sizeof(chunk.fccID)); if (FAILED(hr)) goto error; size = subtract_bytes(size, chunk.dwSize - sizeof(chunk.fccID)); break; } break; } default: TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); hr = advance_stream(stream, chunk.dwSize); if (FAILED(hr)) goto error; break; } } This->loaded = TRUE; return S_OK; error: HeapFree(GetProcessHeap(), 0, This->regions); This->regions = NULL; return DMUS_E_UNSUPPORTED_STREAM; }