Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/candera/dynne
A Clojure library for working with audio.
https://github.com/candera/dynne
Last synced: 20 days ago
JSON representation
A Clojure library for working with audio.
- Host: GitHub
- URL: https://github.com/candera/dynne
- Owner: candera
- Created: 2013-06-14T19:14:55.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2017-05-07T13:01:23.000Z (over 7 years ago)
- Last Synced: 2024-12-09T09:51:19.746Z (25 days ago)
- Language: Clojure
- Size: 140 KB
- Stars: 100
- Watchers: 10
- Forks: 5
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# dynne
> "This is my assistant, the awful DYNNE," said Dr. Dischord.
> "You must forgive his appearance, for he really doesn't have any."From _The Phantom Tollbooth_, by Norton Juster
A library for working with audio data. Supports manipulating, playing,
visualizing, and saving sounds. Sounds can be read in .wav and .mp3
formats, and saved in .wav format.## Installation
Available on [Clojars](https://clojars.org/org.craigandera/dynne). Put
this in your `project.clj`:```
[org.craigandera/dynne "0.4.1"]
```## Concepts
The basic concept in dynne is the _sound_. A sound is the combination
of a duration, a number of channels, and a **deferred** way to get the
amplitudes of all the channels. There is a protocol,
`dynne.sampled-sound/SampledSound` that gives these capabilities
through its `duration`, `channels` and `chunks` functions,
respectively.Calling `chunks` returns a Clojure seq of chunks. A _chunk_ is a seq
of Java primitive double arrays, one per channel. All arrays in the
chunk will be the same length. Amplitudes are represented as
double-precision floating point numbers, which will be clipped to -1.0
and 1.0 (inclusive) when a sound is saved (via _save_ ).Constructors for sounds are given for WAV and MP3 files
( _read-sound_ ), and for arbitrary functions ( _fn-sound_ ).Processor functions accept one or more sounds and return a new sound.
Combination is by functional composition, so combining two sounds does
not result in the underlying sound being sampled - computation of the
combined operation is deferred until the combined sound is sampled.## Usage
```clojure
(require '[dynne.sampled-sound :refer :all])
;; Or, to use the API based on core.async
;; (require '[dynne.async-sound :refer :all]);; Create a simple one-second, 440 Hz sine wave sound
(def s (sinusoid 1.0 440));; See what it looks like
(visualize s);; See what the first 0.01 seconds look like
(visualize (trim s 0 0.01));; Play it. Maybe turn down your volume a bit first. :)
(play s);; Define a new sound that fades `s` in over 0.5 seconds
(def s2 (fade-in s 0.5));; Visualize that
(visualize s2);; Get the double array holding the raw amplitude data of the first
;; channel of the first chunk. Note that we have to pass a sample
;; rate. File-based sounds will be converted to this rate.
(ffirst (chunks s2 16000))
;; => #;; Build up a more complicated sound
(def l (-> (sinusoid 3.0 440)
(fade-in 1.5)))
(def r (-> (square-wave 3.0 880)
(fade-out 1.5)))
(def s3 (-> (->stereo l r)
(pan 0.3)));; And play it
(play s3);; And save it as a 44.1 KHz WAV
(save s3 "sample.wav" 44100);; Load it back in
(def s4 (read-sound "sample.wav"));; read-sound also works with MP3 files, but we can only save to WAV
;; Make a sound of our own design: two seconds of stereo white noise
(def s5 (fn-sound 2.0 2 (fn ^double [^long c ^double t] (- (rand 2.0) 1.0))));; Play it too
(play (gain s5 0.1))
```## History
### 0.4.1
A moderate performance improvement in `async/read-sound`.
### 0.4.0
Introduces a new namespace, `dynne.async-sound`, which has sounds
generate chunks in separate threads, with handoff between threads via
[core.async](https://github.com/clojure/core.async). This should
result in performance improvements for larger audio streams on systems
with multiple cores.The new namespace is API-compatible with the `dynne.sampled-sound`, so
the only change required should be to switch to requiring the new
`dynne.async-sound` namespace.### 0.3.0
Major overhaul. Deprecate `dynne.sound` namespace in favor of
`dynne.sampled-sound`, which uses a more efficient, chunked
representation of sounds leveraging Java native arrays for way higher
performance.### 0.2.0
Performance improvements
### 0.1.0
Initial release
## FAQ
### Why did you build this?
I produce the
[Relevance podcast](http://thinkrelevance.com/blog/tags/podcast). We
talk about Clojure a lot, so I thought I would see if I could automate
the podcast production using Clojure. You can see the in-progress
product of that effort
[here](https://github.com/candera/podcastifier). Along the way, a
general-purpose audio processing library started to fall out of it. So
I busted it out into its own thing, which is now dynne.### Why didn't you just use Overtone?
Mainly because I started out just playing around with the idea and at
some point crossed into being completely obsessed with writing my own
thing. I never even looked at whether
[Overtone](http://overtone.github.io/) can do what I need, because I
knew if I did, and it could, I would stop working on the problem, and
I was having a lot of fun.In short: if Overtone does anything like this, you should use it. It
is likely to be much, much better than dynne.## Appreciations
Thanks to [Stuart Sierra](https://github.com/stuartsierra) for helping
me with some of the weirder problems I hit, especially around compiler
errors.Thanks to [Zach Tellman](https://github.com/ztellman) for his
[primitive-math](https://github.com/ztellman/primitive-math) library,
which was helpful in finding sub-optimal usages of numeric operations.Thanks to [Rich Hickey](http://twitter.com/richhickey) for his
suggestion to rewrite dynne in terms of sequences of double arrays,
which led to a massive increase in performance.Thanks to [Prismatic](http://getprismatic.com) for their
[hiphip](https://github.com/Prismatic/hiphip) library, which was really
helpful in writing the most out of the operations at the core of
dynne.Thanks to [tommyettinger](https://github.com/tommyettinger) for his
[fork of hiphip](https://github.com/tommyettinger/hiphip-aot) that
works around an issue with AOT.## License
Copyright © 2013 Craig Andera
Distributed under the Eclipse Public License, the same as Clojure.