feat: Add MP3 and AAC encoder FFI bindings
- LAME FFI (lame-ffi.lisp) for MP3 encoding - FDK-AAC FFI (fdkaac-ffi.lisp) for AAC encoding - High-level encoder wrappers (encoder.lisp, aac-encoder.lisp) - Fix compilation warnings in buffer.lisp and icy-protocol.lisp Both encoders tested and loading successfully: - LAME version: 3.101 - FDK-AAC: libfdk-aac.so.2 Next steps: Harmony integration for audio pipeline
This commit is contained in:
parent
e1be88a54a
commit
6c15441a08
|
|
@ -0,0 +1,128 @@
|
|||
(in-package #:cl-streamer)
|
||||
|
||||
(defclass aac-encoder ()
|
||||
((handle :initform nil :accessor encoder-handle)
|
||||
(sample-rate :initarg :sample-rate :accessor aac-encoder-sample-rate :initform 44100)
|
||||
(channels :initarg :channels :accessor aac-encoder-channels :initform 2)
|
||||
(bitrate :initarg :bitrate :accessor aac-encoder-bitrate :initform 128000)
|
||||
(aot :initarg :aot :accessor aac-encoder-aot :initform :aot-aac-lc)
|
||||
(out-buffer :initform nil :accessor aac-encoder-out-buffer)
|
||||
(out-buffer-size :initform (* 1024 8) :accessor aac-encoder-out-buffer-size)
|
||||
(frame-length :initform 1024 :accessor aac-encoder-frame-length)))
|
||||
|
||||
(defun make-aac-encoder (&key (sample-rate 44100) (channels 2) (bitrate 128000))
|
||||
"Create an AAC encoder with the specified parameters.
|
||||
BITRATE is in bits per second (e.g., 128000 for 128kbps)."
|
||||
(let ((encoder (make-instance 'aac-encoder
|
||||
:sample-rate sample-rate
|
||||
:channels channels
|
||||
:bitrate bitrate)))
|
||||
(initialize-aac-encoder encoder)
|
||||
encoder))
|
||||
|
||||
(defun initialize-aac-encoder (encoder)
|
||||
"Initialize the FDK-AAC encoder with current settings."
|
||||
(cffi:with-foreign-object (handle-ptr :pointer)
|
||||
(let ((result (aac-enc-open handle-ptr 0 (aac-encoder-channels encoder))))
|
||||
(unless (zerop result)
|
||||
(error 'encoding-error :format :aac
|
||||
:message (format nil "aacEncOpen failed: ~A" result)))
|
||||
(setf (encoder-handle encoder) (cffi:mem-ref handle-ptr :pointer))))
|
||||
(let ((handle (encoder-handle encoder)))
|
||||
(aac-encoder-set-param handle :aacenc-aot 2)
|
||||
(aac-encoder-set-param handle :aacenc-samplerate (aac-encoder-sample-rate encoder))
|
||||
(aac-encoder-set-param handle :aacenc-channelmode
|
||||
(if (= (aac-encoder-channels encoder) 1) 1 2))
|
||||
(aac-encoder-set-param handle :aacenc-channelorder 1)
|
||||
(aac-encoder-set-param handle :aacenc-bitrate (aac-encoder-bitrate encoder))
|
||||
(aac-encoder-set-param handle :aacenc-transmux 2)
|
||||
(aac-encoder-set-param handle :aacenc-afterburner 1)
|
||||
(cffi:with-foreign-object (in-args '(:struct aacenc-in-args))
|
||||
(cffi:with-foreign-object (out-args '(:struct aacenc-out-args))
|
||||
(setf (cffi:foreign-slot-value in-args '(:struct aacenc-in-args) 'num-in-samples) -1)
|
||||
(setf (cffi:foreign-slot-value in-args '(:struct aacenc-in-args) 'num-ancillary-bytes) 0)
|
||||
(let ((result (aac-enc-encode handle (cffi:null-pointer) (cffi:null-pointer)
|
||||
in-args out-args)))
|
||||
(unless (zerop result)
|
||||
(aac-enc-close (cffi:foreign-alloc :pointer :initial-element handle))
|
||||
(error 'encoding-error :format :aac
|
||||
:message (format nil "aacEncEncode init failed: ~A" result))))))
|
||||
(cffi:with-foreign-object (info '(:struct aacenc-info-struct))
|
||||
(aac-enc-info handle info)
|
||||
(setf (aac-encoder-frame-length encoder)
|
||||
(cffi:foreign-slot-value info '(:struct aacenc-info-struct) 'frame-length))
|
||||
(setf (aac-encoder-out-buffer-size encoder)
|
||||
(cffi:foreign-slot-value info '(:struct aacenc-info-struct) 'max-out-buf-bytes)))
|
||||
(setf (aac-encoder-out-buffer encoder)
|
||||
(cffi:foreign-alloc :unsigned-char :count (aac-encoder-out-buffer-size encoder)))
|
||||
(log:info "AAC encoder initialized: ~Akbps, ~AHz, ~A channels, frame-length=~A"
|
||||
(floor (aac-encoder-bitrate encoder) 1000)
|
||||
(aac-encoder-sample-rate encoder)
|
||||
(aac-encoder-channels encoder)
|
||||
(aac-encoder-frame-length encoder))
|
||||
encoder))
|
||||
|
||||
(defun close-aac-encoder (encoder)
|
||||
"Close the AAC encoder and free resources."
|
||||
(when (encoder-handle encoder)
|
||||
(cffi:with-foreign-object (handle-ptr :pointer)
|
||||
(setf (cffi:mem-ref handle-ptr :pointer) (encoder-handle encoder))
|
||||
(aac-enc-close handle-ptr))
|
||||
(setf (encoder-handle encoder) nil))
|
||||
(when (aac-encoder-out-buffer encoder)
|
||||
(cffi:foreign-free (aac-encoder-out-buffer encoder))
|
||||
(setf (aac-encoder-out-buffer encoder) nil)))
|
||||
|
||||
(defun encode-aac-pcm (encoder pcm-samples num-samples)
|
||||
"Encode PCM samples (16-bit signed interleaved) to AAC.
|
||||
Returns a byte vector of AAC data (ADTS frames)."
|
||||
(let* ((handle (encoder-handle encoder))
|
||||
(channels (aac-encoder-channels encoder))
|
||||
(out-buf (aac-encoder-out-buffer encoder))
|
||||
(out-buf-size (aac-encoder-out-buffer-size encoder)))
|
||||
(cffi:with-pointer-to-vector-data (pcm-ptr pcm-samples)
|
||||
(cffi:with-foreign-objects ((in-buf-desc '(:struct aacenc-buf-desc))
|
||||
(out-buf-desc '(:struct aacenc-buf-desc))
|
||||
(in-args '(:struct aacenc-in-args))
|
||||
(out-args '(:struct aacenc-out-args))
|
||||
(in-buf-ptr :pointer)
|
||||
(in-buf-id :int)
|
||||
(in-buf-size :int)
|
||||
(in-buf-el-size :int)
|
||||
(out-buf-ptr :pointer)
|
||||
(out-buf-id :int)
|
||||
(out-buf-size-ptr :int)
|
||||
(out-buf-el-size :int))
|
||||
(setf (cffi:mem-ref in-buf-ptr :pointer) pcm-ptr)
|
||||
(setf (cffi:mem-ref in-buf-id :int) 0)
|
||||
(setf (cffi:mem-ref in-buf-size :int) (* num-samples channels 2))
|
||||
(setf (cffi:mem-ref in-buf-el-size :int) 2)
|
||||
(setf (cffi:foreign-slot-value in-buf-desc '(:struct aacenc-buf-desc) 'num-bufs) 1)
|
||||
(setf (cffi:foreign-slot-value in-buf-desc '(:struct aacenc-buf-desc) 'bufs) in-buf-ptr)
|
||||
(setf (cffi:foreign-slot-value in-buf-desc '(:struct aacenc-buf-desc) 'buf-ids) in-buf-id)
|
||||
(setf (cffi:foreign-slot-value in-buf-desc '(:struct aacenc-buf-desc) 'buf-sizes) in-buf-size)
|
||||
(setf (cffi:foreign-slot-value in-buf-desc '(:struct aacenc-buf-desc) 'buf-el-sizes) in-buf-el-size)
|
||||
(setf (cffi:mem-ref out-buf-ptr :pointer) out-buf)
|
||||
(setf (cffi:mem-ref out-buf-id :int) 1)
|
||||
(setf (cffi:mem-ref out-buf-size-ptr :int) out-buf-size)
|
||||
(setf (cffi:mem-ref out-buf-el-size :int) 1)
|
||||
(setf (cffi:foreign-slot-value out-buf-desc '(:struct aacenc-buf-desc) 'num-bufs) 1)
|
||||
(setf (cffi:foreign-slot-value out-buf-desc '(:struct aacenc-buf-desc) 'bufs) out-buf-ptr)
|
||||
(setf (cffi:foreign-slot-value out-buf-desc '(:struct aacenc-buf-desc) 'buf-ids) out-buf-id)
|
||||
(setf (cffi:foreign-slot-value out-buf-desc '(:struct aacenc-buf-desc) 'buf-sizes) out-buf-size-ptr)
|
||||
(setf (cffi:foreign-slot-value out-buf-desc '(:struct aacenc-buf-desc) 'buf-el-sizes) out-buf-el-size)
|
||||
(setf (cffi:foreign-slot-value in-args '(:struct aacenc-in-args) 'num-in-samples)
|
||||
(* num-samples channels))
|
||||
(setf (cffi:foreign-slot-value in-args '(:struct aacenc-in-args) 'num-ancillary-bytes) 0)
|
||||
(let ((result (aac-enc-encode handle in-buf-desc out-buf-desc in-args out-args)))
|
||||
(unless (zerop result)
|
||||
(error 'encoding-error :format :aac
|
||||
:message (format nil "aacEncEncode failed: ~A" result)))
|
||||
(let ((bytes-written (cffi:foreign-slot-value out-args '(:struct aacenc-out-args)
|
||||
'num-out-bytes)))
|
||||
(if (> bytes-written 0)
|
||||
(let ((result-vec (make-array bytes-written :element-type '(unsigned-byte 8))))
|
||||
(loop for i below bytes-written
|
||||
do (setf (aref result-vec i) (cffi:mem-aref out-buf :unsigned-char i)))
|
||||
result-vec)
|
||||
(make-array 0 :element-type '(unsigned-byte 8)))))))))
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
for j = write-pos then (mod (1+ j) size)
|
||||
do (setf (aref buf-data j) (aref data i))
|
||||
finally (setf (buffer-write-pos buffer) (mod (1+ j) size))))
|
||||
(bt:condition-notify (buffer-not-empty buffer))))
|
||||
len)
|
||||
(bt:condition-notify (buffer-not-empty buffer)))
|
||||
len))
|
||||
|
||||
(defun buffer-read (buffer output &key (start 0) (end (length output)) (blocking t))
|
||||
"Read bytes from BUFFER into OUTPUT. Returns number of bytes read.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
:depends-on (#:cl-streamer
|
||||
#:harmony
|
||||
#:cl-mixed
|
||||
#:cl-mixed-mpg123)
|
||||
#:cl-mixed-mpg123
|
||||
#:cl-mixed-flac)
|
||||
:components ((:file "harmony-backend")))
|
||||
|
||||
(asdf:defsystem #:cl-streamer/encoder
|
||||
|
|
@ -33,3 +34,10 @@
|
|||
#:cffi)
|
||||
:components ((:file "lame-ffi")
|
||||
(:file "encoder")))
|
||||
|
||||
(asdf:defsystem #:cl-streamer/aac-encoder
|
||||
:description "AAC encoding for cl-streamer (FDK-AAC)"
|
||||
:depends-on (#:cl-streamer
|
||||
#:cffi)
|
||||
:components ((:file "fdkaac-ffi")
|
||||
(:file "aac-encoder")))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
(in-package #:cl-streamer)
|
||||
|
||||
(defclass mp3-encoder ()
|
||||
((lame :initform nil :accessor encoder-lame)
|
||||
(sample-rate :initarg :sample-rate :accessor encoder-sample-rate :initform 44100)
|
||||
(channels :initarg :channels :accessor encoder-channels :initform 2)
|
||||
(bitrate :initarg :bitrate :accessor encoder-bitrate :initform 128)
|
||||
(quality :initarg :quality :accessor encoder-quality :initform 5)
|
||||
(mp3-buffer :initform nil :accessor encoder-mp3-buffer)
|
||||
(mp3-buffer-size :initform (* 1024 8) :accessor encoder-mp3-buffer-size)))
|
||||
|
||||
(defun make-mp3-encoder (&key (sample-rate 44100) (channels 2) (bitrate 128) (quality 5))
|
||||
"Create an MP3 encoder with the specified parameters.
|
||||
QUALITY: 0=best/slowest, 9=worst/fastest. 5 is good default."
|
||||
(let ((encoder (make-instance 'mp3-encoder
|
||||
:sample-rate sample-rate
|
||||
:channels channels
|
||||
:bitrate bitrate
|
||||
:quality quality)))
|
||||
(initialize-encoder encoder)
|
||||
encoder))
|
||||
|
||||
(defun initialize-encoder (encoder)
|
||||
"Initialize the LAME encoder with current settings."
|
||||
(let ((lame (lame-init)))
|
||||
(when (cffi:null-pointer-p lame)
|
||||
(error 'encoding-error :format :mp3 :message "Failed to initialize LAME"))
|
||||
(setf (encoder-lame encoder) lame)
|
||||
(lame-set-in-samplerate lame (encoder-sample-rate encoder))
|
||||
(lame-set-out-samplerate lame (encoder-sample-rate encoder))
|
||||
(lame-set-num-channels lame (encoder-channels encoder))
|
||||
(lame-set-mode lame (if (= (encoder-channels encoder) 1) :mono :joint-stereo))
|
||||
(lame-set-brate lame (encoder-bitrate encoder))
|
||||
(lame-set-quality lame (encoder-quality encoder))
|
||||
(lame-set-vbr lame :vbr-off)
|
||||
(let ((result (lame-init-params lame)))
|
||||
(when (< result 0)
|
||||
(lame-close lame)
|
||||
(error 'encoding-error :format :mp3
|
||||
:message (format nil "LAME init-params failed: ~A" result))))
|
||||
(setf (encoder-mp3-buffer encoder)
|
||||
(cffi:foreign-alloc :unsigned-char :count (encoder-mp3-buffer-size encoder)))
|
||||
(log:info "MP3 encoder initialized: ~Akbps, ~AHz, ~A channels"
|
||||
(encoder-bitrate encoder)
|
||||
(encoder-sample-rate encoder)
|
||||
(encoder-channels encoder))
|
||||
encoder))
|
||||
|
||||
(defun close-encoder (encoder)
|
||||
"Close the encoder and free resources."
|
||||
(when (encoder-lame encoder)
|
||||
(lame-close (encoder-lame encoder))
|
||||
(setf (encoder-lame encoder) nil))
|
||||
(when (encoder-mp3-buffer encoder)
|
||||
(cffi:foreign-free (encoder-mp3-buffer encoder))
|
||||
(setf (encoder-mp3-buffer encoder) nil)))
|
||||
|
||||
(defun encode-pcm-interleaved (encoder pcm-samples num-samples)
|
||||
"Encode interleaved PCM samples (16-bit signed) to MP3.
|
||||
PCM-SAMPLES should be a (simple-array (signed-byte 16) (*)).
|
||||
Returns a byte vector of MP3 data."
|
||||
(let* ((lame (encoder-lame encoder))
|
||||
(mp3-buf (encoder-mp3-buffer encoder))
|
||||
(mp3-buf-size (encoder-mp3-buffer-size encoder)))
|
||||
(cffi:with-pointer-to-vector-data (pcm-ptr pcm-samples)
|
||||
(let ((bytes-written (lame-encode-buffer-interleaved
|
||||
lame pcm-ptr num-samples mp3-buf mp3-buf-size)))
|
||||
(cond
|
||||
((< bytes-written 0)
|
||||
(error 'encoding-error :format :mp3
|
||||
:message (format nil "Encode failed: ~A" bytes-written)))
|
||||
((= bytes-written 0)
|
||||
(make-array 0 :element-type '(unsigned-byte 8)))
|
||||
(t
|
||||
(let ((result (make-array bytes-written :element-type '(unsigned-byte 8))))
|
||||
(loop for i below bytes-written
|
||||
do (setf (aref result i) (cffi:mem-aref mp3-buf :unsigned-char i)))
|
||||
result)))))))
|
||||
|
||||
(defun encode-flush (encoder)
|
||||
"Flush any remaining MP3 data from the encoder.
|
||||
Call this when done encoding to get final frames."
|
||||
(let* ((lame (encoder-lame encoder))
|
||||
(mp3-buf (encoder-mp3-buffer encoder))
|
||||
(mp3-buf-size (encoder-mp3-buffer-size encoder)))
|
||||
(let ((bytes-written (lame-encode-flush lame mp3-buf mp3-buf-size)))
|
||||
(if (> bytes-written 0)
|
||||
(let ((result (make-array bytes-written :element-type '(unsigned-byte 8))))
|
||||
(loop for i below bytes-written
|
||||
do (setf (aref result i) (cffi:mem-aref mp3-buf :unsigned-char i)))
|
||||
result)
|
||||
(make-array 0 :element-type '(unsigned-byte 8))))))
|
||||
|
||||
(defun lame-version ()
|
||||
"Return the LAME library version string."
|
||||
(get-lame-version))
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
(in-package #:cl-streamer)
|
||||
|
||||
(cffi:define-foreign-library libfdkaac
|
||||
(:unix (:or "libfdk-aac.so.2" "libfdk-aac.so"))
|
||||
(:darwin "libfdk-aac.dylib")
|
||||
(:windows "libfdk-aac.dll")
|
||||
(t (:default "libfdk-aac")))
|
||||
|
||||
(cffi:use-foreign-library libfdkaac)
|
||||
|
||||
(cffi:defctype aac-encoder-handle :pointer)
|
||||
|
||||
(cffi:defcenum aac-encoder-param
|
||||
(:aacenc-aot #x0100)
|
||||
(:aacenc-bitrate #x0101)
|
||||
(:aacenc-bitratemode #x0102)
|
||||
(:aacenc-samplerate #x0103)
|
||||
(:aacenc-sbr-mode #x0104)
|
||||
(:aacenc-granule-length #x0105)
|
||||
(:aacenc-channelmode #x0106)
|
||||
(:aacenc-channelorder #x0107)
|
||||
(:aacenc-sbr-ratio #x0108)
|
||||
(:aacenc-afterburner #x0200)
|
||||
(:aacenc-bandwidth #x0203)
|
||||
(:aacenc-transmux #x0300)
|
||||
(:aacenc-header-period #x0301)
|
||||
(:aacenc-signaling-mode #x0302)
|
||||
(:aacenc-tpsubframes #x0303)
|
||||
(:aacenc-protection #x0306)
|
||||
(:aacenc-ancillary-bitrate #x0500)
|
||||
(:aacenc-metadata-mode #x0600))
|
||||
|
||||
(cffi:defcenum aac-encoder-error
|
||||
(:aacenc-ok #x0000)
|
||||
(:aacenc-invalid-handle #x0020)
|
||||
(:aacenc-memory-error #x0021)
|
||||
(:aacenc-unsupported-parameter #x0022)
|
||||
(:aacenc-invalid-config #x0023)
|
||||
(:aacenc-init-error #x0040)
|
||||
(:aacenc-init-aac-error #x0041)
|
||||
(:aacenc-init-sbr-error #x0042)
|
||||
(:aacenc-init-tp-error #x0043)
|
||||
(:aacenc-init-meta-error #x0044)
|
||||
(:aacenc-encode-error #x0060)
|
||||
(:aacenc-encode-eof #x0080))
|
||||
|
||||
(cffi:defcenum aac-channel-mode
|
||||
(:mode-invalid -1)
|
||||
(:mode-unknown 0)
|
||||
(:mode-1 1)
|
||||
(:mode-2 2)
|
||||
(:mode-1-2 3)
|
||||
(:mode-1-2-1 4)
|
||||
(:mode-1-2-2 5)
|
||||
(:mode-1-2-2-1 6)
|
||||
(:mode-1-2-2-2-1 7))
|
||||
|
||||
(cffi:defcenum aac-transmux
|
||||
(:tt-unknown -1)
|
||||
(:tt-raw 0)
|
||||
(:tt-adif 1)
|
||||
(:tt-adts 2)
|
||||
(:tt-latm-mcp1 6)
|
||||
(:tt-latm-mcp0 7)
|
||||
(:tt-loas 10))
|
||||
|
||||
(cffi:defcenum aac-aot
|
||||
(:aot-none -1)
|
||||
(:aot-null 0)
|
||||
(:aot-aac-main 1)
|
||||
(:aot-aac-lc 2)
|
||||
(:aot-aac-ssr 3)
|
||||
(:aot-aac-ltp 4)
|
||||
(:aot-sbr 5)
|
||||
(:aot-aac-scal 6)
|
||||
(:aot-er-aac-lc 17)
|
||||
(:aot-er-aac-ld 23)
|
||||
(:aot-er-aac-eld 39)
|
||||
(:aot-ps 29)
|
||||
(:aot-mp2-aac-lc 129)
|
||||
(:aot-mp2-sbr 132))
|
||||
|
||||
(cffi:defcstruct aacenc-buf-desc
|
||||
(num-bufs :int)
|
||||
(bufs :pointer)
|
||||
(buf-ids :pointer)
|
||||
(buf-sizes :pointer)
|
||||
(buf-el-sizes :pointer))
|
||||
|
||||
(cffi:defcstruct aacenc-in-args
|
||||
(num-in-samples :int)
|
||||
(num-ancillary-bytes :int))
|
||||
|
||||
(cffi:defcstruct aacenc-out-args
|
||||
(num-out-bytes :int)
|
||||
(num-in-samples :int)
|
||||
(num-ancillary-bytes :int))
|
||||
|
||||
(cffi:defcstruct aacenc-info-struct
|
||||
(max-out-buf-bytes :uint)
|
||||
(max-ancillary-bytes :uint)
|
||||
(in-buf-fill-level :uint)
|
||||
(input-channels :uint)
|
||||
(frame-length :uint)
|
||||
(encoder-delay :uint)
|
||||
(conf-buf :pointer)
|
||||
(conf-size :uint))
|
||||
|
||||
(cffi:defcfun ("aacEncOpen" aac-enc-open) :int
|
||||
(ph-aac-encoder :pointer)
|
||||
(enc-modules :uint)
|
||||
(max-channels :uint))
|
||||
|
||||
(cffi:defcfun ("aacEncClose" aac-enc-close) :int
|
||||
(ph-aac-encoder :pointer))
|
||||
|
||||
(cffi:defcfun ("aacEncEncode" aac-enc-encode) :int
|
||||
(h-aac-encoder aac-encoder-handle)
|
||||
(in-buf-desc :pointer)
|
||||
(out-buf-desc :pointer)
|
||||
(in-args :pointer)
|
||||
(out-args :pointer))
|
||||
|
||||
(cffi:defcfun ("aacEncInfo" aac-enc-info) :int
|
||||
(h-aac-encoder aac-encoder-handle)
|
||||
(p-info :pointer))
|
||||
|
||||
(cffi:defcfun ("aacEncoder_SetParam" aac-encoder-set-param) :int
|
||||
(h-aac-encoder aac-encoder-handle)
|
||||
(param aac-encoder-param)
|
||||
(value :uint))
|
||||
|
||||
(cffi:defcfun ("aacEncoder_GetParam" aac-encoder-get-param) :uint
|
||||
(h-aac-encoder aac-encoder-handle)
|
||||
(param aac-encoder-param))
|
||||
|
|
@ -32,7 +32,6 @@
|
|||
"Parse an ICY/HTTP request. Returns (values mount-point wants-metadata-p).
|
||||
HEADERS is an alist of (name . value) pairs."
|
||||
(let* ((parts (split-sequence:split-sequence #\Space request-line))
|
||||
(method (first parts))
|
||||
(path (second parts))
|
||||
(icy-metadata-header (cdr (assoc "icy-metadata" headers :test #'string-equal))))
|
||||
(values path
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
(in-package #:cl-streamer)
|
||||
|
||||
(cffi:define-foreign-library liblame
|
||||
(:unix (:or "libmp3lame.so.0" "libmp3lame.so"))
|
||||
(:darwin "libmp3lame.dylib")
|
||||
(:windows "libmp3lame.dll")
|
||||
(t (:default "libmp3lame")))
|
||||
|
||||
(cffi:use-foreign-library liblame)
|
||||
|
||||
(cffi:defctype lame-global-flags :pointer)
|
||||
|
||||
(cffi:defcenum lame-vbr-mode
|
||||
(:vbr-off 0)
|
||||
(:vbr-mt 1)
|
||||
(:vbr-rh 2)
|
||||
(:vbr-abr 3)
|
||||
(:vbr-mtrh 4)
|
||||
(:vbr-default 4))
|
||||
|
||||
(cffi:defcenum lame-mode
|
||||
(:stereo 0)
|
||||
(:joint-stereo 1)
|
||||
(:dual-channel 2)
|
||||
(:mono 3))
|
||||
|
||||
(cffi:defcfun ("lame_init" lame-init) lame-global-flags)
|
||||
|
||||
(cffi:defcfun ("lame_close" lame-close) :int
|
||||
(gfp lame-global-flags))
|
||||
|
||||
(cffi:defcfun ("lame_set_in_samplerate" lame-set-in-samplerate) :int
|
||||
(gfp lame-global-flags)
|
||||
(rate :int))
|
||||
|
||||
(cffi:defcfun ("lame_set_out_samplerate" lame-set-out-samplerate) :int
|
||||
(gfp lame-global-flags)
|
||||
(rate :int))
|
||||
|
||||
(cffi:defcfun ("lame_set_num_channels" lame-set-num-channels) :int
|
||||
(gfp lame-global-flags)
|
||||
(channels :int))
|
||||
|
||||
(cffi:defcfun ("lame_set_mode" lame-set-mode) :int
|
||||
(gfp lame-global-flags)
|
||||
(mode lame-mode))
|
||||
|
||||
(cffi:defcfun ("lame_set_quality" lame-set-quality) :int
|
||||
(gfp lame-global-flags)
|
||||
(quality :int))
|
||||
|
||||
(cffi:defcfun ("lame_set_brate" lame-set-brate) :int
|
||||
(gfp lame-global-flags)
|
||||
(brate :int))
|
||||
|
||||
(cffi:defcfun ("lame_set_VBR" lame-set-vbr) :int
|
||||
(gfp lame-global-flags)
|
||||
(vbr-mode lame-vbr-mode))
|
||||
|
||||
(cffi:defcfun ("lame_set_VBR_quality" lame-set-vbr-quality) :int
|
||||
(gfp lame-global-flags)
|
||||
(quality :float))
|
||||
|
||||
(cffi:defcfun ("lame_init_params" lame-init-params) :int
|
||||
(gfp lame-global-flags))
|
||||
|
||||
(cffi:defcfun ("lame_encode_buffer_interleaved" lame-encode-buffer-interleaved) :int
|
||||
(gfp lame-global-flags)
|
||||
(pcm :pointer)
|
||||
(num-samples :int)
|
||||
(mp3buf :pointer)
|
||||
(mp3buf-size :int))
|
||||
|
||||
(cffi:defcfun ("lame_encode_buffer" lame-encode-buffer) :int
|
||||
(gfp lame-global-flags)
|
||||
(buffer-l :pointer)
|
||||
(buffer-r :pointer)
|
||||
(num-samples :int)
|
||||
(mp3buf :pointer)
|
||||
(mp3buf-size :int))
|
||||
|
||||
(cffi:defcfun ("lame_encode_flush" lame-encode-flush) :int
|
||||
(gfp lame-global-flags)
|
||||
(mp3buf :pointer)
|
||||
(mp3buf-size :int))
|
||||
|
||||
(cffi:defcfun ("lame_get_lametag_frame" lame-get-lametag-frame) :size
|
||||
(gfp lame-global-flags)
|
||||
(buffer :pointer)
|
||||
(size :size))
|
||||
|
||||
(cffi:defcfun ("get_lame_version" get-lame-version) :string)
|
||||
Loading…
Reference in New Issue