# Overview

## decoder.py

decoder.py is a cross-platform module for decoding compressed audio files. It uses external decoders by turning their stdout into file-like object which is completely compatible with wave.py module.

decoder.py is the result of author's knowledge, skill and creativity and a lot of assembled code legally obtained from the internet. Thanks to all who put them there!

## Usage:

>>> import decoder
>>>
>>> mp3 = decoder.open("something.mp3")
>>> print "Channels:", mp3.getnchannels()
Channels: 2
>>> print "Framerate:", mp3.getframerate()
Framerate: 44100
>>> print "Duration:", mp3.getnframes()/mp3.getframerate()
Duration: 206
>>>
>>> import wave
>>>
>>> wf = wave.open("something.wav", "w")
>>> wf.setnchannels(mp3.getnchannels())
>>> wf.setsampwidth(mp3.getsampwidth())
>>> wf.setnframes(mp3.getnframes())
>>> wf.setframerate(mp3.getframerate())
>>> while data!="":
...     wf.writeframes(data)
...
>>> mp3.close()
>>> wf.close()
>>>
>>> # You can abbreviate the above code as this:
>>> mp3 = decoder.open("something.mp3")
>>> wf = wave.open("something.wav", "w")
>>> decoder.copywaveobj(mp3, wf)
>>> mp3.close()
>>> wf.close()
>>>


The "from decoder import *" is also supported, but the function open() will then become acopen(), so to avoid mixing with __builtin__.open().

You can use the audiodev module or PyAudio library or sys.stdout or some external command line player like aplay in the same way as shown above.

## FUNCTIONS:

open(name, fh=0) --> fakewave / wave.Wave_read / aifc.Aifc_read object The name argument is the path to file you wish to decode. Supported filetypes: *.mp1, *.mp2, *.mp3 *.mp4, *.m4a, *.m4b, *.aac *.ogg *.flac *.oga *.wma *.wav, *.aif (uncompressed files only)

fh (force header) argument can be one, zero, boolean or string representing the valid WAVE header. It is used if an external decoder writes only raw data to stdout. For instance, "faad" under Linux.

The open() returns an instance of a class with the following public methods:
getnchannels() -- returns number of audio channels (1 for
mono, 2 for stereo)

getsampwidth() -- returns sample width in bytes getframerate() -- returns sampling frequency getnframes() -- returns number of audio frames getcomptype() -- returns compression type (always 'NONE' - linear samples) getcompname() -- returns human-readable version of

compression type (always 'not compressed' linear samples)
getparams() -- returns a tuple consisting of all of the
above in the above order
getmarkers() -- returns None (for compatibility with the
aifc module) The exception goes when aiff file is used.
getmark(id) -- raises an error since the mark does not
exist (for compatibility with the aifc module) The exception goes when aiff file is used.

readframes(n) -- returns at most n frames of decoded audio rewind() -- rewind to the beginning of the audio stream setpos(pos) -- seek to the specified position tell() -- return the current position close() -- close the instance (make it unusable)

The position returned by tell() and the position given to setpos() are compatible and have nothing to do with the actual position on stdout. The close() method is called automatically when the class instance is destroyed.

## NOTA BENE:

The setpos() and rewind() are usually not accessible because of on-fly decoding and use of one of them often raises the IOError: [Erno 29] Illegal seek.

Unfortunately, you cannot give an open read file pointer to open(), not yet.

getnframes() returns correct number of frames, but decoders nearly always cut off some unimportant frames and therefore be careful about this. In this case fakewave.readframes() returns empty frames where the "" (empty string) would be returned if asking the external decoder.

Returns the WAVE header string which can be used for force header argument of function open(). You are advised to use it when the specifications of the output of external decoder are static and known to you. This function is called (without arguments) if the force header argument of open() function is True or 1.
Returns the WAVE header string which can be used for force header argument of function open(). The generated header does not always match the output of the external decoder and it is also not 100% correct. So you are advised to use CreateWaveHeader() instead. (When possible)

The following functions have to be called with decoder.py imported as "import decoder", not "from decoder import *".

Checks for updates of decoder.py on the official page and mirror. If you are not connected to the internet or both servers are unavailable or the downloaded update script is corrupted, None is returned. If everything went fine, the dictionary of update script options, with their values, is returned. To check for new version do: >>> nv = decoder.CheckForUpdates() >>> if nv: >>> if nv["__version__"] <= decoder.__version__: >>> print "No new version available!" >>> else: >>> print "A new version is", nv["__version__"] >>> else: >>> print "Something wrong with net connection, DNS, servers, uscripts etc."
update (udict=0) --> integer

It may happen, that someone redirects your DNS to fool your system and tricks it to download the files from another location, pretending to be brailleweb.com. The downloaded files may contain malicious code and harm your system. I hope that this warning would not give somebody an idea.
restore (v=None) --> None
Rolls back the decoder.py from the backup file. If you ran the new version and want to restore it to the previous one, you need to specify the version of previous version. If you test the decoder.py and you want to restore to previous one, the restore() will be enough. The function tries to achieve its goal, but does not raise an error if there is one. The adequate backup file 'decoder-__version__-backup.zip' needs to be present in the directory i.e. the update() must be called first.

## CLASSES:

Error --> Exception raised when something is wrong with external decoder's output

fakewave --> Instance returned by open() function if compressed audio file given

copywaveobj --> Instance that copies information from one wave object to another.
__init__(self, src, dst, start=None, end=None, bufsize=1024, blocking=True) --> None
Constructor that initialises copying information from one wave object to another. I.e. from Wave_read/like-Wave_read object to Wave_write/like-Wave_write object. This method also supports copying from file to file and mixed copying: from wave to file and vice versa, but then, you must have in mind that file-like.read() and file-like.seek() differs from wave-like.readframes() and wave-like.setpos(). If you use the file-like/wave-like object that has both readframes() and read() or writeframes() and write() or setpos() and seek() methods, then, this function will mess the objects pretty badly. So be careful. The start argument sets the source object to offset of frames/bytes from which to start copying. If you use fakewave object as a source, do not use this, because it will raise the Illegal seek error. End is the offset of frames/bytes after which the copying will stop. Bufsize is, of course, the number of frames/bytes copied per one iteration. Blocking is the mode of copying information. If it is True, then instance acts like a structural function and you need to wait until the copying is done. Else, the copying is launched in a thread, and you can control it using below described methods.
begin(self) --> None
A method that really does the copying of data. If you call it, and it is already started, nothing will happen. If the process is paused, and you call it, the copying will resume. If you call it after calling the stop() method, the copying will start again (from the beginning), but in structural manner - you will have to wait till the end. If you want to restart the unblocking way of copying, then do: a = copywaveobj(...); a.thread(a.begin, ())
pause(self) --> None
Freezes the copying (unblocking mode).
resume(self) --> None
Resumes the copying (Unblocking mode). If copying is not paused, no problems!
stop(self) --> None
Stops the copying (unblocking mode).
status(self) --> int (1; -1; 0)
Returns -1, when copying is paused, 1 when it is in progress, and 0 when it is stopped.
tell(self) --> int
Returns the number of finished iterations while copying. The approximate number of copied frames (wave-like) or bytes (file-like) is: a = copywaveobj(...); print a.bufsize*a.tell()
wait(self) --> None
Waits until copying STOPS (unblocking mode).
VARIABLES:
wildcard --> A list containing all extensions that open() supports.
When imported with 'from', it is called "decoder_wildcard"

## DEPENDENCIES:

decoder.py depends on mutagen library - to calculate the number of frames and create WAVE headers.

In order to make it work (decoder.py), you need external decoders: lame, faad, flac, oggdec, wmadec (on Windows) and ffmpeg (on Unix). To install them on Ubuntu/Debian use: apt-get install lame apt-get install vorbis-tools apt-get install faad apt-get install flac apt-get install ffmpeg

For Windows: As I hate searching for dependencies for years and then finding the wrong ones, you will get them along in the same ZIP as decoder.py. But better be warned that there might be newer versions somewhere on the internet. That especially goes for "wmadec" which is still buggy.

In the "codecs.pdc" file you should put commands for external decoders. How the system reaches them.