output the same stream on two soundcards

Started by Sl@jaR,

Sl@jaR

Hi there ...

I use a wrapper class to use multiple soundcards with bass. That works pretty fine. Actually I am trying to play a stream through 2 soundcards...
The idea was to create two user streams and run them seperately through two bass instances. The one used to decode is a decoding channel and a no sound device.
It works but i get blobbs :(
Maybe someone has an idea.


DWORD PlayStream(DWORD * buf, DWORD length)
{
      DWORD ret      =      bass->ChannelGetData(stream, buf,length<bufferlength?length:bufferlength);

      if(bufid==0)
      {
            buflength = length<bufferlength?length:bufferlength;
            memcpy(oldbuf,buf,buflength);
            bufid=1;
      }
      else if(bufid==1)
      {
            buflength2 = length<bufferlength?length:bufferlength;
            memcpy(oldbuf2,buf,buflength2);
            bufid=0;
      }
     
      return length;
}

DWORD PlayStream2(DWORD * buf, DWORD length)
{
     
      if(bufid==1)
      {      
            length = length<buflength?length:buflength;
            if(oldbuf)memcpy(buf,oldbuf,length);
      }
      else if(bufid==0)
      {
            length = length<buflength2?length:buflength2;
            if(oldbuf2) memcpy(buf,oldbuf2, length);
      }
      return length;
}

Sl@jaR

last night I tried a second idea. I am playing the first stream and after that i am resetting the stream (SetPos). That work better but not perfect and it uses way too much processor power :(

Sl@jaR

I am going crazy. ??? I tried 4 different methods to solve this problem. Now I have no more ideas. My best result was one stream superb and the other one crackles :(

Save me from committing suicide :evil:

Irrational86

You have not really given the idea of what you're trying to do...

Sl@jaR

The basic idea is to play a stream on two soundcards  synchronously at the same time. I don't want to do anything else. Anyways thanx for your reply.

Ian @ un4seen

In the source above, it looks like you're getting new decoded data each time for each stream, so the data is not being played by the other stream. You need to buffer the data, so that the other stream can play it too, and only discard it once it's been used by both streams.

You should also use the BASS_ChannelGetData return value :)

Sl@jaR

Thank you for your reply. I tried this too. Actually it worked but I got crackles. The problem was when I decode the stream the buffer is filled. So if I play this buffer everything is ok. The decoding is now faster than the playing and so the buffering mechanism writes to my buffer thats currently in use. Actually I tried 3 ringbuffers but there was no difference :(
Is there any chance to decode just a specific amount of bytes? If this is possible I think doublebuffering should work.

Ian @ un4seen

You could just dynamically allocate memory as it's needed - although a bit slower, you avoid any buffer overflow problems. Here's an (untested :)) example...
char *buffer=NULL;
QWORD bufpos=0;
int buflen=0;

#define STREAMS 2
QWORD streampos[STREAMS]={0};

CRITICAL_SECTION ingetdata;

int GetData(int stream, char *streambuf, int bytes)
{
      int a;
      QWORD b=-1;
      EnterCriticalSection(&ingetdata);
// check there's enough data in buffer
      if (streampos[stream]+bytes > bufpos+buflen) {
            a=streampos[stream]+bytes-(bufpos+buflen);
            buffer=realloc(buffer, buflen+a);
            a=BASS_ChannelGetData(handle, buffer+buflen, a);
            if (a>0) buflen+=a;
      }
// copy data from buffer
      a=streampos[stream]-bufpos;
      if (bytes>buflen-a) bytes=buflen-a;
      memcpy(streambuf, buffer+a, bytes);
      streampos[stream]+=bytes;
// remove used data from buffer
      for (a=0; a<STREAMS; a++)
            if (b>streampos[a]) b=streampos[a];
      if (b>bufpos) {
            a=b-bufpos;
            bufpos=b;
            buflen-=a;
            memmove(buffer, buffer+a, buflen);
      }
      LeaveCriticalSection(&ingetdata);
      return bytes;
}
Call that from your STREAMPROC callback, and initialize the "ingetdata" critical section at startup.

Sl@jaR

Thanx for the idea. It's allmost my last one ;)
Actually your code didn't work but after 2 hours I finally got it.

!!Thanx a lot!!

Patrick


Any chance you could post how (code) you got this working.
I would very much like to know.

Thanks in advance,

Patrick