1 # A Monkey's Audio (APE) reader/tagger
3 # Copyright 2006 Lukas Lalinsky <lalinsky@gmail.com>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as
7 # published by the Free Software Foundation.
9 # $Id: monkeysaudio.py 3976 2007-01-13 22:00:14Z piman $
11 """Monkey's Audio streams with APEv2 tags.
13 Monkey's Audio is a very efficient lossless audio compressor developed
16 For more information, see http://www.monkeysaudio.com/.
19 __all__
= ["MonkeysAudio", "Open", "delete"]
23 from mutagen
.apev2
import APEv2File
, error
, delete
24 from mutagen
._util
import cdata
26 class MonkeysAudioHeaderError(error
): pass
28 class MonkeysAudioInfo(object):
29 """Monkey's Audio stream information.
32 channels -- number of audio channels
33 length -- file length in seconds, as a float
34 sample_rate -- audio sampling rate in Hz
35 bits_per_sample -- bits per sample
36 version -- Monkey's Audio stream version, as a float (eg: 3.99)
39 def __init__(self
, fileobj
):
40 header
= fileobj
.read(76)
41 if len(header
) != 76 or not header
.startswith("MAC "):
42 raise MonkeysAudioHeaderError("not a Monkey's Audio file")
43 self
.version
= cdata
.ushort_le(header
[4:6])
44 if self
.version
>= 3980:
45 (blocks_per_frame
, final_frame_blocks
, total_frames
,
46 self
.bits_per_sample
, self
.channels
,
47 self
.sample_rate
) = struct
.unpack("<IIIHHI", header
[56:76])
49 compression_level
= cdata
.ushort_le(header
[6:8])
50 self
.channels
, self
.sample_rate
= struct
.unpack(
52 total_frames
, final_frame_blocks
= struct
.unpack(
54 if self
.version
>= 3950:
55 blocks_per_frame
= 73728 * 4
56 elif self
.version
>= 3900 or (self
.version
>= 3800 and
57 compression_level
== 4):
58 blocks_per_frame
= 73728
60 blocks_per_frame
= 9216
61 self
.version
/= 1000.0
63 if self
.sample_rate
!= 0 and total_frames
> 0:
64 total_blocks
= ((total_frames
- 1) * blocks_per_frame
+
66 self
.length
= float(total_blocks
) / self
.sample_rate
69 return "Monkey's Audio %.2f, %.2f seconds, %d Hz" % (
70 self
.version
, self
.length
, self
.sample_rate
)
72 class MonkeysAudio(APEv2File
):
73 _Info
= MonkeysAudioInfo
74 _mimes
= ["audio/ape", "audio/x-ape"]
76 def score(filename
, fileobj
, header
):
77 return header
.startswith("MAC ") + filename
.lower().endswith(".ape")
78 score
= staticmethod(score
)