Code Monkey home page Code Monkey logo

pink's Introduction

Pink

Build Status

Clojars Project

A library for music systems development, written in Clojure.

Introduction

This library provides the basis for developing music systems. It is also designed so to scale to user needs, whether they are exploring and designing low-level signal processing algorithms, developing pre-written compositions, or creating interactive real-time systems. It offers a slim core engine designed to be highly customizable.

Features include:

  • 64-bit signal processing chain
  • Functional Audio Signal Graph: Build up Audio Graphs using functional approach
  • Clear Synchronization of time-aware functions with Control Functions
  • Higher-order Events: Functions and events can be used as arguments to events
  • Use Clojure to extend the system: single language for all extension points to the system

For more information, please see the website.

Installation

At the moment, installation requires cloning this repostory and installing it using 'lein install'. (This instruction will be updated when a stable release is made available.)

Mailing List

For questions, please consider joining the Pink Users mailing list here.

Examples

Examples for using Pink are available in the music-examples project.

YourKit

Many thanks to YourKit for granting an Open Source license. Their software is exceptional for helping to diagnose memory and performance issues with Pink.

YourKit supports open source projects with its full-featured Java Profiler.YourKit, LLC is the creator of YourKit Java Profiler and YourKit .NET Profiler, innovative and intelligent tools for profiling Java and .NET applications.

License

Copyright © 2014 Steven Yi

Distributed under the Eclipse Public License, the same as Clojure.

pink's People

Contributors

kunstmusik avatar triss avatar vdmit11 avatar

Stargazers

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

Watchers

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

pink's Issues

Should Event.start time be somehow aligned to `*tempo*`?

Hello, I'm playing around with Pink, and spotted something odd.

When you add new events to the engine, you always specify the start time relative to the current point of time.

This is ok when you add events from a control function (which is triggered accurately on every beat for example), but when you add events from outside of the engine thread, you may experience a significant clock skew.

In my case, I generate scores and add events from a separate thread (because sometimes it takes long time, and I would not like to put these heavy operations into the engine cycle).
So when I'm adding events, the EventList.cur-beat is almost random to me, so for each event, I have to manually de-reference it and compute the difference between the cur-time and the nearest beat boundary according to *tempo*, which is a bit inconvenient.

And, I spotted something in the Pink's code here:
https://github.com/kunstmusik/pink/blob/master/src/main/pink/event.clj#L111

The docstring says that the function adjusts event start times according to *tempo*.
But actually it doesn't use *tempo* at all, It adjust event times according to the cur-beat.

So, I thought that maybe this code was intended to work a bit differently?

@kunstmusik please let me know what you think

Using JACK with Pink

I've been trying to get Jack working with Pink. It seems to me that jnajack is the best solution.

After installing Java Native Access and jnajack
And adding jna.jar and org-jaudiolibs-jnajack.jar to my ext directory
I was able to run trough jack:
java -Xincgc -cp jna.jar:org-jaudiolibs-jnajack.jar org.jaudiolibs.jnajack.examples.SineAudioSource

It seems to me that engine.clj needs to be adjusted or alternative version created for JACK

Looking how SineAudioSource.java operaties with the jnajack library may give an idea how to send audio buffer to JACK (this may also be a bad solution, but after looking at clj-jack 0.0.1 which is based on overtone, I noticed that it's really the supercollider server that handles all communication to jack but not java).

package org.jaudiolibs.jnajack.examples;

import java.nio.FloatBuffer;
import java.util.EnumSet;
import org.jaudiolibs.jnajack.Jack;
import org.jaudiolibs.jnajack.JackPortFlags;
import org.jaudiolibs.jnajack.JackPortType;
import org.jaudiolibs.jnajack.util.SimpleAudioClient;

/**
 *
 * @author Neil C Smith
 */
@Deprecated
public class SineAudioSource implements SimpleAudioClient.Processor {

    private final static int TABLE_SIZE = 200;
    private int left_phase = 0;
    private int right_phase = 0;
    private float[] data;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        SimpleAudioClient client = SimpleAudioClient.create("sine", new String[0],
                new String[]{"output-L", "output-R"}, true, true, new SineAudioSource());
        client.activate();
        while (true) {
            Thread.sleep(1000);
        }
    }

    public void setup(float samplerate, int buffersize) {
        data = new float[TABLE_SIZE];
        for (int i=0; i < TABLE_SIZE; i++) {
            data[i] = (float) (0.2 * Math.sin( ((double)i/(double)TABLE_SIZE) * Math.PI * 2.0 ));
        }
    }

    public void process(FloatBuffer[] inputs, FloatBuffer[] outputs) {
//        for (FloatBuffer buf : outputs) {
//            int size = buf.capacity();
//            for (int i=0; i < size; i++) {
//                buf.put(i, (float) Math.random() - 0.5f);
//            }
//        }
        FloatBuffer left = outputs[0];
        FloatBuffer right = outputs[1];
        int size = left.capacity();
        for (int i=0; i<size; i++) {
            left.put(i, data[left_phase]);
            right.put(i, data[right_phase]);
            left_phase += 2;
            right_phase += 3;
            if (left_phase >= TABLE_SIZE) {
                left_phase -= TABLE_SIZE;
            }
            if (right_phase >= TABLE_SIZE) {
                right_phase -= TABLE_SIZE;
            }
        }
    }

    public void shutdown() {
        System.out.println("Sine Audio Source shutdown");
    }
}

pink.io.midi/find-midi-device can't find devices on Windows

Attempting to find device names via :description is ineffective on Windows.

It appears the description field is rarely populated properly on Windows, for example on my system:

(map :description (list-midi-input-devices)) 
;=> ("No details available" "No details available" "No details available" ...)

This results in an exception being thrown whenever find-midi-device is called.

:name is however fully populated:

(map :name (list-midi-input-devices))
;=> ("lappy" "Audio Kontrol 1 In" ... "Real Time Sequencer")

Perhaps making find-midi-device search by :name once a :description based search has failed or doing different searches dependant on platform would be sensible solutions?

add dynamic variable: *engine*

Imagine that you have a complex control function, or a function triggered by event.
It consists of many deeply nested function calls.
And in one of nested function calls, you need to manage control functions (or add new events).

Then you have a little problem: you need to remember the current engine, and pass it all the way down via function arguments, which is annoying.

Or, you can use a dynamic variable (e.g., *engine*), bind it at the top level, and then refer to it somewhere in the deeply nested function call.

That could be manually implemented by any Pink user as a bunch of wrappers around events/cfuncs (and actually I'm already doing this), but I think that it could be nice to have it out of the box.

So, I suggest to add the *engine* (or maybe *current-engine*) variable to config.clj
...and simply bind it in (engine-run), together with other dynamic variables.

@kunstmusik, the change is trivial, but I wonder if it somehow contradicts your design ideas?
I can implement it if you don't have time, just let me know....

Heap size

Hi Steven, interesting to follow the development of Pink.

Anyhow, not an important issue but I get this error when starting the REPL:
error in process sentinel: Could not start nREPL server: Error occurred during initialization of VM
Too small initial heap for new size specified

And then I comment out
; "-Xms256m" "-Xmx1g"

Then the repl runs, but going trough the demos I hear a lot of distortion. Maybe unrelated?

Encourage users to :require :as and simplify naming

Many functions name domain they operate on yet namespace all ready provides this information.

For example in pink.io.midi the following fn all refer to MIDI in there names. It'd be more inline with current practice to expect users to (:require [pink.io.midi :as midi]) and rename them as follows:

Current name Suggested name
list-midi-devices list-devices
midi-input-device? input-device?
midi-output-device? output-device?
list-midi-input-devices list-input-devices
list-midi-output-devices list-output-devices
create-midi-manager create-manager
find-midi-device find-device
get-midi-cc-atom get-cc-atom

These functions could then be utilised through midi/list-devices etc.

Probable incorrect usage of .getMaxReceivers and .getMaxTransmitters in find-midi-device

find-midi-device appears to use .getMaxReceivers and .getMaxTransmitters incorrectly.

It appears you are using these methods in an attempt to confirm that a device is a valid input or output.

Unfortunately all you do is confirm that it does not have an infinite number of connections available in it by testing that there results >= 0.

The documentation for these methods state that they return the number of connections available or -1 if an infinite number are available.

As a result it's my belief that you should be checking the functions results are either > 0 or = -1 here. Using midi-input-device? and midi-output-device? would probably make a reasonably neat fix.

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.