byulparan / cl-collider

A SuperCollider client for CommonLisp
Other
218 stars 23 forks source link

better buffer-get-*, + buffer-to-list and buffer-to-array functions #104

Closed defaultxr closed 3 years ago

defaultxr commented 3 years ago

This change fixes a bug in my previous implementation of buffer-get-to-list; it incorrectly limited the maximum number of frames to (frames buffer) rather than (* (chanls buffer) (frames buffer)).

Additionally, it introduces buffer-to-list which forwards to buffer-load-to-list by default, or to buffer-get-to-list if buffer-load-to-list is not available (i.e. non-local server).

It also introduces buffer-get-to-array, buffer-load-to-array and buffer-to-array which are similar to buffer-get-to-list, buffer-load-to-list and buffer-to-list, respectively, except that they return a (possibly multidimensional) array of the buffer's channels, rather than simply a flat list of the interlaced frame data.

i.e. for a 2-channel buffer *buf*:

;; one channel, single-dimension array of the channel:
(array-dimensions (buffer-to-array *buf* 0 200 0)) ;=> (200)

;; one channel as a list, 2-dimension array of the channel:
(array-dimensions (buffer-to-array *buf* 0 200 '(0))) ;=> (1 200)

;; two channels as a list, 2-dimensional array of the channels:
(array-dimensions (buffer-to-array *buf* 0 200 '(0 1))) ;=> (2 200)

;; defaults to all channels:
(array-dimensions (buffer-to-array *buf* 0 200)) ;=> (2 200)

Additionally, for consistency and ease of use, buffer-getn, buffer-get-to-list, and buffer-load-to-list now take START and END as arguments instead of START and FRAMES (as do all buffer-to-* and buffer-get* functions). This is obviously an incompatible change but judging by the fact that no one noticed these functions were broken, I feel it is unlikely to cause major problems.

Docstrings have been updated and improved to explain the differences between the functions, and each one suggests the best function for the job (i.e. buffer-to-list or buffer-to-array).

ntrocado commented 3 years ago

I think this is useful! I wonder if buffer-to-array on a single channel buffer shouldn't return a one-dimensional array... Currently it returns:

(let ((buf (buffer-alloc 10))) 
  (array-rank (buffer-to-array buf)))

;=> 2
defaultxr commented 3 years ago

@ntrocado I figured it would be more consistent to always return a 2-dimensional array when channels is not specified, even if the buffer only has one channel. That way it's not necessary to have a special case in code that calls buffer-to-list for the possibility of it returning a 1-dimensional array.

If the user only wants a one-dimensional array of one channel, they can supply just the channel number as the value of channel, i.e. (buffer-to-array buf 0 10 0) which returns a 1D array of just the first channel. Similarly (buffer-to-array buf 0 10 '(0)) returns a 2D array of the first channel.

Thanks for pointing out those spelling mistakes; I will fix them in a future PR.

Also, looking at this again now, it seems like it may be better to use &key arguments instead of &optional since a user may want to specify channels without having to also specify start and end. Either that or I should make it possible to supply -1 as the end value since that would be more convenient than the user having to provide (frames buf). Opinions?

ntrocado commented 3 years ago

I think I prefer &key in this case, but it's obviously debatable. I also prefer nil instead of -1, because it's consistent with the CL spec, like in find, subseq, etc.