Author Topic: BASSWMA problem  (Read 5138 times)

Gluber

  • Posts: 7
BASSWMA problem
« on: 10 Mar '03 - 21:09 »
Hi again.

I am still working on my karaoke program, and now i have to mix the recorded voice with the playback data of the "original" song..

For a long time i just used
// Get the data.
if ( BASS_ChannelGetData(
s_decodeStream,s_inputBuffer,len ) == -1 )
in my RecordProc to get the channel data from the (!) playing WMA Stream.. now we had reports of certain "delays" using this technique
so i thought i just add WMA Stream decoding and thus,
i now create an additional stream for the mixing data in my RecordStart method:

Here is the call:

// Create decoder stream
s_decodeStream = BASS_WMA_StreamCreateFile( FALSE,(void*)playback,0,0,BASS_STREAM_DECODE );

and use this in the above "GetChannelData" call to get my mixing data.

But the BASS_GetChannelData call fails all the time...
Am i doing anything wrong here ? Or is there something else required to achieve this ? I just want to mix my record data with the decoding stream of a song ( Karaoke ).

( BTW the recording data is passed through its own decoding channel for audio effects, as some helpful guy on this forum explained to me, by the way it works great, thanks )

My problem was that using GetChannelData on a normal PLAYING wma stream had a 0.5 sec delay so that we were not able to mix correctly ( the recorded voice was displaced by 0.5 sec in the final record, rendering it unusuable )

Thanks
Bernhard Glück

Gluber

  • Posts: 7
Re: BASSWMA problem
« Reply #1 on: 10 Mar '03 - 21:10 »
By the way here is the full source code of my recordproc and my recordstart procedure and all revelant other things:

#define MIXBUFFER_SIZE 128000

static short s_mixBuffer[MIXBUFFER_SIZE];
static short s_inputBuffer[MIXBUFFER_SIZE];

void *fxstreaminput = NULL;

static DWORD CALLBACK fxstreamproc(HSTREAM handle, void *buffer, DWORD length, DWORD user)
{
     memcpy(buffer,fxstreaminput,length);
     return length;
}

static BOOL CALLBACK RecordProc( void * data,DWORD len,DWORD user )
{
     fxstreaminput      =      data;
     BASS_ChannelGetData(s_fxStream,data,len);
     
     // Clear buffers
     ZeroMemory( s_mixBuffer,MIXBUFFER_SIZE );
     ZeroMemory( s_inputBuffer,MIXBUFFER_SIZE );
     
     // Get the input sample buffer
     short * recordData = ( short * )data;
     
     // Check
     if ( len > MIXBUFFER_SIZE )
     {
           Starmaker::Native::Throw("Überlauf des Misch Puffers.");
     }

     // Half length.
     int shortLength = len / 2;

     // If we are playing back.
     if ( s_stream != 0 && s_playing )
     {
           // Get the data.
           if ( BASS_ChannelGetData( s_decodeStream,s_inputBuffer,len ) == -1 )
                 Starmaker::Native::Throw("Konnte Stream Daten nicht lesen.");

           for ( int i = 0; i < shortLength; i++ )
           {      
                 int tempVal = recordData + s_inputBuffer;
                 
                 if ( tempVal > 32767 )
                       tempVal = 32767;
                 else if ( tempVal < -32768)
                       tempVal = -32768;
                 
                 s_mixBuffer = (short)tempVal;
           }
     }
     else
     {
           for ( int i = 0; i < shortLength; i++ )
           {
                 // Just assign
                 s_mixBuffer = recordData;
           }
     }

     // Encode
     if ( !BASS_WMA_EncodeWrite( s_encoder,s_mixBuffer,len ) )
           Starmaker::Native::Throw("Konnte nicht WMA enkodieren.");

     // Set the flag to true
     s_encodeWritten = true;

     // Return
     return TRUE;
}
     
void Starmaker::Native::RecordStart(            const char * filename,
                                                                 const char * playback,
                                                                 int bitrate,
                                                                 const char * title,
                                                                 const char * author,
                                                                 const char * description )
{      
     DebugLog("Recording: %s | %s ",filename,playback );
     
     // Close first
     RecordStop();

     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,filename );

     // Create encoder
     // IF this fails and crashes, something is wrong with WMA Components
     // e.g NIMO Codec pack.
     s_encoder = BASS_WMA_EncodeOpenFile( s_freq,0,bitrate,s_string);

     if ( s_encoder == 0 )
           Starmaker::Native::Throw("Konnte WMA Encoder nicht erzeugen.");

     // Set tags
     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,title );

     BASS_WMA_EncodeSetTag( s_encoder,"Title",s_string );

     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,author );

     BASS_WMA_EncodeSetTag( s_encoder,"Author",s_string );

     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,description );

     BASS_WMA_EncodeSetTag( s_encoder,"Description",s_string );

     // Finish tags
     BASS_WMA_EncodeSetTag( s_encoder,NULL,NULL );

     // Start recording
     if ( !BASS_RecordStart( s_freq,0,RecordProc,0 ) )
           Starmaker::Native::Throw("Konnte Aufnahme nicht starten.");

     // Set flag
     s_recording = true;

     // set hte back flag
     s_encodeWritten = false;

     // Create effect stream.
     s_fxStream = BASS_StreamCreate(s_freq,BASS_STREAM_DECODE,&fxstreamproc,0);

     // Create decoder stream
     s_decodeStream = BASS_WMA_StreamCreateFile( FALSE,(void*)playback,0,0,BASS_STREAM_DECODE );

     // Set volumes ( force )
     Volume( s_playVolume,s_recordVolume );

     // Force effects
     SetEffects( s_effects );
}

Gluber

  • Posts: 7
Re: BASSWMA problem
« Reply #2 on: 11 Mar '03 - 10:03 »
By the way this system uses BASS1.8, BASSWMA1.8 and BASSFX1.1

Ian @ un4seen

  • Administrator
  • Posts: 20424
Re: BASSWMA problem
« Reply #3 on: 11 Mar '03 - 10:43 »
What is the error code (BASS_ErrorGetCode) from the BASS_GetChannelData call that fails? Also, does converting the WMA to a WAV work, using the precompiled WRITEWAV example that comes with BASSWMA?

Btw, in the "fxstream" bit, there's no need for the "fxstreaminput" stuff, due to the fact that the processing is done in-place, so the sample data is already in the buffer. See that thread again - I editted my reply a couple hours after :)

Gluber

  • Posts: 7
Re: BASSWMA problem
« Reply #4 on: 11 Mar '03 - 11:25 »
Thanks about the fxinputstream stuff, i will correct that ( Thanks for your help anyways, it is greatly appreciated )

I did some error checking, and it turns out the ERROR Code ist
BASS_ERROR_HANDLE for the BASS_GetChannelData Call.

By the way.. is the way i mix together the two streams in my record proc "Correct" or is there a "better" way ?

Thanks
Bernhard

Ian @ un4seen

  • Administrator
  • Posts: 20424
Re: BASSWMA problem
« Reply #5 on: 11 Mar '03 - 18:33 »
Quote
I did some error checking, and it turns out the ERROR Code ist
BASS_ERROR_HANDLE for the BASS_GetChannelData Call.

That suggests that the stream does not exist, ie. the BASS_WMA_StreamCreateFile call failed. Check the BASS_WMA_StreamCreateFile return value and error code.

Quote
By the way.. is the way i mix together the two streams in my record proc "Correct" or is there a "better" way ?

The way you're mixing looks ok (you may want to slightly reduce the level to avoid too much clipping), but you may have problems with the music and voice not quite being in sync.

The problem is getting the decoding WMA exactly in sync with what the user is hearing from the playing WMA - I presume you're playing the WMA at the same time, for the user to hear what they're singing along with? :)

The simplest way to do it would be to just play the WMA normally, and record from the "what you hear" type of input. That way the soundcard is doing the mixing for you, and there are no syncing problems. But then you can't apply effects to only the mic... if the syncing is ok using your current method, I'd stick with it :)

GluberNoLogin

  • Guest
Re: BASSWMA problem
« Reply #6 on: 11 Mar '03 - 20:54 »
Thanks for your response.

1. The File is correctly loaded. The strange thing is that after i removed the exception throwing and just quit the recordproc if BASS_GetChannelData failed, recording worked again ( with the stream ) and it turned out that BASS_getCHannelData only fails the FIRST time it is called, all further calls succeed.

2. Actually the sync of WMA/heard music and the actually sang song is a big problem ( thats why i introduced the seperate WMA decoding stream in addition to the playback WMA stream )
we have about 0.4 sec delay between them.

Now my question. How to activate the record inputs so that i get "everything mixed together" already ( I am willing to give up on the Effects on the voice for the ability to have absolute sync ) ....... Note that this program is also destined to run on Laptops etc....

Right now we do the following
* Check if record device is "single input"
* if it is, we activate the microphone input and set its volume
* if not we activate microphone and line in ( so that a laptop user can use the built in microphone but also plugin an external one into the line in connector
and set the volume on both.

What should i do to make it run like you suggested ?
( And have microphone open on singlein devices, as well as linein and microphone on non singlein devices )

And another thing how can one set the VOLUME of individual PLAYBACK devices with BASS ?

e.g in Windows Volume Control you have two tabs "Recording" and Playback. with the RecordInput API of BASS i can set and activate all RECORDING devise just fine.. but how to change the volume of individual PLAYBACK devices ( so that e.g microphone input is instantly heared ?


Thanks
Bernhard

Ian @ un4seen

  • Administrator
  • Posts: 20424
Re: BASSWMA problem
« Reply #7 on: 12 Mar '03 - 12:09 »
Quote
1. The File is correctly loaded. The strange thing is that after i removed the exception throwing and just quit the recordproc if BASS_GetChannelData failed, recording worked again ( with the stream ) and it turned out that BASS_getCHannelData only fails the FIRST time it is called, all further calls succeed.

Looking at it now, it's so obvious :D ... you're starting recording before creating the stream. The recording should of course only be started once everything it relies on is ready.

Quote
Now my question. How to activate the record inputs so that i get "everything mixed together" already ( I am willing to give up on the Effects on the voice for the ability to have absolute sync ) ....... Note that this program is also destined to run on Laptops etc....

It depends on what soundcard/chip is used. On Creative cards (apart from the very old ones) there's an input called "what you hear", other manufacturers usually call it something like "stereo mix". You'd select that input (instead of mic/line-in). With cards that allow multiple inputs to be selected, there may be a "wave/pcm" input which you could enable, along with the mic/line-in.

One of these options will be available with the vast majority of the soundcards.

Quote
And another thing how can one set the VOLUME of individual PLAYBACK devices with BASS ?

e.g in Windows Volume Control you have two tabs "Recording" and Playback. with the RecordInput API of BASS i can set and activate all RECORDING devise just fine.. but how to change the volume of individual PLAYBACK devices ( so that e.g microphone input is instantly heared ?

You can adjust the volume of the BASS output, with BASS_SetVolume, but I'm afraid BASS will not adjust other "playback" levels for you.

Gluber

  • Posts: 7
Re: BASSWMA problem
« Reply #8 on: 13 Mar '03 - 20:00 »
I have one question remaining.

We discussed today the problems with our publisher , and i came up with a theoretical solution for the WMA delays..

What if we used Vorbis OGG for decoding ( all SONGS on the CD are in OGG format, and the program decodes from them in the s_decodeStream stream for mixing... and we only encode to WMA...

Would this solve the problems with the delays ?
The WMA output is required because our publisher wants kids to be able to record their songs, and send them to friends via email ... and almost no "casual" pc home users have OGG Dshow filters installed.... so WMA is the better choice for ENCODING...

Any thoughts ?

Ian @ un4seen

  • Administrator
  • Posts: 20424
Re: BASSWMA problem
« Reply #9 on: 13 Mar '03 - 22:15 »
I suspect the delay is most likely just down to not syncing the decoding channel with the playing channel. When do you start the playback in relation to starting the recording? Ideally, you should call BASS_StreamPlay to start the playing just before you call BASS_RecordStart to start the recording. That'll minimize any delay.

Btw, something else I just noticed... the BASS_WMA_ENCODE_TAGS flag needs to be added to your BASS_WMA_EncodeOpenFile call, to be able to set the tags.

Gluber

  • Posts: 7
Re: BASSWMA problem
« Reply #10 on: 13 Mar '03 - 22:39 »
DebugLog("Recording: %s | %s ",filename,playback );
     
     // Close first
     RecordStop();

     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,filename );

     // Create encoder
     // IF this fails and crashes, something is wrong with WMA Components
     // e.g NIMO Codec pack.
     s_encoder = BASS_WMA_EncodeOpenFile( s_freq,BASS_WMA_ENCODE_TAGS,bitrate,s_string);

     if ( s_encoder == 0 )
           Starmaker::Native::Throw("Konnte WMA Encoder nicht erzeugen.");

     // Set tags
     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,title );

     BASS_WMA_EncodeSetTag( s_encoder,"Title",s_string );

     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,author );

     BASS_WMA_EncodeSetTag( s_encoder,"Author",s_string );

     // Zero string
     ZeroMemory( s_string,255 );
     strcpy( s_string,description );

     BASS_WMA_EncodeSetTag( s_encoder,"Description",s_string );

     // Finish tags
     BASS_WMA_EncodeSetTag( s_encoder,NULL,NULL );

     // Create effect stream.
     s_fxStream = BASS_StreamCreate(s_freq,BASS_STREAM_DECODE,&fxstreamproc,0);

     // Create decoder stream
     s_decodeStream = BASS_WMA_StreamCreateFile( FALSE,(void*)playback,0,0,BASS_STREAM_DECODE );

     // Start recording
     if ( !BASS_RecordStart( s_freq,0,RecordProc,0 ) )
           Starmaker::Native::Throw("Konnte Aufnahme nicht starten.");

     // Set flag
     s_recording = true;

     // set hte back flag
     s_encodeWritten = false;

     // Set volumes ( force )
     DebugLog("Volume for recording set: %u %u",s_playVolume,s_recordVolume );
     Volume( s_playVolume,s_recordVolume );

     // Force effects
     SetEffects( s_effects );

here is the relevant code. The WMA Stream is created just before RecordStart... it is never played since its decode only stream and i access its content ONLY by using GetChannelData in my record proc...... so where are the delay coming from ?


Ian @ un4seen

  • Administrator
  • Posts: 20424
Re: BASSWMA problem
« Reply #11 on: 14 Mar '03 - 13:05 »
Quote
The WMA Stream is created just before RecordStart... it is never played since its decode only stream and i access its content ONLY by using GetChannelData in my record proc

I don't mean playing the decoding channel (it's not possible :)), but surely you have another "normal" channel to play the file simultaneously? Otherwise, how does the user know what they're singing along with?