Ogg Length in samples


#1

Hey,
Should Ogg samples length be any different from the original wav which was used to create it?


#2

I don’t know, but mp3s are block aligned, so it’s quite possible oggs are too.


#3

Well… I figured out there is probably a bug with the OggVorbisAudioFormat writer.
as this code returns different lengths

WavAudioFormat WavFormat;
OggVorbisAudioFormat OggFormat;

// Create wav reader and print length
AudioFormatReader* wavReader = WavFormat.createReaderFor(File("c:\\original.wav").createInputStream(),true);
printf("Original Wav reader length: %d \n", wavReader->lengthInSamples);

// create ogg writer and write from wav reader
AudioFormatWriter* oggWriter = OggFormat.createWriterFor(File("c:\\test.ogg").createOutputStream(),
															wavReader->sampleRate,wavReader->numChannels,				wavReader->bitsPerSample,StringPairArray(), 0);
										
oggWriter->writeFromAudioReader(*wavReader, 0, wavReader->lengthInSamples);
delete oggWriter;

// create ogg reader and print length
AudioFormatReader* oggReader = OggFormat.createReaderFor(File("C:\\test.ogg").createInputStream(),true);
printf("Ogg reader length: %d \n", oggReader->lengthInSamples);

Is there anything wrong with what i do here?

the length i get for the ogg is always smaller by variable amount of samples.

If i use some other tool to encode the ogg (like the one found in libvorbis tools) the readers returns the exact length for both.


#4

i had no problems with ogg i used it in this project http://code.google.com/p/thor-v2/

i guess the sample number should change it’s a lossy compression method, so you loose some of the information of the audio file, and i guess that information is samples.


#5

It seems illogical to me as sample length also represents the length in time
(ie: 44100 samples or frames = 1 second). that’s means that the ogg version is a little shorter in time.

in most cases i tried the difference is not too big (less then 2000 samples) i also guess the problem is probably at the beginning or the end of the data, if your project suffers from this bug its almost unnoticeable, but its still a bug.

As i stated before I also find the length to be identical between the ogg and wav when using other tools which are not based on juce code.


#6

Well it calls all the right functions to pass the ogg encoder the same number of samples that you give it. Exactly what happens inside the encoder, I’m not sure! But I wouldn’t be surprised if it rounded it off to a packet boundary.


#7

The problem with the ogg vorbis is that after writing the last chunk of data you need to write a 0 size chunk so the file will know it is done.

If you don’t do it different readers will read differently the file. The juce ogg reader reads up until before the last chunk.

Anyway, the fix is simple, a little change in the dtor of the oggWriter should make it work good.

One little step in ogg, A giant step in my beta going out :slight_smile:

Rotem Bar
http://www.rotem-bar.com


code

juce\src\juce_appframework\audio\audio_file_formats\juce_OggVorbisAudioFormat.cpp

[code]~OggWriter()
{
if (ok)
{
int numSamples = 0;
vorbis_analysis_wrote (&vd, numSamples);

		while (vorbis_analysis_blockout (&vd, &vb) == 1)
		{
			vorbis_analysis (&vb, 0);
			vorbis_bitrate_addblock (&vb);

			while (vorbis_bitrate_flushpacket (&vd, &op))
			{
				ogg_stream_packetin (&os, &op);

				for (;;)
				{
					if (ogg_stream_pageout (&os, &og) == 0)
						break;

					output->write (og.header, og.header_len);
					output->write (og.body, og.body_len);

					if (ogg_page_eos (&og))
						break;
				}
			}
		}

        ogg_stream_clear (&os);
        vorbis_block_clear (&vb);
        vorbis_dsp_clear (&vd);
        vorbis_comment_clear (&vc);

        vorbis_info_clear (&vi);
        output->flush();
    }
    else
    {
        vorbis_info_clear (&vi);
        output = 0; // to stop the base class deleting this, as it needs to be returned
                    // to the caller of createWriter()
    }
}[/code][/code]

#8

Many thanks for spotting that!

But one question - maybe I’m missing something subtle, but why not just do this:

[code] ~OggWriter()
{
if (ok)
{
write (0, 0);

        ogg_stream_clear (&os);
        vorbis_block_clear (&vb);
        vorbis_dsp_clear (&vd);

…etc…
[/code]

?

I can’t see any difference between the code you’ve added and the code that’s already in the write method (?)