#!/usr/bin/python
#
# Partial port of decoder_example.c from the vorbis library.
# Decodes an ogg/vorbis file from stdin, writing the first channel to disk.
#
# Daniel Holth <dholth@fastmail.fm>, 2004

try:
    import oss
except:
    oss = None
import sys
import oggpy
import vorbispy
import numarray
import wave

BUFSIZE=8192


def packetsource(ogg):
    """Generator to take ogg packets out of a file.  Only returns packets from the first stream."""
    state = 0
    
    oy = oggpy.sync()
    og = oggpy.page()
    op = oggpy.packet()

    buffer = True   # prime the pump
    while buffer:
        buffer = ogg.read(BUFSIZE)
        oy.write(buffer)
        while(oy.pageout(og)):
            if state == 0:
                stream = oggpy.stream(og.serialno())
                state += 1
            stream.pagein(og)
            while(stream.packetout(op) == 1):
                yield op



def test(ogg, outfile = None):
    numarray.Error.setMode(all="ignore")
    
    vi = vorbispy.info()
    vd = vorbispy.dsp()
    vb = vorbispy.block()
    vc = vorbispy.comment()

    packets = packetsource(ogg)

    vorbis = 0

    sizes = {}

    for packet in packets:
        
        if vorbis < 3:
            rc = vi.synthesis_headerin(vc, packet)
            if rc < 0:
                print "Faulty vorbis header #%d, error %d" % (vorbis, rc)                
                return
            
        elif vorbis == 3: 
            print >> sys.stderr, vc.get_comments()

            channels = vi.get_channels()
            rate     = vi.get_rate()

            if not outfile:
                audio = oss.open_audio()
                if channels >= 2:
                    audio.stereo(1)
                audio.format(oss.AFMT_S16_LE)
                audio.speed(rate)
                samplewriter = audio.write
            else:   # outfile will be a wave_writer object
                audio = wave.open(outfile, "wb")
                audio.setsampwidth(2)
                audio.setframerate(rate)
                audio.setnchannels(channels)
                samplewriter = audio.writeframesraw
        
            vd.synthesis_init(vi)
            vd.block_init(vb)

        if vorbis >= 3:
            if vb.synthesis(packet) == 0:
                vd.synthesis_blockin(vb)

                samples = vd.synthesis_pcmout()
                if samples != None:
                    samples *= 32767;
                    wav = samples.astype('Int16')

                    interleaved = numarray.zeros(samples.shape[1]*channels, numarray.Int16)

                    shape = samples.shape[1]
                    try:
                        sizes[shape] += 1
                    except:
                        sizes[shape] = 1

                    for i in range(channels):
                        interleaved[i::channels] = wav[i]

                    samplewriter(interleaved.tostring())
                    
                    # seems to clean them out the first time.
                    # samples = vd.synthesis_pcmout()
                    # if samples != None:
                    #    print "synthesis_pcmout foo!"


        vorbis += 1

    # set total frames in wav header when done
    if not outfile:
        audio.writeframes('')

    # see how the block sizes go
    print sizes
                                

if __name__ == "__main__":
    outfile = None
    if len(sys.argv) == 3:
        sys.argv.pop()
        outfile = file("decode.wav", "wb")
    if len(sys.argv) == 2:
        if sys.argv[1] == "-":
            test(sys.stdin, outfile)
        else:
            test(file(sys.argv[1], "rb"), outfile)
    else:
        test(file("music.ogg", "rb"), outfile)


syntax highlighted by Code2HTML, v. 0.9.1