Git Product home page Git Product logo

bdef's Introduction

bdef

“Buffer definition”; abstraction of audio buffers for Lisp sound synthesis systems.

Basically, this simplifies buffer management in cl-collider, making them easier to use.

Note: Previously Bdef for SuperCollider was hosted at this URL. That repository has since moved here.

Intro

Bdef is available from Quicklisp, so you can simply Quickload it:

(ql:quickload :bdef)

It also has multiple sub-systems for integration with various other libraries. So if you use cl-patterns, cl-collider, or Incudine you may want to load bdef/cl-patterns and/or the other sub-systems:

;; integration with cl-patterns and cl-collider:
(ql:quickload '(bdef/cl-patterns bdef/cl-collider))

To load a buffer from a file, provide the path to the bdef function:

(bdef "~/path/to/your/buffer.mp3")

;; you can also give it an alias:
(bdef :foo "/path/to/buffer.wav")

;; the buffer can then be referred to with it:
(bdef :foo)

bdef returns a bdef object which can be provided in place of a buffer for any functions that expect it, as long as you’ve quickloaded the proper bdef sub-system for the library those functions are from. For example:

;; cl-collider:
(synth :playbuf :buffer (bdef :foo)) ; will work if you've loaded the bdef/cl-collider system.

;; cl-patterns:
(play (event :instrument :playbuf :buffer :foo)) ; will work if you've loaded the bdef/cl-patterns system.
;; Notice that you can just specify the bdef name as a symbol without even having to use the bdef function! The same is true in patterns too.

Metadata can be associated with bdefs for various uses:

(setf (bdef-metadata :foo :bpm) 120) ; set the "bpm" metadatum to 120

Some metadata is automatically generated; for example, the tempo may be automatically detected from the filename or id3 tags.

bdef includes functionality for defining buffer regions called splits. This is useful, for instance, to divide a drum loop up by each hit, or to divide up a source track into sections based on onsets or beats.

;; define three consecutive regions, one second long each:
(make-splits (list (list 0 1) (list 1 2) (list 2 3)) :unit :seconds)

;; auto-generate splits from sound onsets in a file using the aubio library:
(splits-from-aubio-onsets "/path/to/file.wav")

Aubio is an external library of audio analysis functions. If installed, splits can be automatically generated from its analyses.

bdef can also generate splits from other formats as well:

  • OP-1 drumsets (splits-from-op-1-drumset, but automatically parsed from any valid aif or aiff file)
  • Audacity labels (splits-from-audacity-labels)
  • Renoise regions (planned for future implementation)

See the following section for detail on more features of the bdef library.

Features

Can be re-evaluated without loading a new buffer:

Compare:

(defparameter *buf* (cl-collider:buffer-read "/buffer.wav"))

(defparameter *buf* (cl-collider:buffer-read "/buffer.wav")) ; the same variable, and same file!

(length (remove nil (slot-value *s* 'cl-collider::buffers))) ; => 2 -- duplicate buffers!

versus:

(bdef :buf "/buffer.wav") ; here we give it the name :buf

(bdef :foo "/buffer.wav") ; same file, different "name"...

(length (remove nil (slot-value *s* 'cl-collider::buffers))) ; => 1 -- no duplicate buffers :D

…To force a file to be reloaded, simply call bdef-free on it, then call bdef again.

Automatically converts files unsupported by the backend if you have ffmpeg installed:

(bdef :bar "/blah.mp3") ; works!

It does this by storing them in a temporary directory (/tmp/bdef/ by default on linux and mac).

No additional name needed if loading from a file:

(bdef "/my-file.ogg")

Supports pathname abbreviations:

(bdef "~/cool-sound.wav") ; will find a cool sound in your home directory

Loads mono files as stereo by default.

For consistency. To load as mono, supply 1 for bdef’s num-channels keyword argument.

Supports loading in wavetable format:

(bdef "~/wilhelm.wav" :wavetable t) ; load the Wilhelm scream as a wavetable

Supports loading envelopes as buffers:

Either as wavetables, or standard.

Integration with cl-collider:

(cl-collider:bufnum (bdef :sound)) ; returns the buffer number.

(cl-collider:synth :playbuf :bufnum (bdef :sound)) ; plays the buffer.

Load the bdef/cl-collider system to enable this.

Integration with cl-patterns:

(cl-patterns:play (bdef :sound)) ; plays the buffer using the *cl-collider-buffer-preview-synth* set in cl-patterns.

(cl-patterns:play (cl-patterns:event :instrument :playbuf :bufnum (bdef :sound))) ; automatically converts bdef to the buffer number.

Load the bdef/cl-patterns system to enable this.

Supports multiple sound server backends:

SuperCollider/cl-collider is the primary backend tested against, however Incudine is also supported for most functionality.

Enable the cl-collider backend, for example, like so:

(ql:quickload :bdef/cl-collider)

Allows metadata about the buffer to be stored:

(setf (bdef-metadata (bdef :snd) :bpm) 99) ; set :snd's tempo to 99 BPM.

(bdef-metadata (bdef :snd) :bpm) ; get the stored bpm value.

Automatically set various metadata when a bdef is created:

;; load a file with its bpm in its filename:
(bdef :my-file "~/my-file-128bpm.wav")

;; the bpm is automatically stored as metadata:
(bdef-metadata :my-file :bpm) ; => 128

You can also add your own auto-metadata keys with the define-bdef-auto-metadata macro or set-bdef-auto-metadata function, or remove them with the remove-bdef-auto-metadata function.

Additional metadata is loaded asynchronously in background threads using futures from the eager-future2 library. If a requested metadatum is still being generated, bdef-metadata will block until the result is available.

Automatically generate metadata from functions:

(setf (bdef-metadata :foo :bpm) 142) ; sets the "tempo" metadata key instead to its beats per minute value

;; tempo is stored as beats per second:
(bdef-metadata :foo :tempo) ; => 71/30 (142 beats per minute in beats per second)

;; beats per minute is still available, dynamically calculated from the tempo key:
(bdef-metadata :foo :bpm) ; => 142

You can define your own “dynamic metadata” with define-bdef-dynamic-metadata.

“Splits” functionality to define split points or regions in buffers:

(make-splits (list 0 0.25 0.5 0.75) :bdef (bdef :foo)) ; splits at the start, 25%, 50%, and 75% into the file.

(splits-from-audacity-labels "/path/to/label.txt") ; make a splits object from an Audacity labels file.

(setf (bdef-splits :my-bdef) *) ; set the :my-bdef bdef's :splits metadatum to the splits object generated from the above.

(splits-point :my-bdef 3 :start :second) ; get the start of :my-bdef's fourth split in seconds.

Splits integration with cl-patterns:

(pbind :instrument :playbuf
       :bufnum (bdef :my-bdef)
       :split (pwhite 0 (1- (splits-length :my-bdef))) ; pick a random split
       :embed (psplits) ; the psplits pattern yields events with :start, :end, and :dur keys to play the split specified by :split from the :splits metadatum of the bdef specified as :bufnum.
       :dur 1)

Integration with the Aubio audio analysis library if installed:

(bdef::splits-from-aubio-onsets "/path/to/audio/file.wav")

(bdef :pee "/path/to/pee.wav") ; since no BPM is listed in the filename, aubio is used to detect it (if installed)...

(bdef-metadata :pee :tempo) ; ...and it is stored in the bdef's :tempo metadatum! nice!

Ability to import splits from OP-1 drumset file metadata:

(bdef::splits-from-op-1-drumset "/path/to/op-1-drumset.aif") ; generates a splits by parsing the metadata in the file.

Note that any aif or aiff file will automatically be checked for OP-1 metadata, which will be parsed and stored in the splits bdef metadata key if it is found.

Backends

Currently, bdef supports SuperCollider via cl-collider as a backend. There is also basic (likely buggy) Incudine support - this will be improved later.

To write your own backend, you will need to implement the following methods on your backend’s buffer class:

  • bdef-backend-supported-file-types
  • bdef-backend-load
  • bdef-backend-free
  • bdef-length
  • bdef-sample-rate
  • bdef-channels
  • bdef-id (optional if your backend doesn’t use buffer IDs)
  • bdef-file (optional if your backend doesn’t keep track of what file a buffer was loaded from)
  • bdef-frames

All other functionality is derived from those functions.

For the user’s convenience, you might also want to define methods on the bdef class for the backend’s relevant functions; see the bottom of cl-collider.lisp for an example.

Future

  • Fix the various minor/not-so-minor issues marked with “FIX” in the code.
  • We have bdef-frames to get buffer data; we should have support for setting buffer data as well.
  • Support for configurable pathname shortcuts. (i.e. set foo as a shortcut to /a/long/path/name/, then provide ~”foo/bar.wav”~ instead of ~”/a/long/path/name/bar.wav”~.)
  • “Dynamic” splits; i.e. define a set of splits as “this region in four equal-length pieces” rather than all splits being immediately “baked” as specific points.
  • Allow importing as splits from .srt (subtitle) files, .tsv (tab-separated values; this seems to be what Audacity uses, and Whisper has an option to export in this format), and .vtt (WebVTT; similar to .srt)?

bdef's People

Contributors

defaultxr avatar miker2049 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

bdef's Issues

Some systems failed to build for Quicklisp dist

Building with SBCL 2.1.10.195-bca540cd6 / ASDF 3.3.5 for quicklisp dist creation.

Trying to build commit id 9a20de6

bdef/cl-patterns fails to build with the following error:

; caught WARNING:
;   DEPRECATED-FUNCTION-WARNING: Using deprecated function BDEF::BDEF-REF -- please update your code to use a newer API.
;   The docstring for this function says:
;   Deprecated alias for `find-bdef'.
;   
...
Unhandled UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001BFC103}>: COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "bdef/cl-patterns" "cl-patterns">

bdef/tests fails to build because of a failure in bdef/cl-patterns.

Full log here

undocumented-symbols now in test-helpers, so undefined in the test

The test uses undocumented-symbols, which was defined in "mutility", but is now in "mutility/test-helpers", so it is undefined.

Adding "mutility/test-helpers" to the :depned-on of "bdef/tests" fixes it, but it is probably better to put undocumented-symbols back in "mutility" itself.

After the fix it errors with undocumented symbols:
(*BDEF-TEMPORARY-DIRECTORY* SPLITS-FROM-OP-1-DRUMSET BDEF-ID BDEF-KEY)

op-1-format-to-frame and frame-to-op-1-format are just broken, op-1-format-to-frame.new almost correct.

The function frame-to-op-1-format is completely broken, and seems to a mis-interpretation o fthe code in https://github.com/padenot/libop1/blob/master/src/op1_drum_impl.cpp. The function frame-to-op-1-format.new is close to what the C code does. To do precisely what the C code does it needs to do:

 (* (floor +op-1-drumkit-end+ +op-1-bytes-in-12-sec+)
      frame +size-of-uint16-t+)

[assuming that frame is an integer]

op-1-format-to-frame also broken. The function op-1-format-to-frame.new multiply by +size-of-uint16-t+ instead of dividing by it. To match frame-to-op-1-format, op-1-format-to-frame needs to do:

(round
   (/  op-1
       (* (floor +op-1-drumkit-end+ +op-1-bytes-in-12-sec+)
          +size-of-uint16-t+)))

The test op-1 will not work as is even after the fix, because op-1 value of 40 is rounded to 0. Switching the calls, so 40 is the frame number, make it work with the fixed functions.

Failed to build for Quicklisp dist

Building with SBCL 2.0.9.5-442f54894 / ASDF 3.3.1 for quicklisp dist creation.

Commit id 954ed51

bdef/incudine fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001A50103}>: Component #:INCUDINE not found, required by #<SYSTEM "bdef/incudine">

Full log here

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.