Index: trunk/src/dsound/OS2DSOUND.CPP
===================================================================
--- trunk/src/dsound/OS2DSOUND.CPP	(revision 5291)
+++ trunk/src/dsound/OS2DSOUND.CPP	(revision 5292)
@@ -1,3 +1,3 @@
-/* $Id: OS2DSOUND.CPP,v 1.7 2000-05-18 20:37:08 mike Exp $ */
+/* $Id: OS2DSOUND.CPP,v 1.8 2001-03-10 06:21:06 mike Exp $ */
 
 /*
@@ -5,5 +5,6 @@
  *
  * Copyright 1998 Sander van Leeuwen
- * Copyright 2000 Michal Necasek
+ * Copyright 2000 Kevin Langman
+ * Copyright 2001 Michal Necasek
  *
  * Project Odin Software License can be found in LICENSE.TXT
@@ -18,9 +19,5 @@
 #include <string.h>
 
-
-
 #include <stdio.h> /****** DEBUGGING ********/
-
-
 
 #define INITGUID
@@ -34,6 +31,4 @@
 #include <misc.h>
 
-// TODO: primary buffer should probably created right away when creating the DSound
-// object
 // TODO: handle cooperative levels properly!!
 
@@ -60,5 +55,5 @@
    Vtbl.Initialize           = SoundInitialize;
 
-   dprintf(("DSOUND-OS2IDirectSound::OS2IDirectSound\n"));
+   dprintf(("DSOUND-OS2IDirectSound::OS2IDirectSound"));
 
    speakerConfig = DSSPEAKER_STEREO;
@@ -75,5 +70,5 @@
    if ( primary->GetLastError() != DS_OK ){
       ULONG lastErr = primary->GetLastError();
-      dprintf(("LastErr = %d\n", lastErr));
+      dprintf(("LastErr = %d", lastErr));
       delete primary;
       lastError = lastErr;
@@ -82,6 +77,7 @@
    primary->Vtbl.AddRef(primary);
 
-   dprintf(("Sound init OK\n"));
-}
+   dprintf(("Sound init OK"));
+}
+
 //******************************************************************************
 //******************************************************************************
@@ -92,9 +88,10 @@
    OS2IDirectSound::fDSExists = FALSE;
 }
+
 //******************************************************************************
 //******************************************************************************
 HRESULT WIN32API SoundQueryInterface(THIS, REFIID riid, LPVOID * ppvObj)
 {
-   dprintf(("DSOUND-OS2IDirectSound::QueryInterface\n"));
+   dprintf(("DSOUND-OS2IDirectSound::QueryInterface"));
    if (This == NULL) {
       return DSERR_INVALIDPARAM;
@@ -118,5 +115,5 @@
    OS2IDirectSound *me = (OS2IDirectSound *)This;
 
-   dprintf(("DSOUND-OS2IDirectSound::AddRef %d\n", me->Referenced+1));
+   dprintf(("DSOUND-OS2IDirectSound::AddRef %d", me->Referenced+1));
    return ++me->Referenced;
 }
@@ -128,5 +125,5 @@
    OS2IDirectSound *me = (OS2IDirectSound *)This;
 
-   dprintf(("DSOUND-OS2IDirectSound::Release %d\n", me->Referenced-1));
+   dprintf(("DSOUND-OS2IDirectSound::Release %d", me->Referenced-1));
    if (me->Referenced) {
       me->Referenced--;
@@ -146,5 +143,5 @@
 HRESULT WIN32API SoundCompact(THIS)
 {
-  dprintf(("DSOUND-OS2IDirectSound::Compact\n"));
+  dprintf(("DSOUND-OS2IDirectSound::Compact - NOP"));
   return DS_OK;
 }
@@ -160,5 +157,5 @@
    OS2IDirectSoundBuffer *sndbuf;
 
-   dprintf(("DSOUND-OS2IDirectSound::CreateSoundBuffer\n"));
+   dprintf(("DSOUND-OS2IDirectSound::CreateSoundBuffer"));
    if (me == NULL || lpDSBufferDesc == NULL || lplpDirectSoundBuffer == NULL) {
       return DSERR_INVALIDPARAM;
@@ -171,29 +168,4 @@
 
    if (lpDSBufferDesc->dwFlags & DSBCAPS_PRIMARYBUFFER) {
-
-/*
-
-      // The Primary buffer is now created by the Constructor.. This only
-      // makes sence becuse you can really only have one primary buffer and
-      // you need it before you can to do anything.
-
-      OS2PrimBuff *primbuff;
-      primbuff = new OS2PrimBuff(me, lpDSBufferDesc);
-
-      if (primbuff == NULL)
-         return DSERR_OUTOFMEMORY;
-
-      if ( primbuff->GetLastError() != DS_OK ){
-         ULONG lastErr = primbuff->GetLastError();
-
-         dprintf(("LastErr = %d\n", lastErr));
-         delete primbuff;
-         return lastErr;
-      }
-      *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)primbuff;
-      primbuff->Vtbl.AddRef(primbuff);
-      dprintf(("Created PrimBuff... Exiting Create Buffer function\n"));
-*/
-
       *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)me->primary;
       return DS_OK;
@@ -204,5 +176,5 @@
       return DSERR_OUTOFMEMORY;
    }
-   if(sndbuf->GetLastError() != DS_OK) {
+   if (sndbuf->GetLastError() != DS_OK) {
       ULONG lastErr = sndbuf->GetLastError();
       delete sndbuf;
@@ -220,5 +192,5 @@
 HRESULT WIN32API SoundGetCaps(THIS_ LPDSCAPS lpCaps)
 {
-   dprintf(("DSOUND-OS2IDirectSound::GetCaps\n"));
+   dprintf(("DSOUND-OS2IDirectSound::GetCaps"));
 
    if (lpCaps == NULL)
@@ -258,8 +230,30 @@
 //******************************************************************************
 //******************************************************************************
-HRESULT WIN32API SoundDuplicateSoundBuffer(THIS_ LPDIRECTSOUNDBUFFER, LPLPDIRECTSOUNDBUFFER )
-{
-   dprintf(("DSOUND-OS2IDirectSound::DuplicateSoundBuffer\n"));
-   return DSERR_OUTOFMEMORY;
+HRESULT WIN32API SoundDuplicateSoundBuffer(THIS_ LPDIRECTSOUNDBUFFER lpBuf, LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer)
+{
+   OS2IDirectSound *me = (OS2IDirectSound *)This;
+   OS2IDirectSoundBuffer *srcBuf = (OS2IDirectSoundBuffer*)lpBuf;
+   OS2IDirectSoundBuffer *tgtBuf;
+
+   dprintf(("DSOUND-OS2IDirectSound::DuplicateSoundBuffer (%X to %X)", lpBuf, lplpDirectSoundBuffer));
+   if (me == NULL || lpBuf == NULL || lplpDirectSoundBuffer == NULL) {
+      return DSERR_INVALIDPARAM;
+   }
+
+   tgtBuf = new OS2IDirectSoundBuffer(me, srcBuf);
+   if (tgtBuf == NULL) {
+      return DSERR_OUTOFMEMORY;
+   }
+
+   if (tgtBuf->GetLastError() != DS_OK) {
+      ULONG lastErr = tgtBuf->GetLastError();
+      delete tgtBuf;
+      return lastErr;
+   }
+   tgtBuf->Vtbl.AddRef(tgtBuf);
+
+   *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)tgtBuf;
+
+   return DS_OK;
 }
 
@@ -270,5 +264,5 @@
    OS2IDirectSound *me = (OS2IDirectSound *)This;
 
-   dprintf(("DSOUND-OS2IDirectSound::SetCooperativeLevel (to %d)\n", level));
+   dprintf(("DSOUND-OS2IDirectSound::SetCooperativeLevel (to %d)", level));
    if (me == NULL) {
      return DSERR_INVALIDPARAM;
@@ -278,4 +272,5 @@
    return DS_OK;
 }
+
 //******************************************************************************
 //******************************************************************************
@@ -284,5 +279,5 @@
    OS2IDirectSound *me = (OS2IDirectSound *)This;
 
-   dprintf(("DSOUND-OS2IDirectSound::GetSpeakerConfig\n"));
+   dprintf(("DSOUND-OS2IDirectSound::GetSpeakerConfig"));
    if (me == NULL) {
       return(DSERR_INVALIDPARAM);
@@ -299,5 +294,5 @@
    OS2IDirectSound *me = (OS2IDirectSound *)This;
 
-   dprintf(("DSOUND-OS2IDirectSound::SetSpeakerConfig %X\n", speakerCfg));
+   dprintf(("DSOUND-OS2IDirectSound::SetSpeakerConfig %X", speakerCfg));
    if (me == NULL) {
      return DSERR_INVALIDPARAM;
@@ -311,7 +306,7 @@
 HRESULT WIN32API SoundInitialize(THIS_ LPGUID)
 {
-   dprintf(("DSOUND-OS2IDirectSound::Initialize NOP\n"));
-   return DS_OK;
-}
-//******************************************************************************
-//******************************************************************************
+   dprintf(("DSOUND-OS2IDirectSound::Initialize NOP"));
+   return DS_OK;
+}
+//******************************************************************************
+//******************************************************************************
Index: trunk/src/dsound/OS2SNDBUFFER.CPP
===================================================================
--- trunk/src/dsound/OS2SNDBUFFER.CPP	(revision 5291)
+++ trunk/src/dsound/OS2SNDBUFFER.CPP	(revision 5292)
@@ -1,3 +1,3 @@
-/* $Id: OS2SNDBUFFER.CPP,v 1.9 2001-03-06 20:11:16 mike Exp $ */
+/* $Id: OS2SNDBUFFER.CPP,v 1.10 2001-03-10 06:21:06 mike Exp $ */
 
 /*
@@ -5,5 +5,5 @@
  *
  * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
- * Copyright 2000 Michal Necasek
+ * Copyright 2001 Michal Necasek
  *
  * Project Odin Software License can be found in LICENSE.TXT
@@ -50,4 +50,5 @@
         : Referenced(0), lastError(DS_OK)
 {
+   //This is the "normal" constructor
    lpVtbl = &Vtbl;
    Vtbl.AddRef               = SoundBufAddRef;
@@ -110,5 +111,4 @@
    DSpan     = 0;
    lpfxFormat= NULL;
-   lpBuffer  = NULL;
    fPlaying  = FALSE;
    fLoop     = FALSE;
@@ -135,11 +135,98 @@
    dprintf((" Buffer format: %dHz, %dbit, %d channels", lpfxFormat->nSamplesPerSec, lpfxFormat->wBitsPerSample, lpfxFormat->nChannels));
 
-   lpBuffer = (LPSTR)VirtualAlloc(0, bufferdesc.dwBufferBytes, MEM_COMMIT, PAGE_READWRITE);
-   if (lpBuffer == NULL) {
+   lpSndBuffer = (SOUNDBUF*)VirtualAlloc(0, bufferdesc.dwBufferBytes + sizeof(DWORD), MEM_COMMIT, PAGE_READWRITE);
+   if (lpSndBuffer == NULL) {
       dprintf(("VirtualAlloc failed"));
-      lpBuffer  = NULL;
+      lpSndBuffer  = NULL;
       lastError = DSERR_OUTOFMEMORY;
       return;
    }
+   lpBuffer = &(lpSndBuffer->pData[0]);
+   lpSndBuffer->dwReferences = 1;
+
+   next = dsbroot;
+   dsbroot = this;
+}
+
+//******************************************************************************
+//******************************************************************************
+OS2IDirectSoundBuffer::OS2IDirectSoundBuffer(OS2IDirectSound *DSound, OS2IDirectSoundBuffer *srcBuf)
+        : Referenced(0), lastError(DS_OK)
+{
+   //This is the constructor used for duplicating sound buffers
+   lpVtbl = &Vtbl;
+   Vtbl.AddRef               = SoundBufAddRef;
+   Vtbl.Release              = SoundBufRelease;
+   Vtbl.QueryInterface       = SoundBufQueryInterface;
+   Vtbl.GetCaps              = SoundBufGetCaps;
+   Vtbl.GetFormat            = SoundBufGetFormat;
+   Vtbl.GetVolume            = SoundBufGetVolume;
+   Vtbl.GetStatus            = SoundBufGetStatus;
+   Vtbl.GetCurrentPosition   = SoundBufGetCurrentPosition;
+   Vtbl.GetPan               = SoundBufGetPan;
+   Vtbl.GetFrequency         = SoundBufGetFrequency;
+   Vtbl.Initialize           = SoundBufInitialize;
+   Vtbl.Restore              = SoundBufRestore;
+   Vtbl.SetFormat            = SoundBufSetFormat;
+   Vtbl.SetVolume            = SoundBufSetVolume;
+   Vtbl.SetCurrentPosition   = SoundBufSetCurrentPosition;
+   Vtbl.SetPan               = SoundBufSetPan;
+   Vtbl.SetFrequency         = SoundBufSetFrequency;
+   Vtbl.Lock                 = SoundBufLock;
+   Vtbl.Unlock               = SoundBufUnlock;
+   Vtbl.Stop                 = SoundBufStop;
+   Vtbl.Play                 = SoundBufPlay;
+
+   dprintf(("DSOUND-OS2IDirectSoundBuffer::OS2IDirectSoundBuffer/Duplicate (buf=%X)", this));
+
+   if (srcBuf->fPrimary) {
+      dprintf(("Error: Cannot duplicate primary sound buffer!"));
+      lpBuffer  = NULL;
+      lastError = DSERR_INVALIDPARAM;
+      return;
+   }
+
+   // get the primary buffer from the DSound instance.
+   primary = DSound->primary;
+
+   // No need to check if primary exists - it has to (this can't be the first
+   // secondary buffer being created)
+
+   // Add a reference to the primary buffer for _every_ secondary buffer; this makes
+   // sure that as long as a secondary buffer exists the primary buffer won't get
+   // destroyed; moreover if the user didn't create  a primary buffer himself/herself,
+   // it will automatically get created and destroyed with the last secondary buffer
+   primary->Vtbl.AddRef(primary);
+
+   parentDS  = DSound;
+   writepos  = 0;
+   playpos   = 0;
+   status    = 0;
+   fLocked   = FALSE;
+   fPrimary  = FALSE;
+   volume    = srcBuf->volume;
+   DSvolume  = srcBuf->DSvolume;
+   pan       = srcBuf->pan;
+   DSpan     = srcBuf->DSpan;
+   lpBuffer  = srcBuf->lpBuffer;
+   fPlaying  = FALSE;
+   fLoop     = srcBuf->fLoop;
+   notify    = NULL;
+   memcpy(&bufferdesc, &(srcBuf->bufferdesc), sizeof(DSBUFFERDESC));
+
+   // Note: this cannot be a primary buffer - those take a different route
+
+   // frequency has to be set according to the bufer format
+   frequency = srcBuf->frequency;
+
+   lpfxFormat = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
+   memcpy(lpfxFormat,srcBuf->lpfxFormat,
+          sizeof(WAVEFORMATEX));
+
+   dprintf((" Buffer format: %dHz, %dbit, %d channels", lpfxFormat->nSamplesPerSec, lpfxFormat->wBitsPerSample, lpfxFormat->nChannels));
+
+   // Increment reference count for the buffer memory
+   lpSndBuffer  = srcBuf->lpSndBuffer;
+   lpSndBuffer->dwReferences++;
 
    next = dsbroot;
@@ -157,7 +244,10 @@
    dprintf(("DSOUND-OS2IDirectSoundBuffer::~OS2IDirectSoundBuffer (buf=%X)", this));
 
-   // free allocted memory
-   if (lpBuffer)
-      VirtualFree(lpBuffer, 0, MEM_RELEASE);
+   // free allocted memory - unless it's shared by a duplicated buffer
+   if (lpSndBuffer) {
+      lpSndBuffer->dwReferences--;
+      if (lpSndBuffer->dwReferences == 0)
+         VirtualFree(lpSndBuffer, 0, MEM_RELEASE);
+   }
 
    if (lpfxFormat)
@@ -328,5 +418,5 @@
       return DSERR_INVALIDPARAM;
    }
-   copysize = MIN(ddwSizeAllocated, (me->lpfxFormat->cbSize + sizeof(WAVEFORMATEX)));
+   copysize = min(ddwSizeAllocated, (me->lpfxFormat->cbSize + sizeof(WAVEFORMATEX)));
    memcpy(lpwfxFormat, me->lpfxFormat, copysize);
 
@@ -457,4 +547,6 @@
 {
    OS2IDirectSoundBuffer *me = (OS2IDirectSoundBuffer *)This;
+
+   ULONG ulBytesToPlay;
 
    dprintf(("DSOUND-OS2IDirectSoundBuffer::SoundBufPlay (buf=%X)", me));
Index: trunk/src/dsound/OS2SNDBUFFER.H
===================================================================
--- trunk/src/dsound/OS2SNDBUFFER.H	(revision 5291)
+++ trunk/src/dsound/OS2SNDBUFFER.H	(revision 5292)
@@ -1,3 +1,3 @@
-/* $Id: OS2SNDBUFFER.H,v 1.7 2000-05-18 20:37:09 mike Exp $ */
+/* $Id: OS2SNDBUFFER.H,v 1.8 2001-03-10 06:21:06 mike Exp $ */
 
 /*
@@ -18,4 +18,12 @@
 #define THIS_ VOID*This,
 
+// simple structure to handle duplicated buffers - the first DWORD of
+// a sound buffer contains the buffer's usage count (to prevent freeing
+// of buffers still in use)
+typedef struct _SOUNDBUF {
+    DWORD   dwReferences;
+    char    pData[1];
+} SOUNDBUF;
+
 // a forward declaration of some classes is needed here!
 class OS2IDirectSoundNotify;
@@ -31,4 +39,5 @@
 
     OS2IDirectSoundBuffer(OS2IDirectSound *DSound, const DSBUFFERDESC *lpDSBufferDesc);
+    OS2IDirectSoundBuffer(OS2IDirectSound *DSound, OS2IDirectSoundBuffer *srcBuf);
     OS2IDirectSoundBuffer() {};
     ~OS2IDirectSoundBuffer();
@@ -39,7 +48,7 @@
     inline  HRESULT       GetLastError()    { return lastError;    };
     inline  void          SetNotify(OS2IDirectSoundNotify *_notify) {
-                                    notify = _notify; };
+                          notify = _notify; };
     inline  void          Set3DBuffer(OS2IDirectSound3DBuffer *_buffer3D) {
-                                      buffer3D = _buffer3D; };
+                          buffer3D = _buffer3D; };
  private:
 
@@ -61,5 +70,6 @@
     LONG  frac;                // saved mixer position overflow
 
-    char *lpBuffer;            // sound data
+    SOUNDBUF *lpSndBuffer;     // sound data + reference count
+    char     *lpBuffer;        // actual sound data
 
     OS2IDirectSoundNotify*   notify;    // pointer to the associated Notify object (if exists)
