Giter Club home page Giter Club logo

nvorbis's Introduction

NVorbis Gitter

NVorbis is a .Net library for decoding Xiph.org Vorbis files. It is designed to run in partial trust environments and does not require P/Invoke or unsafe code. It is built for .Net Standard 2.0 and .Net Framework 4.5.

This implementation is based on the Vorbis specification found on xiph.org. The MDCT and Huffman codeword generator were borrowed from public domain implementations in https://github.com/nothings/stb/blob/master/stb_vorbis.c.

To use:

// add a reference to NVorbis.dll

// this is the simplest usage; see the public classes and constructors for other options
using (var vorbis = new NVorbis.VorbisReader("path/to/file.ogg"))
{
	// get the channels & sample rate
    var channels = vorbis.Channels;
    var sampleRate = vorbis.SampleRate;

    // OPTIONALLY: get a TimeSpan indicating the total length of the Vorbis stream
    var totalTime = vorbis.TotalTime;

	// create a buffer for reading samples
    var readBuffer = new float[channels * sampleRate / 5];	// 200ms

	// get the initial position (obviously the start)
    var position = TimeSpan.Zero;

    // go grab samples
    int cnt;
    while ((cnt = vorbis.ReadSamples(readBuffer, 0, readBuffer.Length)) > 0)
    {
    	// do stuff with the buffer
    	// samples are interleaved (chan0, chan1, chan0, chan1, etc.)
    	// sample value range is -0.99999994f to 0.99999994f unless vorbis.ClipSamples == false
    
    	// OPTIONALLY: get the position we just read through to...
        position = vorbis.TimePosition;
    }
}

NVorbis can be downloaded on NuGet.

If you are using NAudio, support is available via NAudio.Vorbis.

Support for OpenTK also exists and can be downloaded on NuGet.

If you have any questions or comments, feel free to join us on Gitter. If you have any issues or feature requests, please submit them in the issue tracker.

nvorbis's People

Contributors

aurorabertaoldham avatar dan200 avatar danzel avatar frooxius avatar ioctllr avatar jjxtra avatar lafirest avatar mrhelmut avatar renaudbedard avatar waltdestler avatar yyagi8864 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

nvorbis's Issues

Need lots more tests

WHAT WORKS: Test App project can be set as the Startup project and it plays a sample OGG file.
PROBLEMS: 1) Usage instructions are not even a unit test. 2) The current usage instructions require you to ReadSamples with 4 parameters but current implementation only has 3 parameters. 3) I am not sure that the current usage instructions even plays the sound. It seems to read the file but not actually play anything. 4) The current TestApp project is not a even test project. 5) The only test in the current TestApp project requires a external dependency on a 3rd party application called NAudio . (If you want to show how to utilize NAudio integration, then you should build another test app just for it and take the dependency there.) 6) There is no active test for the ForwardOnlyStream unit that was provided in the TestApp.

IndexOutOfRangeException in PacketProvider.CreatePacket while seeking

To reproduce, open Tromboon.ogg and seek to sample 23104:

VorbisReader reader = new("Tromboon.ogg");
reader.SamplePosition = 23104;

This throws a IndexOutOfRangeException in PacketProvider.CreatePacket (line 210; _reader.GetPagePackets(pageIndex) returns an array of length 17 but packetIndex is 23.)

I have been able to reproduce this with multiple unrelated ogg files.

IndexOutOfRangeException for this OGG file since v0.10.0-alpha

Since the rewrite with v0.10.0-alpha and up to the most recent version I'm getting IndexOutOfRangeExceptions when trying to read a specific OGG file. I tried it with the TestApp from this repo. This is the stack trace of the exception I'm seeing:

System.IndexOutOfRangeException
  HResult=0x80131508
  Message=Index was outside the bounds of the array.
  Source=NVorbis
  StackTrace:
   at NVorbis.Ogg.PacketProvider.CreatePacket(Int32& pageIndex, Int32& packetIndex, Boolean advance, Int64 granulePos, Boolean isResync, Boolean isContinued, Int32 packetCount, Int32 pageOverhead) in D:\DEV\NVorbis\NVorbis\Ogg\PacketProvider.cs:line 195
   at NVorbis.Ogg.PacketProvider.GetNextPacket(Int32& pageIndex, Int32& packetIndex) in D:\DEV\NVorbis\NVorbis\Ogg\PacketProvider.cs:line 178
   at NVorbis.Ogg.PacketProvider.GetNextPacket() in D:\DEV\NVorbis\NVorbis\Ogg\PacketProvider.cs:line 46
   at NVorbis.StreamDecoder.DecodeNextPacket(Int32& packetStartindex, Int32& packetValidLength, Int32& packetTotalLength, Boolean& isEndOfStream, Nullable`1& samplePosition, Int32& bitsRead, Int32& bitsRemaining, Int32& containerOverheadBits) in D:\DEV\NVorbis\NVorbis\StreamDecoder.cs:line 464
   at NVorbis.StreamDecoder.ReadNextPacket(Int32 bufferedSamples, Nullable`1& samplePosition) in D:\DEV\NVorbis\NVorbis\StreamDecoder.cs:line 414
   at NVorbis.StreamDecoder.Read(Single[] buffer, Int32 offset, Int32 count) in D:\DEV\NVorbis\NVorbis\StreamDecoder.cs:line 346
   at NVorbis.VorbisReader.ReadSamples(Single[] buffer, Int32 offset, Int32 count) in D:\DEV\NVorbis\NVorbis\VorbisReader.cs:line 342
   at TestApp.VorbisWaveStream.Read(Single[] buffer, Int32 offset, Int32 count) in D:\DEV\NVorbis\TestApp\VorbisWaveStream.cs:line 92
   at TestApp.VorbisWaveStream.Read(Byte[] buffer, Int32 offset, Int32 count) in D:\DEV\NVorbis\TestApp\VorbisWaveStream.cs:line 79
   at NAudio.Wave.WaveOutBuffer.OnDone()
   at NAudio.Wave.WaveOutEvent.DoPlayback()
   at NAudio.Wave.WaveOutEvent.PlaybackThread()

Exact repro steps

  1. Download the test file into the TestFiles directory:
PS> Invoke-WebRequest https://raw.githubusercontent.com/bert2/DtmfDetection/master/test/integration/testdata/very_short_dtmf_tones.ogg -OutFile .\TestFiles\4test.ogg
  1. Use the TestApp project to play 4test.ogg.

Expected: TestApp should exit with success after playing the file.

Actual: TestApp crashes with the exception shown above.

Additional notes

The crash happens at the end of the file, so maybe the decoder failed to detect the EOF?

Also, I'm not sure whether my file is corrupted or this is a bug in the implementation. But I'm assuming the latter, because the file works without problems when I'm using v0.9.1 by checking out the tag.

"Could not read pre-roll packet!" exception when seeking

Here is an example.ogg file that demonstrates this issue. Simple load it and seek to sample 1:

VorbisReader reader = new("example.ogg");
reader.SamplePosition = 1;

This throws an InvalidOperationException "Could not read pre-roll packet! Try seeking again prior to reading more samples." in StreamDecoder.cs line 607.

I have not found any other ogg files with this particlular issue, so I can't be 100% sure it's not an issue with this file, but it does work in NVorbis 0.10.2, so I assume it's a regression bug.

VorbisReader class SamplePosition issue

I've found that the number of samples returned by vorbis.ReadSamples() does not line up with SamplePosition. Every so often it will get 4 or so samples off during reads
image

For some reason seeking to SamplePosition = 0 before doing reading improves the issue, but it doesn't entirely fix the issue.

LGPL Compatible Licensing

@Danielku15, @jjxtra, @ToddBertaOldham
Continuation of #12 in the old repository.

With the exception of Todd, all other submissions no longer apply as of the merge of the rearchitecting branch (the Ogg components, in particular, have been fully re-written), so given Todd's approval in the previous thread I'm going to re-license as MIT.

ForwardOnlyPageReader exception on last page

ForwardOnlyPageReader seems to throw a specific ArgumentException on the last page for all files, including test files.
Maybe that's why TestApp doesn't try to use ForwardOnlyStream?

The fault seems to be incorrect fallthrough logic at:

// otherwise, remove the stream from our list and fall through to:
_packetProviders.Remove(streamSerial);
}
Adding return true; at the end of this block, disobeying the comment, seems to fix it.
I looked at the normal PageReader to come up with this fix so I'm doubtful that this fallthrough comment is correct.

image

Weird issue ?

Hello i was getting _prevPacketStart bigger than _prevPacketEnd after a seek in StreamDecoder
it was doing an INFINITE loop

i Changed line 335 operator == to >= and it fixed the issue for me (the result audio is valid)

Seeking causes entire stream to be fetched

This is particularly killing for apps that rely on web streaming (which is the case for me), as it has to fetch all chunks for even a couple of seconds of seeking.

Upon inspecting the source code, it seems that the "TotalSamples" property might be the culprit, which calls the "GetGranuleCount" function, which in turn fetches all the pages.

 public long GetGranuleCount()
        {
            if (_reader == null) throw new ObjectDisposedException(nameof(PacketProvider));

            if (!_reader.HasAllPages)
            {
                // this will force the reader to attempt to read all pages
                _reader.GetPage(int.MaxValue, out _, out _, out _, out _, out _, out _);
            }
            return _reader.MaxGranulePosition.Value;
        }

I'll try to look into maybe using some kind of bisection method to seek to the correct position without having to fetch all the pages, but I am in no way an expert in audio processing etc, so any help would be appreciated.

Playback timing issue with some ogg files

I recently upgraded to the latest NAudio/NVorbis and I am now getting some playback synchronization issues with files that used to work.

Some files when decoded get slightly out of sync over time compared to how they should be.

Here is an example file:

https://drive.google.com/file/d/1KnMiL29oW8x9LA1xQtLAj9347AWJdKWt/view?usp=sharing

Here is that ogg decoded to a .wav file using NVorbis:

https://drive.google.com/file/d/1BXXs2OGqWHoqrguVJtlByb2r7_dH9dDg/view?usp=sharing

If you load both the .ogg file and the .wav file into an audio editor (such as Audacity), you will easily be able to see/hear the progressive sync issue.

The .wav was created from the .ogg as follows:

using (var fs = File.OpenRead(fileName)) { using (var waveStream = new VorbisWaveStream(fs)) { WaveFileWriter.CreateWaveFile16(Path.Combine(@"C:\tmp", Path.GetFileNameWithoutExtension(fileName) + ".wav"), waveStream); } }

As I said, this file (and other files I have issues with) worked fine previously. I think I was previously using NAudio.Vorbis 1.2.0.

Build on .NET 6

NVorbis builds just fine if you add net6.0 to its TargetFrameworks. Is there any reason this shouldn't be done?

A project that I'm trying to get to build entirely on net6 as a self-challenge depends on NAudio.Vorbis. NAudio recently got net6 builds in 2.1.0-beta.1, and NAudio.Vorbis builds fine in net6 on those as well. I'm not skilled enough at .NET to understand why NAudio.Vorbis builds on net6 without NVorbis building on net6, but my gut tells me here's the best place to ask.

Exception when reading certain ogg files.

Seems like I cannot play certain ogg files. The exception reads: "Granule Position was -1 but page has completed packets."
I'm happy to provide the files when this error happens. foobar2000 can read the file just fine.

rollForward results in negative value on seeking, resulting in negative _prevPacketStart

Hello!

I've ran into a seeking issue with this .ogg file: SGM_example.zip

Seek to position 678951
vorbRead.SamplePosition = 678951;

If you then call ReadSamples, it will throw an IndexOutOfRange exception in ClippingCopyBuffer.

I've found that this is due to the var pos = _packetProvider.SeekTo(samplePosition, 1, GetPacketGranules); in StreamDecoder.cs returning position that's ahead of the samplePosition.

This results in rollForward being negative and _prevPacketStart negative as well, causing the IndexOutOfRange on next read. Unfortunately I'm not sure how to fix this myself, but I hope this helps!

Add additional TFM so dependencies can be eliminated

Is your feature request related to a problem? Please describe.

I want to minimise dependencies in my project by utilising framework dependencies wherever possible

Describe the solution you'd like

To be able to install the package on a modern TFM ie net 6 and have no dependencies.

Describe alternatives you've considered

Accept the additional dependency

Additional context

n/a

"Ran out of packets?!" when seeking

The new 0.10.3 release appears to have a bug that causes an InvalidDataException to be thrown with the message "Ran out of packets?!" when seeking/setting the sample position. This appears to be a regression in 0.10.3; it did not happen for me in 0.10.2.

Here is a small sample program that easily reproduces the issue for me:

using NVorbis;

namespace NVorbisTest
{
    class Program
    {
        static void Main()
        {
            VorbisReader reader = new("test.ogg");
            while (reader.SamplePosition < reader.TotalSamples)
                reader.SamplePosition += reader.Channels;
        }
    }
}

I have been able to reproduce this easily with every ogg file I've tried, but just in case here is a test.ogg file that I know reproduces this issue consistently for me.

For convenience, here is the stack trace:

System.IO.InvalidDataException: Ran out of packets?!
   at NVorbis.Ogg.PacketProvider.FindPacket(Int32 pageIndex, Int64& granulePos, GetPacketGranuleCount getPacketGranuleCount, Boolean isRecursed)
   at NVorbis.Ogg.PacketProvider.SeekTo(Int64 granulePos, Int32 preRoll, GetPacketGranuleCount getPacketGranuleCount)
   at NVorbis.StreamDecoder.SeekTo(Int64 samplePosition, SeekOrigin seekOrigin)
   at NVorbis.StreamDecoder.set_SamplePosition(Int64 value)
   at NVorbis.VorbisReader.set_SamplePosition(Int64 value)
   at NVorbisTest.Program.Main() in C:\Users\walt\Desktop\NVorbisTest\Program.cs:line 11

Dead loop in StreamDecoder.Read()

// try to fill the buffer; drain the last buffer if EOS, resync, bad packet, or parameter change
while (idx < tgt)
{
    // if we don't have any more valid data in the current packet, read in the next packet
    if (_prevPacketStart == _prevPacketEnd)
    {
        if (_eosFound)
        {
            _nextPacketBuf = null;
            _prevPacketBuf = null;

            // no more samples, so just return
            break;
        }

        if (!ReadNextPacket((idx - offset) / _channels, out var samplePosition))
        {
            // drain the current packet (the windowing will fade it out)
            _prevPacketEnd = _prevPacketStop;
        }

        // if we need to pick up a position, and the packet had one, apply the position now
        if (samplePosition.HasValue && !_hasPosition)
        {
            _hasPosition = true;
            _currentPosition = samplePosition.Value - (_prevPacketEnd - _prevPacketStart) - (idx - offset) / _channels;
        }
    }

    // we read out the valid samples from the previous packet
    var copyLen = Math.Min((tgt - idx) / _channels, _prevPacketEnd - _prevPacketStart);
    if (copyLen > 0)
    {
        if (ClipSamples)
        {
            idx += ClippingCopyBuffer(buffer, idx, copyLen);
        }
        else
        {
            idx += CopyBuffer(buffer, idx, copyLen);
        }
    }
}

Not happen all the time, but when it happen, inside this while loop, while _eosFound is true, but code doesn't enter this if bracket. I don't know how but the _prevPacketEnd is small than _prevPacketStart causing copyLen to be negative value. The loop doesn't exit at all.

I temporarily added an if to check if copyLen is negative and return early to break the loop. No sure if the issue is caused by the ogg file but I cannot provide it due to copy right issue.

Update package readme

Summary

I wish for the nuget packages to have a more informative readme.

Details

The nuget package should be using the same readme as the repo to make it as easy as possible for a user to get started with the package.

Seeking fails with "Could not read pre-roll packet"

One of my test files fails to read after it has been parsed once. It works fine in 0.10.4, but the issue started in 0.10.5.

Start to read from the file via VorbisReader ReadSamples() method until it returns 0. Then try seeking to the start of the file using either TimePosition or SamplePosition, then it fails. Other files I have works fine, so I guess there is something special with this file. I have attached it.

Example.zip

Need Unit Tests

NVorbis is woefully lacking in UTs. More refactoring is required in the low-level decoding logic to properly accomplish unit testing. Other classes "should be" close or already ready. For this issue, we need to accomplish the refactoring and write the unit tests.

Infinite loop on fast seek

I was stressing out my player NAudio-NVorbis based and I also upgrade NVorbis at the latest version but when I perform lots of seeks during playback it causes a deadlock because of the infinite loop as shown in the screenshot
err2

Assuming that:
granulePos = 79062591
highGranulePos = 79062592
low = 3
lowGranulePos = num1 = 0
dist = num2 = 222

int index = low + (int)(dist * ((granulePos - lowGranulePos) / (float)(highGranulePos - lowGranulePos)));

then

index = 3 + (int)(222*((79062591 - 0) / (79062592 - 0))

should give 224 but at runtime 225 is calculated, casting to double instead float works fine

int index = low + (int)(dist * ((granulePos - lowGranulePos) / (double)(highGranulePos - lowGranulePos)))

Documentation is ambiguous

I've been trying to speak to someone in the chat on Element to get guidance on merging ogg files.

The example in the Readme doesn't show much.
Am I meant to place the read buffer into the stream? If so, does reading the ogg file have a header to account for?
I see a comment for "// 200MS". Is the read buffer meant to be that way for all samples?

Concat Header and a single page won't give correct PageSamples

I was trying to concat header with a single ogg page to get FirstGranulePosition ( in this case 0 ) but reading that stream with NVorbis gives more samples than expected. Is there any reason why that happens?
image

Update.....
I've actually found out the problem. For some reason, Reading too fast from the stream causes it to give more samples.
Debugging ( simulating slow read )
image
Without Debug ( fast read )
image

Update....
It might be possible that debug updates some properties as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.