
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio.hpp>
#include <iostream>


////////////////////////////////////////////////////////////
/// Customized sound stream for acquiring audio data
/// from memory (completely useless, just to illustrate the
/// streaming techniques)
////////////////////////////////////////////////////////////
class MyCustomStream : public sf::SoundStream
{
public :

    ////////////////////////////////////////////////////////////
    /// Default constructor
    ///
    /// \param BufferSize : Size of the internal audio buffer
    ///
    ////////////////////////////////////////////////////////////
    MyCustomStream(std::size_t BufferSize) :
    myOffset    (0),
    myBufferSize(BufferSize)
    {

    }

    ////////////////////////////////////////////////////////////
    /// Load sound data from a file
    ///
    /// \param Filename : File to load
    ///
    ////////////////////////////////////////////////////////////
    bool Open(const std::string& Filename)
    {
        // Load the sound data into a sound buffer
        sf::SoundBuffer SoundData;
        if (SoundData.LoadFromFile(Filename))
        {
            // Initialize the stream with the sound parameters
            Initialize(SoundData.GetChannelsCount(), SoundData.GetSampleRate());

            // Copy the audio samples into our internal array
            const sf::Int16* Data = SoundData.GetSamples();
            myBuffer.assign(Data, Data + SoundData.GetSamplesCount());

            return true;
        }

        return false;
    }

private :

    ////////////////////////////////////////////////////////////
    /// /see sfSoundStream::OnStart
    ///
    ////////////////////////////////////////////////////////////
    virtual bool OnStart()
    {
        // Reset the read offset
        myOffset = 0;

        return true;
    }

    ////////////////////////////////////////////////////////////
    /// /see sfSoundStream::OnGetData
    ///
    ////////////////////////////////////////////////////////////
    virtual bool OnGetData(sf::SoundStream::Chunk& Data)
    {
        // Check if there is enough data to stream
        if (myOffset + myBufferSize >= myBuffer.size())
        {
            // Returning false means that we want to stop playing the stream
            return false;
        }

        // Fill the stream chunk with a pointer to the audio data and the number of samples to stream
        Data.Samples   = &myBuffer[myOffset];
        Data.NbSamples = myBufferSize;

        // Update the read offset
        myOffset += myBufferSize;

        return true;
    }

    ////////////////////////////////////////////////////////////
    // Member data
    ////////////////////////////////////////////////////////////
    std::vector<sf::Int16> myBuffer;     ///< Internal buffer that holds audio samples
    std::size_t            myOffset;     ///< Read offset in the sample array
    std::size_t            myBufferSize; ///< Size of the audio data to stream
};


////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
    // Create an instance of our custom audio stream
    // Try different (lower) values to hear the effect
    MyCustomStream Stream(40000);

    // Open a sound file
    if (!Stream.Open("music.ogg"))
        return EXIT_FAILURE;

    // Play it
    Stream.Play();
    std::cout << "Playing 5 seconds of audio data..." << std::endl;

    // Stop it after 5 seconds
    sf::Sleep(5.f);
    Stream.Stop();

    // Wait until the user presses 'enter' key
    std::cout << "Press enter to exit..." << std::endl;
    std::cin.ignore(10000, '\n');

    return EXIT_SUCCESS;
}

