Permalink
Browse files

FLAC streamer implemented but not working

  • Loading branch information...
1 parent 592de4f commit 349a5b82182fd9ba3d3c842d20e4c04021cd4543 @soemraws soemraws committed Jul 31, 2010
Showing with 153 additions and 24 deletions.
  1. +1 −1 flac-grovelling-metadata.lisp
  2. +19 −3 flac-grovelling.lisp
  3. +1 −1 flac-metadata.lisp
  4. +4 −1 flac-package.lisp
  5. +113 −18 flac-stream.lisp
  6. +6 −0 flac.lisp
  7. +9 −0 mixalot-flac.asd
@@ -5,7 +5,7 @@
(in-package :flac)
(include "FLAC/stream_decoder.h")
-(cc-flags "-lFLAC")
+(cc-flags "-lFLAC" "-lm")
(cstruct flac-metadata "FLAC__StreamMetadata"
(type "type" :type flac-metadata-type)
View
@@ -5,18 +5,25 @@
(in-package :flac)
(include "FLAC/stream_decoder.h")
-(cc-flags "-lFLAC")
+(cc-flags "-lFLAC" "-lm")
;;;; Basic types
+(ctype flac-int16 "FLAC__int16")
(ctype flac-int32 "FLAC__int32")
(ctype flac-uint64 "FLAC__uint64")
(ctype flac-bool "FLAC__bool")
(ctype flac-unsigned "unsigned")
(ctype flac-decoder-init-status "FLAC__StreamDecoderInitStatus")
-(ctype flac-decoder-write-status "FLAC__StreamDecoderWriteStatus")
(ctype flac-decoder-error-status "FLAC__StreamDecoderErrorStatus")
+(ctype flac-decoder-state "FLAC__StreamDecoderState")
+
+(cenum flac-decoder-write-status
+ ((:write-continue "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE")
+ :documentation "The write was OK and decoding can continue.")
+ ((:write-abort "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT")
+ :documentation "An unrecoverable error occurred. The decoder will return from the process call."))
(cenum flac-metadata-type
((:stream-info "FLAC__METADATA_TYPE_STREAMINFO")
@@ -36,16 +43,25 @@
((:undefined "FLAC__METADATA_TYPE_UNDEFINED")
:documentation "marker to denote beginning of undefined type range; this number will increase as new metadata types are added"))
-(cstruct flac-metadata-streaminfo "FLAC__StreamMetadata_StreamInfo"
+(cstruct flac-metadata-stream-info "FLAC__StreamMetadata_StreamInfo"
(sample-rate "sample_rate" :type flac-unsigned)
(channels "channels" :type flac-unsigned)
(bits-per-sample "bits_per_sample" :type flac-unsigned)
(total-samples "total_samples" :type flac-uint64))
+;(cvar "FLAC__StreamDecoderErrorStatusString" :pointer :read-only t)
+
(cstruct flac-metadata-padding "FLAC__StreamMetadata_Padding")
(cstruct flac-metadata-application "FLAC__StreamMetadata_Application")
(cstruct flac-metadata-seektable "FLAC__StreamMetadata_SeekTable")
(cstruct flac-metadata-vorbiscomment "FLAC__StreamMetadata_VorbisComment")
(cstruct flac-metadata-cuesheet "FLAC__StreamMetadata_CueSheet")
(cstruct flac-metadata-picture "FLAC__StreamMetadata_Picture")
(cstruct flac-metadata-unknown "FLAC__StreamMetadata_Unknown")
+
+(cstruct flac-frame-header "FLAC__FrameHeader"
+ (block-size "blocksize" :type flac-unsigned)
+ (channels "channels" :type flac-unsigned))
+
+(cstruct flac-frame "FLAC__Frame"
+ (frame-header "header" :type flac-frame-header))
View
@@ -25,6 +25,6 @@
(in-package :flac)
(defcunion flac-metadata-data
- (stream-info flac-metadata-streaminfo)
+ (stream-info flac-metadata-stream-info)
(padding flac-metadata-padding)
(application flac-metadata-application))
View
@@ -1,12 +1,13 @@
(defpackage :flac
(:use :common-lisp :cffi)
(:export #:flac-bool
+ #:flac-int16
#:flac-int32
#:flac-uint64
#:flac-metadata
#:flac-metadata-data
- #:flac-metadata-streaminfo
+ #:flac-metadata-stream-info
#:flac-decoder-write-status
#:flac-decoder-error-status
@@ -23,4 +24,6 @@
#:flac-decoder-init-file
#:flac-decoder-finish
+ #:flac-decoder-get-state
+ #:flac-decoder-process-single
#:flac-decoder-process-until-end-of-metadata))
View
@@ -23,7 +23,11 @@
;;;; OTHER DEALINGS IN THE SOFTWARE.
(defpackage :mixalot-flac
- (:use :common-lisp :cffi :mixalot :flac))
+ (:use :common-lisp :cffi :mixalot :flac)
+ (:export #:flac-streamer
+ #:make-flac-streamer
+ #:flac-sample-rate
+ #:flac-streamer-release-resources))
(in-package :mixalot-flac)
@@ -35,8 +39,10 @@
(output-rate :reader flac-output-rate :initarg :output-rate)
(filename :initform nil :initarg filename)
(buffer :initform nil :accessor buffer)
+ (client-data :initform nil :initarg :client-data :accessor flac-client-data)
(length :initform nil)
(position :initform 0)
+ (err :initform 2)
(seek-to :initform nil)))
;;;; Callbacks
@@ -45,23 +51,34 @@
flac-decoder-write-status
((handle handleptr)
(frame :pointer)
- (buffer (:pointer (:pointer flac-int32)))
+ (buffer :pointer)
(client-data :pointer))
- nil)
+ (let* ((client-buffer (mem-ref client-data :pointer))
+ (frame-header (foreign-slot-value frame 'flac::flac-frame 'flac::frame-header))
+ (block-size (foreign-slot-value frame-header 'flac::flac-frame-header 'flac::block-size))
+ (channels (foreign-slot-value frame-header 'flac::flac-frame-header 'flac::channels)))
+ (loop for frame from 0 below block-size
+ do (loop for channel from 0 below channels
+ do (setf (mem-aref client-buffer 'flac-int16 (+ (* channels frame) channel))
+ (mem-aref (mem-aref buffer :pointer frame) 'flac-int16 channel)))))
+ :write-continue)
+
(defcallback metadata-callback
:void
((handle handleptr)
(metadata metadataptr)
(client-data :pointer))
- (let ((type (foreign-slot-value metadata 'flac-metadata 'type))
- (data (foreign-slot-pointer metadata 'flac-metadata 'data)))
+ (let ((type (foreign-slot-value metadata 'flac-metadata 'flac::type))
+ (data (foreign-slot-pointer metadata 'flac-metadata 'flac::data)))
(when (equal type :stream-info)
- (let ((stream-info (foreign-slot-pointer data 'flac-metadata-data 'stream-info)))
- (with-foreign-slots ((sample-rate channels bits-per-sample) stream-info flac-metadata-stream-info)
- (format t "Sample rate : ~D Hz~%" sample-rate)
- (format t "Channels : ~D~%" channels)
- (format t "Total samples: ~D~%" bits-per-sample))))))
+ (let ((stream-info (foreign-slot-pointer data 'flac-metadata-data 'flac::stream-info))
+ (client-buffer (mem-ref client-data :pointer)))
+ (with-foreign-slots ((flac::sample-rate flac::channels flac::bits-per-sample flac::total-samples) stream-info flac-metadata-stream-info)
+ (setf (mem-aref client-buffer 'flac-uint64 0) flac::sample-rate
+ (mem-aref client-buffer 'flac-uint64 1) flac::channels
+ (mem-aref client-buffer 'flac-uint64 2) flac::bits-per-sample
+ (mem-aref client-buffer 'flac-uint64 3) flac::total-samples))))))
(defcallback error-callback
:void
@@ -70,21 +87,99 @@
(client-data :pointer))
(error 'flac-error "Stream decoder error from callback" (flac-strerror status)))
-(defun flac-open (filename handle)
- (flac-decoder-init-file handle filename
- (callback write-callback)
- (callback metadata-callback)
- (callback error-callback)
- (null-pointer)))
+(defun open-flac-file (filename &key (output-rate 44100))
+ (let ((uhandle (flac-decoder-new))
+ (client-data (foreign-alloc :pointer))
+ (client-buffer (foreign-alloc 'flac-uint64 :count 4))
+ handle)
+ (setf (mem-aref client-data :pointer) client-buffer)
+ (unwind-protect
+ (progn
+ (flac-decoder-init-file uhandle filename
+ (callback write-callback)
+ (callback metadata-callback)
+ (callback error-callback)
+ client-data)
+ (flac-decoder-process-until-end-of-metadata uhandle)
+ (unless (= (mem-aref client-buffer 'flac-uint64 2) 16)
+ (error 'flac-error "Open FLAC file"
+ "Can only handle FLAC streams with 16 bits per sample."))
+ (rotatef handle uhandle))
+ (when uhandle
+ (flac-decoder-delete uhandle)
+ (foreign-free client-buffer)
+ (foreign-free client-data)))
+ (values handle client-data)))
(defun flac-streamer-release-resources (flac-stream)
"Release foreign resources associated with the flac-stream."
- (with-slots (handle) flac-stream
+ (with-slots (handle client-data) flac-stream
(when handle
(flac-decoder-finish handle)
(flac-decoder-delete handle)
- (setf handle nil))))
+ (setf handle nil))
+ (when client-data
+ (foreign-free client-data)
+ (setf client-data nil))))
(defmethod streamer-cleanup ((stream flac-streamer) mixer)
(declare (ignore mixer))
(flac-streamer-release-resources stream))
+
+(defun make-flac-streamer
+ (filename &rest args
+ &key
+ (output-rate 44100)
+ (class 'flac-streamer)
+ &allow-other-keys)
+ (multiple-value-bind (handle client-data)
+ (open-flac-file filename :output-rate output-rate)
+ (remf args :class)
+ (remf args :prescan)
+ (let* ((client-buffer (mem-ref client-data :pointer))
+ (stream (apply #'make-instance
+ class
+ :handle handle
+ :client-data client-data
+ :sample-rate (mem-aref client-buffer 'flac-uint64 0)
+ :channels (mem-aref client-buffer 'flac-uint64 1)
+ :output-rate output-rate
+ 'filename filename
+ args)))
+ (let ((result (mem-aref client-buffer 'flac-uint64 3)))
+ (when (> result 0)
+ (setf (slot-value stream 'length) result)))
+ (foreign-free client-buffer)
+ (setf (mem-ref client-data :pointer) (null-pointer))
+ stream)))
+
+(defmethod streamer-mix-into ((streamer flac-streamer) mixer mix-buffer offset length time)
+ (declare (ignore time)
+ (optimize (speed 3))
+ (type array-index offset length)
+ (type sample-vector mix-buffer))
+; (update-for-seek streamer)
+ (let* ((handle (flac-handle streamer))
+ (channels (flac-channels streamer))
+ (max-buffer-length 4)
+ (read-buffer (or (buffer streamer)
+ (setf (buffer streamer)
+ (make-array max-buffer-length
+ :element-type 'stereo-sample)))))
+ (declare (type sample-vector read-buffer))
+ (mixalot:with-array-pointer (bufptr read-buffer)
+ (setf (mem-ref (flac-client-data streamer) :pointer) bufptr)
+ (format nil "Length ~D~%" length)
+ (loop for sample from 0 below length by channels
+ do
+ (setf (slot-value streamer 'err) 3)
+ (when (= (+ sample (slot-value streamer 'position)) (slot-value streamer 'length))
+ (loop-finish))
+ (setf (slot-value streamer 'err) (flac-decoder-process-single handle))
+ (stereo-mixf (aref mix-buffer (+ frame offset))
+ (aref read-buffer 0))
+ (incf (slot-value streamer 'position) channels)
+ finally
+ (when (= (+ 1 (slot-value streamer 'position)) (slot-value streamer 'length))
+ (setf (slot-value streamer 'err) 4)
+ (mixer-remove-streamer mixer streamer))))))
View
@@ -79,4 +79,10 @@
(defcfun ("FLAC__stream_decoder_process_until_end_of_metadata" flac-decoder-process-until-end-of-metadata) flac-bool
(decoder handleptr))
+(defcfun ("FLAC__stream_decoder_process_single" flac-decoder-process-single) flac-bool
+ (decoder handleptr))
+
+(defcfun ("FLAC__stream_decoder_get_state" flac-decoder-get-state) flac-decoder-state
+ (decoder handleptr))
+
;;;; Helper functions
View
@@ -0,0 +1,9 @@
+(asdf:defsystem :mixalot-flac
+ :name "Mixalot-FLAC"
+ :description "FLAC Streamer class for Mixalot"
+ :version "0.0.1"
+ :author "Sumant S.R. Oemrawsingh <soemraws@xs4all.nl>"
+ :license "MIT-style license"
+ :depends-on (:cffi :mixalot :flac-ffi)
+ :serial t
+ :components ((:file "flac-stream")))

0 comments on commit 349a5b8

Please sign in to comment.