Michael Stefaniuc : dmime: Use a rbtree to store the PChannels of a performance.

Alexandre Julliard julliard at winehq.org
Fri Dec 20 14:07:23 CST 2019


Module: wine
Branch: master
Commit: 9b6a45638194fe63241dc7ff81aed3fcea3a6c81
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=9b6a45638194fe63241dc7ff81aed3fcea3a6c81

Author: Michael Stefaniuc <mstefani at winehq.org>
Date:   Thu Dec 19 23:20:18 2019 +0100

dmime: Use a rbtree to store the PChannels of a performance.

The PChannel id is a 32bit, potentially random identifier and not an
array index.
Fixes also the handling of channel group "dwGroup" 0. As it is invalid
it is used to mark uninitialized PChannels.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=17766
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=24740
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=31562
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dmime/performance.c | 109 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 75 insertions(+), 34 deletions(-)

diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c
index 615a3f8b14..2124c1fe35 100644
--- a/dlls/dmime/performance.c
+++ b/dlls/dmime/performance.c
@@ -19,10 +19,18 @@
  */
 
 #include "dmime_private.h"
+#include "wine/heap.h"
+#include "wine/rbtree.h"
 #include "dmobject.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
 
+struct pchannel_block {
+    DWORD block_num;   /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */
+    DMUSIC_PRIVATE_PCHANNEL pchannel[16];
+    struct wine_rb_entry entry;
+};
+
 typedef struct IDirectMusicPerformance8Impl {
     IDirectMusicPerformance8 IDirectMusicPerformance8_iface;
     LONG ref;
@@ -35,7 +43,7 @@ typedef struct IDirectMusicPerformance8Impl {
     float fMasterTempo;
     long lMasterVolume;
     /* performance channels */
-    DMUSIC_PRIVATE_PCHANNEL PChannel[32];
+    struct wine_rb_tree pchannels;
     /* IDirectMusicPerformance8Impl fields */
     IDirectMusicAudioPath *pDefaultPath;
     HANDLE hNotification;
@@ -192,6 +200,49 @@ static BOOL PostMessageToProcessMsgThread(IDirectMusicPerformance8Impl* This, UI
   return PostThreadMessageA(This->procThreadId, iMsg, 0, 0);
 }
 
+static int pchannel_block_compare(const void *key, const struct wine_rb_entry *entry)
+{
+    const struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct pchannel_block, entry);
+
+    return *(DWORD *)key - b->block_num;
+}
+
+static void pchannel_block_free(struct wine_rb_entry *entry, void *context)
+{
+    struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry);
+
+    heap_free(b);
+}
+
+static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWORD block_num,
+        IDirectMusicPort *port, DWORD group, BOOL only_set_new)
+{
+    struct pchannel_block *block;
+    struct wine_rb_entry *entry;
+    unsigned int i;
+
+    entry = wine_rb_get(tree, &block_num);
+    if (entry) {
+        block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry);
+        if (only_set_new)
+            return block;
+    } else {
+        if (!(block = heap_alloc(sizeof(*block))))
+            return NULL;
+        block->block_num = block_num;
+    }
+
+    for (i = 0; i < 16; ++i) {
+        block->pchannel[i].port = port;
+        block->pchannel[i].group = group;
+        block->pchannel[i].channel = i;
+    }
+    if (!entry)
+        wine_rb_put(tree, &block->block_num, &block->entry);
+
+    return block;
+}
+
 static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface)
 {
     return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface);
@@ -236,6 +287,7 @@ static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance
   TRACE("(%p): ReleaseRef to %d\n", This, ref);
   
   if (ref == 0) {
+    wine_rb_destroy(&This->pchannels, pchannel_block_free, NULL);
     This->safe.DebugInfo->Spare[0] = 0;
     DeleteCriticalSection(&This->safe);
     HeapFree(GetProcessHeap(), 0, This);
@@ -579,7 +631,6 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerforman
 	  GUID port_guid;
 	  IDirectMusicPort* pDefaultPort = NULL;
 	  DMUS_PORTPARAMS params;
-	  int i, j;
           hr = IDirectMusic8_GetDefaultPort(This->dmusic, &port_guid);
 	  if (FAILED(hr)) return hr;
 	  ZeroMemory(&params, sizeof(params)); 
@@ -591,15 +642,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerforman
 	  if (FAILED(hr)) return hr;
 	  hr = IDirectMusicPort_Activate(pDefaultPort, TRUE);
 	  if (FAILED(hr)) { IDirectMusicPort_Release(pDefaultPort); return hr; }
-	  j = 0;
-	  for (i = 0; i < 16; ++i) {
-	    if (NULL == This->PChannel[i].port) {
-	      This->PChannel[i].port = pPort; 
-	      This->PChannel[i].group = 0; 
-	      This->PChannel[i].channel = j; /* FIXME: should this be assigned? */
-	      j++;
-	    }
-	  }
+          IDirectMusicPerformance8_AssignPChannelBlock(iface, 0, pDefaultPort, 1);
 	} else {
 	  IDirectMusicPort_AddRef(pPort);	  
 	}
@@ -621,41 +664,38 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerfor
 }
 
 static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMusicPerformance8 *iface,
-        DWORD dwBlockNum, IDirectMusicPort *pPort, DWORD dwGroup)
+        DWORD block_num, IDirectMusicPort *port, DWORD group)
 {
-        IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
-	int i, j, range /* min value in range */;
-
-	FIXME("(%p, %d, %p, %d): semi-stub\n", This, dwBlockNum, pPort, dwGroup-1);
-	if (NULL == pPort) return E_POINTER;
-
-	range = 16 * dwBlockNum;
-	j = 0;
-	for (i = range; i < range+16; i++) {
-		/*TRACE("Setting PChannel[%i] to port %p, group %ld, MIDI port %i\n", i, pPort, dwGroup-1, j); */
-		This->PChannel[i].port = pPort; 
-		This->PChannel[i].group = dwGroup - 1; /* first index is always zero */
-		This->PChannel[i].channel = j; /* FIXME: should this be assigned? */
-		j++;
-	}
-	/*if (dwGroup > 2) return S_FALSE;*/
+    IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
 
-	return S_OK;
+    FIXME("(%p, %d, %p, %d): semi-stub\n", This, block_num, port, group);
+
+    if (!port)
+        return E_POINTER;
+    if (block_num > MAXDWORD / 16)
+        return E_INVALIDARG;
+
+    pchannel_block_set(&This->pchannels, block_num, port, group, FALSE);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPerformance8 *iface,
-        DWORD PChannel, IDirectMusicPort *port, DWORD group, DWORD MChannel)
+        DWORD pchannel, IDirectMusicPort *port, DWORD group, DWORD channel)
 {
     IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface);
+    struct pchannel_block *block;
 
-    TRACE("(%p)->(%d, %p, %d, %d)\n", This, PChannel, port, group, MChannel);
+    FIXME("(%p)->(%d, %p, %d, %d) semi-stub\n", This, pchannel, port, group, channel);
 
     if (!port)
         return E_POINTER;
 
-    This->PChannel[PChannel].port = port;
-    This->PChannel[PChannel].group = group;
-    This->PChannel[PChannel].channel = MChannel;
+    block = pchannel_block_set(&This->pchannels, pchannel / 16, port, 0, TRUE);
+    if (block) {
+        block->pchannel[pchannel % 16].group = group;
+        block->pchannel[pchannel % 16].channel = channel;
+    }
 
     return S_OK;
 }
@@ -1211,6 +1251,7 @@ HRESULT WINAPI create_dmperformance(REFIID lpcGUID, void **ppobj)
 	obj->pDefaultPath = NULL;
 	InitializeCriticalSection(&obj->safe);
 	obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe");
+        wine_rb_init(&obj->pchannels, pchannel_block_compare);
 
         obj->rtLatencyTime  = 100;  /* 100 ms TO FIX */
         obj->dwBumperLength =   50; /* 50 ms default */




More information about the wine-cvs mailing list