Using an AudioSampleBuffer


#1

Hi

I have a 16bit PCM wav format stream [coming from a video’s audio stream from VFW], and I have manually filled an AudioSampleBuffer doing the conversion to 32bit float as I fill it.

how do i then get that AudioSampleBuffer inserted into my chain?

I am using an AudioTransportSource plugged into a ResamplingAudioSource which is then plugged into a MixerAudioSource.

Thanks for your advice :slight_smile:


#2

You’ll have to create your own source that you will then fill up with your buffer. The easiest thing to do is useToneGeneratorAudioSource by copying its methods into your own class (just rename and get rid of the setAmplitude and setFrequency methods), then in getNextAudioBlock, copy/convert your 16bit pcm data into getNextAudioBlock’s AudioSourceChannelInfo& info.buffer rather than creating your own AudioSampleBuffer. Then you just attach that source to your chain and you’re done.

  • kbj

#3

thanks thats really usefull advice.

I’ve done what you reccomended and it very nearly works…

I get successful playback of the audio stream from the video file, except it is quite badly distorted, and a lot louder than I would expect it to be.

heres my GetNextAudioBlock() function:

void VideoStreamAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { if(streamLoaded&&streamPlaying) { pActiveVFW16bitBlockL = (short *) &ByteBuffer[CurrentReadPosition * infoAudioStream.dwScale]; pActiveVFW16bitBlockR = &pActiveVFW16bitBlockL[1]; pActiveJuceBlockL = info.buffer->getSampleData (0, info.startSample); pActiveJuceBlockR = info.buffer->getSampleData (1, info.startSample); for (int i = 0; i < info.numSamples; ++i) { *pActiveJuceBlockL = (float)*pActiveVFW16bitBlockL; *pActiveJuceBlockR = (float)*pActiveVFW16bitBlockR; pActiveVFW16bitBlockL+=2; pActiveVFW16bitBlockR+=2; pActiveJuceBlockL++; pActiveJuceBlockR++; } CurrentReadPosition += info.numSamples; //newPosition = roundDoubleToInt (newPosition * sourceSampleRate / sampleRate); } }

AudioSourceChannelInfo& info comes into the function with StartSample = 0 and numSamples = 1024 every time the function is called.

maybe I’m missing something obvious. Like I have to set the sample Rate somewhere cos its different to my source sample rate? I’m not sure where in the chain that should be set now tho.

heres the code where I instantiate my new VideoStreamAudioSource objects and connect them to my mixer

VideoStreamAudio[0] = new VideoStreamAudioSource(); mixerSource.addInputSource(VideoStreamAudio[0], false); VideoStreamAudio[1] = new VideoStreamAudioSource(); mixerSource.addInputSource(VideoStreamAudio[1], false); VideoStreamAudio[2] = new VideoStreamAudioSource(); mixerSource.addInputSource(VideoStreamAudio[2], false); VideoStreamAudio[3] = new VideoStreamAudioSource(); mixerSource.addInputSource(VideoStreamAudio[3], false);

And here is my vfw stream read function incase thats of any use?

[code]HRESULT VideoStreamAudioSource::ExtractAVIAudio(String szFileName)
{
AVIFileInit();

PAVIFILE avi;
LONG plBytes = 0; 
LONG plSamples = 0; 
int audioDataOffset = 0;

HRESULT res=AVIFileOpen(&avi, LPCTSTR(szFileName), OF_READ, NULL);

if (res!=AVIERR_OK)
{
	if (avi!=NULL)
		AVIFileRelease(avi);
	return res;
}

AVIFILEINFO avi_info;
res = AVIFileInfo(avi, &avi_info, sizeof(AVIFILEINFO));
res = AVIFileGetStream(avi, &pAVIAudioStream, streamtypeAUDIO /*Audio stream*/, 0 /*first stream*/);

if(res!=AVIERR_OK) return(res);

LONG lSize;
audioDataOffset = AVIStreamStart(pAVIAudioStream);
AVIStreamReadFormat(pAVIAudioStream, AVIStreamStart(pAVIAudioStream), NULL, &lSize);
LPBYTE pChunk = new BYTE[lSize];
if(pChunk)
	res = AVIStreamReadFormat(pAVIAudioStream, audioDataOffset, pChunk, &lSize);
if(res!=AVIERR_OK) 
	return(res);

pWaveFormat = (LPWAVEFORMATEX)pChunk;

AVIStreamInfo(pAVIAudioStream, &infoAudioStream, sizeof(infoAudioStream));

AVIStreamRead(pAVIAudioStream, 0, AVISTREAMREAD_CONVENIENT, NULL, 0, &lSize, NULL);

BufferSizeBytes = infoAudioStream.dwLength * infoAudioStream.dwScale;
ByteBuffer = new BYTE[BufferSizeBytes]; 
if(ByteBuffer) 
	res = AVIStreamRead(pAVIAudioStream, audioDataOffset, BufferSizeBytes - audioDataOffset, ByteBuffer, 
					BufferSizeBytes, &plBytes, &plSamples);
if(res==AVIERR_OK) 
{
	pAVIBufferDataL = (WORD *)ByteBuffer;
	pAVIBufferDataR = (WORD *)&ByteBuffer[2];
	pAVIBufferEnd = &ByteBuffer[BufferSizeBytes];
	nSamples = infoAudioStream.dwLength;
	streamLoaded = true;
}

return res;

}[/code]


#4

is a straight cast from the 16bit PCM Audio Sample [signed short] to juce’s 32bit float Sample gonna have the desired effect?

Or is there some difference in range which is resulting in my distorted playback?


#5

[quote=“dginside”]is a straight cast from the 16bit PCM Audio Sample [signed short] to juce’s 32bit float Sample gonna have the desired effect?

Or is there some difference in range which is resulting in my distorted playback?[/quote]

Ouch! No! The floating points need to be in the range -1.0 to 1.0 !


#6

(have a look inside the WavAudioFormat stuff for some code that does the conversion)


#7

thanks jules, thats got me another leap closer to what i’m after :slight_smile:

I’m using:

[code] if(*pActiveVFW16bitBlockL > 0)
*pActiveJuceBlockL = (float)*pActiveVFW16bitBlockL / 32767.0f;
else
*pActiveJuceBlockL = (float)*pActiveVFW16bitBlockL / 32768.0f;

		if(*pActiveVFW16bitBlockR > 0)
			*pActiveJuceBlockR = (float)*pActiveVFW16bitBlockR / 32767.0f;
		else
			*pActiveJuceBlockR = (float)*pActiveVFW16bitBlockR / 32768.0f;[/code]

and it sounds pretty damn good… only thing now is that its abit slower than i expected, and for some reason a bit louder.

any ideas?

thanks so much!


#8

That’s actually not quite right, there’s no need to handle negatives differently. Just multiply the number by (1.0 / 0x8000), and you’re sorted. If you expect a different volume, you can scale it at this point too.

You’ll probably need to use a ResamplingAudioSource to make sure the rate is matched to the audio device.


#9