Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non usb8 buffers #3

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@ To play random noise on one channel of default stereo device:
(defconstant +channels+ 2)

(also-alsa:with-alsa-device (pcm "sysdefault" +buffer-size+ '(signed-byte 16) :direction :output
:channels-count +channels+ :sample-rate +sample-rate+)
:channels-count +channels+ :sample-rate +sample-rate+)
(also-alsa:alsa-start pcm)
(loop repeat 2 do
(loop with buffer = (also-alsa:buffer pcm)
for pos from 0 below (* +channels+ (also-alsa:buffer-size pcm)) by (* 2 +channels+)
for sample = (coerce (- (random 65535) 32767) '(signed-byte 16)) do
(setf (aref buffer pos) (logand sample #xff))
(setf (aref buffer (1+ pos)) (logand (ash sample -8) #xff))
(multiple-value-bind (avail delay) (also-alsa:get-avail-delay pcm)
(also-alsa:alsa-write pcm)))))

(loop with buffer = (also-alsa:buffer pcm)
for pos from 0 below (also-alsa:buffer-size pcm)
for sample = (coerce (- (random 65535) 32767) '(signed-byte 16)) do
(setf (aref buffer pos) sample)
(multiple-value-bind (avail delay) (also-alsa:get-avail-delay pcm)
(also-alsa:alsa-write pcm))))
```
104 changes: 60 additions & 44 deletions also-alsa.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@

(defun alsa-element-type (type)
(cond ((equalp type '(signed-byte 16)) :int16)
((eql type 'single-float) :float)
((eql type 'single-float) :float)
((eql type 'double-float) :double)
((equalp type '(unsigned-byte 8)) :uint8)
((equalp type '(signed-byte 8)) :int8)
Expand Down Expand Up @@ -210,20 +210,22 @@
pcs)

(defun make-alsa-buffer (&key element-type size channels)
(cffi:make-shareable-byte-vector (* (cffi:foreign-type-size (alsa-element-type element-type)) size channels)))
(if (equalp element-type '(unsigned-byte 8))
(cffi:make-shareable-byte-vector (* size channels))
(make-array (* size channels) :element-type element-type)))

(defun alsa-open (device buffer-size element-type &key direction (sample-rate 44100) (channels-count 2) buffer)
(when buffer
(assert (and (subtypep (type-of buffer) 'simple-array)
(subtypep (array-element-type buffer) element-type))))
(subtypep (array-element-type buffer) element-type))))
(let ((pcs (make-instance 'pcm-stream
:direction (case direction
(:input :snd-pcm-stream-capture)
(:output :snd-pcm-stream-playback))
:device device
:element-type element-type
:buffer (or buffer
(make-alsa-buffer :element-type element-type :size buffer-size :channels channels-count))
(make-alsa-buffer :element-type element-type :size buffer-size :channels channels-count))
:buffer-size (* buffer-size channels-count) ;number of samples really
:channels-count channels-count
:sample-rate sample-rate
Expand All @@ -234,33 +236,35 @@
(:documentation "Reopens the stream. If all parameters are the same, just keeps the exiting one."))

(defmethod alsa-reopen ((pcs pcm-stream) device buffer-size element-type &key direction (sample-rate 44100) (channels-count 2))
(if (or (eql (status pcs) :initial)
(not (and (equal device (device pcs))
(= (* buffer-size channels-count) (buffer-size pcs))
(equal element-type (element-type pcs))
(eql direction (case (direction pcs)
(:snd-pcm-stream-capture :input)
(:snd-pcm-stream-playback :output)))
(= sample-rate (sample-rate pcs))
(= channels-count (channels-count pcs)))))
(progn
(when (eql (status pcs) :open)
(alsa-close pcs))
(alsa-open-2 (reinitialize-instance pcs
:direction (case direction
(:input :snd-pcm-stream-capture)
(:output :snd-pcm-stream-playback))
:device device
:element-type element-type
:buffer (cffi:make-shareable-byte-vector
(* (cffi:foreign-type-size (alsa-element-type element-type)) buffer-size channels-count))
#+nil(foreign-alloc (alsa-element-type element-type)
:count (* (cffi:foreign-type-size (alsa-element-type element-type)) buffer-size channels-count))
:buffer-size (* buffer-size channels-count) ;number of samples really
:channels-count channels-count
:sample-rate sample-rate
:pcm-format (to-alsa-format element-type))))
(snd-pcm-drop (deref (handle pcs))))
(if (or (eql (status pcs) :initial)
(not (and (equal device (device pcs))
(= (* buffer-size channels-count) (buffer-size pcs))
(equal element-type (element-type pcs))
(eql direction (case (direction pcs)
(:snd-pcm-stream-capture :input)
(:snd-pcm-stream-playback :output)))
(= sample-rate (sample-rate pcs))
(= channels-count (channels-count pcs)))))
(progn
(when (eql (status pcs) :open)
(alsa-close pcs))
(alsa-open-2 (reinitialize-instance
pcs
:direction (case direction
(:input :snd-pcm-stream-capture)
(:output :snd-pcm-stream-playback))
:device device
:element-type element-type
:buffer (make-alsa-buffer :element-type element-type
:size buffer-size
:channels channels-count)
#+nil(foreign-alloc (alsa-element-type element-type)
:count (* (cffi:foreign-type-size (alsa-element-type element-type)) buffer-size channels-count))
:buffer-size (* buffer-size channels-count) ;number of samples really
:channels-count channels-count
:sample-rate sample-rate
:pcm-format (to-alsa-format element-type))))
(snd-pcm-drop (deref (handle pcs))))
pcs)

(defmethod ref ((pcm pcm-stream) position)
Expand Down Expand Up @@ -307,32 +311,44 @@
(defmethod alsa-write ((pcm pcm-stream))
(assert (eql (direction pcm) :snd-pcm-stream-playback))
(let* ((expected (/ (buffer-size pcm) (channels-count pcm)))
(result (with-pointer-to-vector-data (ptr (buffer pcm))
(snd-pcm-writei (deref (handle pcm)) ptr expected))))
(element-type (array-element-type (buffer pcm)))
(result (if (equalp element-type '(unsigned-byte 8))
(with-pointer-to-vector-data (ptr (buffer pcm))
(snd-pcm-writei (deref (handle pcm)) ptr expected))
(with-foreign-array
(ptr (buffer pcm)
(cffi::ensure-parsed-base-type
(list :array (alsa-element-type element-type) expected)))
(snd-pcm-writei (deref (handle pcm)) ptr expected)))))
(cond ((= result (- +epipe+))
;; Under run, so prepare and retry
(alsa-warn "Underrun!")
(alsa-warn "Underrun!")
(snd-pcm-prepare (deref (handle pcm)))
(alsa-write pcm))
((/= result expected)
(error "ALSA error: ~A" result)))))

(defmethod alsa-read ((pcm pcm-stream))
(assert (eql (direction pcm) :snd-pcm-stream-capture))
(let ((result (with-pointer-to-vector-data (ptr (buffer pcm))
(snd-pcm-readi (deref (handle pcm)) ptr (/ (buffer-size pcm) (channels-count pcm))))))
(let* ((expected (/ (buffer-size pcm) (channels-count pcm)))
(element-type (array-element-type (buffer pcm)))
(result (if (equalp element-type '(unsigned-byte 8))
(with-pointer-to-vector-data (ptr (buffer pcm))
(snd-pcm-readi (deref (handle pcm)) ptr expected))
(with-foreign-array
(ptr (buffer pcm)
(cffi::ensure-parsed-base-type
(list :array (alsa-element-type element-type) expected)))
(prog1
(snd-pcm-readi (deref (handle pcm)) ptr expected)
(setf (slot-value pcm 'buffer)
(foreign-array-to-lisp ptr cffi-type :element-type element-type)))))))
(unless (= result (/ (buffer-size pcm) (channels-count pcm)))
(if (eql result (- +epipe+))
(progn (alsa-warn "Underrun!") (snd-pcm-prepare (deref (handle pcm))))
(error "ALSA error: ~A" result)))
(progn (alsa-warn "Underrun!") (snd-pcm-prepare (deref (handle pcm))))
(error "ALSA error: ~A" result)))
pcm))

(defmethod contents-to-lisp ((pcm pcm-stream))
(let ((result (make-array (buffer-size pcm) :element-type (element-type pcm))))
(loop for i from 0 below (buffer-size pcm) do
(setf (aref result i) (ref pcm i)))
result))

(defmacro with-alsa-device ((stream device buffer-size element-type &key direction (sample-rate 44100) (channels-count 2) buffer) &body body)
(assert direction)
`(let ((,stream (also-alsa:alsa-open ,device ,buffer-size ,element-type
Expand Down