3 Copyright 2005 Kenneth Hayber <ken@hayber.us>, All rights reserved.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License.
9 This program is distributed in the hope that it will be useful
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 import flac
.metadata
as metadata
22 import flac
.decoder
as fldecoder
26 print "No FLAC support!"
34 A decoder to process FLAC sound files. Utilizes the standard pyflac module
35 Called from the Player class to read and decode FLAC files.
37 def __init__(self
, filename
, buffersize
):
38 """Initialize the decoder"""
39 self
.buffersize
= buffersize
40 self
.filename
= filename
43 chain
= metadata
.Chain()
45 it
= metadata
.Iterator()
48 block
= it
.get_block()
49 if block
.type == metadata
.STREAMINFO
:
50 streaminfo
= block
.data
.stream_info
51 self
.total_samples
= streaminfo
.total_samples
52 self
.sample_rate
= streaminfo
.sample_rate
53 self
.nchannels
= streaminfo
.channels
59 """Open the file and prepare for decoding"""
61 def metadata_callback(dec
, block
): pass
62 def error_callback(dec
, status
): pass
63 def write_callback(dec
, buff
, size
):
67 self
.buff
+= buff
[:-1]
68 return fldecoder
.FLAC__FILE_DECODER_OK
70 # create a new file decoder
71 mydec
= fldecoder
.FileDecoder()
74 mydec
.set_md5_checking(False);
75 mydec
.set_filename(self
.filename
)
76 mydec
.set_metadata_respond_all()
79 mydec
.set_write_callback(write_callback
)
80 mydec
.set_error_callback(error_callback
)
81 mydec
.set_metadata_callback(metadata_callback
)
83 # initialise, process metadata
85 mydec
.process_until_end_of_metadata()
90 """Close the file and do any needed cleanup"""
94 """Return the length of the file in seconds as an integer"""
95 return self
.total_samples
/ self
.sample_rate
98 """Return the sample rate of the file in samples per second"""
99 return self
.sample_rate
102 """Return the number of channels in the file"""
103 return self
.nchannels
107 Read data from the file and decode to PCM data. Return a buffer
108 of data and length, or (None, 0) at EOF
111 self
.mydec
.process_single()
112 bytes
= len(self
.buff
)
114 return (self
.buff
, bytes
)
119 """Return the current playback position in seconds"""
120 curr_decode
= self
.mydec
.get_decode_position()
121 return int(curr_decode
/ (self
.sample_rate
* self
.channels()))
124 """Jump to pos as a percentage of the total length of the file"""
128 """Display some FLAC information"""
130 chain
= metadata
.Chain()
131 chain
.read(self
.filename
)
133 # get iterator, initialise
134 it
= metadata
.Iterator()
139 block
= it
.get_block()
140 # print some common fields
141 print 'METADATA BLOCK #%d' % cur_block
142 print ' type: %d (%s)' % (block
.type, metadata
.TypeString(block
.type))
143 print ' is_last: %d' % block
.is_last
144 print ' length: %d' % block
.length
147 if block
.type == metadata
.STREAMINFO
:
148 # print STREAMINFO fields
149 streaminfo
= block
.data
.stream_info
150 print ' minimum blocksize: %d' % streaminfo
.min_blocksize
151 print ' maximum blocksize: %d' % streaminfo
.max_blocksize
152 print ' minimum framesize: %d' % streaminfo
.min_framesize
153 print ' maximum framesize: %d' % streaminfo
.max_framesize
154 print ' sample_rate: %d' % streaminfo
.sample_rate
155 print ' channels: %d' % streaminfo
.channels
156 print ' bits-per-sample: %d' % streaminfo
.bits_per_sample
157 print ' total samples: %d' % streaminfo
.total_samples
158 #print ' md5sum: %s' % streaminfo.md5sum
160 elif block
.type == metadata
.SEEKTABLE
:
161 # print SEEKTABLE fields
162 seektable
= block
.data
.seek_table
163 print ' seek points: %d' % seektable
.num_points
164 for i
in range(seektable
.num_points
):
165 pt
= seektable
.points
[i
]
166 print ' point %d: sample_number=%d, stream_offset=%d, frame_samples=%d' % (i
, pt
.sample_number
, pt
.stream_offset
, pt
.frame_samples
)
168 elif block
.type == metadata
.CUESHEET
:
170 cuesheet
= block
.data
.cue_sheet
171 print ' media catalog number: %s' % cuesheet
.media_catalog_number
172 print ' lead-in: %d' % cuesheet
.lead_in
173 print ' is CD: %d' % cuesheet
.is_cd
174 print ' number of tracks: %d' % cuesheet
.num_tracks
175 for i
in range(cuesheet
.num_tracks
):
176 tr
= cuesheet
.tracks
[i
]
177 print ' track[%d]' % i
178 print ' offset: %d' % tr
.offset
179 print ' number: %d' % ord(tr
.number
)
180 print ' ISRC: %s' % tr
.isrc
184 print ' type: NON-AUDIO'
185 if tr
.pre_emphasis
== 1:
186 print ' pre-emphasis: true'
188 print ' pre-emphasis: false'
189 print ' number of index points: %d' % ord(tr
.num_indices
)
190 for j
in range(ord(tr
.num_indices
)):
191 print ' index[%d]' % j
192 print ' offset: %d' % tr
.indices
[j
].offset
193 print ' number: %d' % ord(tr
.indices
[j
].number
)
195 elif block
.type == metadata
.VORBIS_COMMENT
:
197 comment
= block
.data
.vorbis_comment
198 print ' vendor string: %s' % comment
.vendor_string
199 print ' comments: %d' % comment
.num_comments
200 for i
in range(comment
.num_comments
):
201 print ' comment[%d]: %s' % (i
, comment
.comments
[i
])