Announcing Fragment – The Collaborative Spectral Synthesizer

Although i developed a proof of concept one year ago, this more serious version begun in September 2016 with the original codebase, with some hard work for a few month, it is now almost ready to be shipped to the world!

So, what is Fragment?

Fragment is a web-based collaborative spectral musical instrument driven by real-time visuals generated by its users from shared GLSL scripts.

If this sound cryptic, it is alright, i will explain its concept here.

Fragment is first and foremost a simple additive synthesizer, meaning that under the hood, the synthesis engine just add sine waves of different frequencies together!

The originality come from the method of control of those frequencies, in Fragment you have three essential visual components, a GLSL code editor, a canvas (which can be called the score) and what i call slices, these components are the core of Fragment with the global timer and the synthesis engine that you cannot see but hear.

  • The GLSL code editor is used to generate the visuals, it is essentially a fragment shader it compute the color of each pixels of the canvas individually
  • The score (or canvas) is where the output of the fragment shader is shown
  • Slices are parts of the score, they are 1 pixel in width and the height of the canvas, they are vertical parts of the score

So, how does it work?

Fragment simplified flow is essentially : GLSL code > canvas > slice > synthesis engine

The code that users type produce visuals (a bunch of pixels), pixels are captured by the vertical slices, those vertical slices are unified into one and a conversion process happen to transform the pixels into “notes”, one pixel will equate to a sine wave with the amplitude defined by the pixel brightness, the frequency defined by the vertical position of the pixel in the slice and the stereo channel defined by the color of the pixel, this happen at a rate of 60 fps.

Fragment add alot of goodies on top of that such as MIDI controllable uniforms (variables that you use in your GLSL code that are updated by you from controllers), an unlimited number of slices possible, frequency shifting of individual slices, many other small features, textures import, configurable score and most importantly collaborative features, Fragment can be used locally or online, peoples can join and share sessions to experiment together, almost everything is synchronized between users.

Fragment will be released sometimes in january, the beta testing phase is just beginning and there is still some things to affine.

Fragment – The Collaborative Spectral Synthesizer

If you like this project and want to see its progression, you can follow us through social media :

facebook twitter soundcloud youtube

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

KORG Audio Gallery AG-10 – ai² PCM synthesizer

Some weeks ago i  got my hands on a Korg AG-10, the lowest-end model of ai² synthesis series, which started with the 01/W in 1991.

The AG-10 was basically sold as a General MIDI Wavetable Sound Module and it came with two floppy with bundled software (Passport Trax, KORG MIDI driver, KORG SMF converter, Passport MIDI player, Passport QuickTunes), it was a great compact GM box for its time but it is more than a simple “rompler”, it had “hidden” editing capabilities, there was no softwares to program the synthesis engine at the time it was sold although most of the informations to program it is found in the manual.

Here are the specs :

  • AI² synthesis engine, same as 01/W, full digital processing with 4 Mb ROM
  • GM compliant
  • 32 voices polyphony
  • 16 parts / 16 channels
  • Two FX units (Reverb, Chorus)
  • Drum kits : 4
  • Outputs : Head phone jack, L/R RCA jacks, 1 x MIDI out, 1 x MIDI Thru, To Host Computer (PCI/F) interface
  • Inputs : L/R RCA jacks, 1 x MIDI in
  • PC1/2 host select switch on the back side
  • Front volume slider, power button and power LED/MIDI led indicator
  • Power : DC 12v 400ma

With its editing capabilities, the AG-10 unit can be used as a kind of synthesizer, you can get some serious vintage sonic characters out of it, it approach the sonic capabilities of the other ai² series synthesizers for a cheap price and with its own character since it also have hidden waveforms/hidden modulations making it possible to make it sound like Roland D-50 / D-110, Ensoniq VFX / SQ-R and Emu Morpheus. Roland D-70‘s DLM, circuit-bending-like loop modulation.

The only issue is that there is no available editor right now to edit the AG-10, there used to be one which included hidden waveforms/hidden modulations but i cannot find it anymore… however it may be possible to do another easily.

I made images of the floppy disks to test and archive the bundled softwares with DosBox and Windows 3.1, those images are available below.

Download :

These are fairly hard to find and you won’t see many available for sale these days but if you see it, it might be of your interest to pick one up because it might be cheap and is not a simple GM sound module!

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Multi-user collaborative text editing with ShareDB and CodeMirror

Do you desire to add a multi-users collaborative text editing to your application? This article will show you how to do it by using ShareDB and the CodeMirror library.

ShareDB which used to be ShareJS is a real time database backend based on Operational Transformation (OT) of JSON documents, it allow real-time synchronization of documents and many other nifty things, in this article, i will focus on the implementation of a multi-user collaborative text editor by using ShareDB and CodeMirror which is a versatile text editor implemented in JavaScript for browsers.

There is some projects that exist already such as a CodeMirror binding for ShareDB and ShareJS but they are outdated or not working correctly, as there is limited resources on this subject, i am sharing my implementation for CodeMirror, it can also be useful for other editors such as the Ace Editor.

In this article, i assume that there is already a CodeMirror instance which is named “code_editor” on the client side.

The Node.js server is extremely simple, ShareDB will do everything, all alone… we will just make ShareDB listen to a WebSocketJSONStream :

var http = require('http');
var express = require('express');
var ShareDB = require('sharedb');
var ShareDB_logger = require('sharedb-logger');
var WebSocket = require('ws');
var WebSocketJSONStream = require('websocket-json-stream');

var share = new ShareDB();

var sharedb_logger = new ShareDB_logger(share);

var app = express();
var server = http.createServer(app);

var wss = new WebSocket.Server({server: server});
wss.on('connection', function(ws, req) {
    console.log("client connected");
    
    var stream = new WebSocketJSONStream(ws);
    share.listen(stream);
});

wss.on('close', function(ws, req) {
    console.log("client disconnected");
});

server.listen(3000);

Here are the dependencies to add to the “package.json” file to build the server with “npm” :

    "dependencies": {
        "sharedb": "1.0.0-beta.6",
        "ot-text": "1.0.1",
        "websocket-json-stream": "0.0.3",
        "express": "4.14.0",
        "ws": "1.1.1",
        "sharedb-logger": "0.1.4"
    }

sharedb-logger” is useful to monitor all ShareDB messages.

On the client side, you need to connect to the server through WebSocket (ShareDB is transport agnostic but it will require additional code to implement other transports) :

var ws = new WebSocket("ws://127.0.0.1:3000"); // Connect to localhost on port 3000

Then bind ShareDB to the WebSocket :

var sharedb_connection = new ShareDB.Connection(ws);

Now it is time to get the document we are interested in :

sharedb_doc = sharedb_connection.get("my_collection", "my_document");

We are getting a document named “my_document” in the collection “my_collection”, if the connection is established and the document exist on the server, we will get the latest snapshot of that document from the server, if it does not exist already, we will create it and set the document content to the text editor content, if it exist we just assign the document content to our text editor, we do that by using the document function “subscribe“, we will also start to listen to the “op” event to integrate remote document changes to our CodeMirror instance.

    sharedb_doc.subscribe(function(err) {
        if (err) {
            console.log(err); // handle the error
        }
        
        if (!sharedb_doc.data) { // does not exist so we create the document and replace the code editor content by the document content
            sharedb_doc.create(code_editor.getValue());
        } else { // it exist, we set the code editor content to the latest document snapshot
            code_editor.setValue(sharedb_doc.data);
        }

        // we listen to the "op" event which will fire when a change in content (an operation) is applied to the document, "source" argument determinate the origin which can be local or remote (false)
        sharedb_doc.on('op', function(op, source) {
            var i = 0, j = 0,
                from,
                to,
                operation,
                o;
            
            if (source === false) { // we integrate the operation if it come from the server
                for (i = 0; i < op.length; i += 1) {
                    operation = op[i];
                    
                    for (j = 0; j < operation.o.length; j += 1) {
                        o = operation.o[j];
                        
                        if (o["d"]) { // delete operation
                            from = code_editor.posFromIndex(o.p);
                            to = code_editor.posFromIndex(o.p + o.d.length);
                            code_editor.replaceRange("", from, to, "remote");
                        } else if (o["i"]) { // insert operation
                            from = code_editor.posFromIndex(o.p);
                            code_editor.replaceRange(o.i, from, from, "remote");
                        } else {
                            console.log("Unknown type of operation.")
                        }
                    }
                }
            }
        });
        
        sharedb_doc_ready = true; // this is mandatory but we will use this to determine if the document is ready in the "change" event of CodeMirror
    });

You can look here for informations concerning the text operations, this is pretty easy to manipulate because there is basically two types, insert, delete and both come with the position from which it happen, we need to do some conversions for the position because CodeMirror use lines and characters, ShareDB just use characters. The very important things is the last argument that we pass to CodeMirror “replaceRange” function, because all of these operations will fire the “changes” event of CodeMirror which we will listen to submit operations… so if we want to avoid cyclic changes problem, we need to “type” the origin by setting it as “remote” and we will ignore the change with this origin in the CodeMirror “changes” event.

Now it is time to listen to changes from CodeMirror through the “changes” event and push the operation to ShareDB :

    CodeMirror.on(code_editor, 'changes', function (instance, changes) {
        var op,
            change,
            start_pos,
            chars,

            i = 0, j = 0;

        if (!sharedb_doc_ready) { // if the document is not ready, we just ignore all changes, a much better way to handle this would be to call the function again with the same changes at regular intervals until the document is ready (or just cancel everything if the document will never be ready due to errors or something else)
            return;
        }

        op = {
            p: [],
            t: "text0",
            o: []
        };

        // we must do it in order (this avoid issue with same-time op)
        changes.reverse();

        for (i = 0; i < changes.length; i += 1) {
            change = changes[i];
            start_pos = 0;
            j = 0;

            if (change.origin === "remote") { // do not submit back things pushed by remotes... ignore all "remote" origins
                continue;
            }

            while (j < change.from.line) {
                start_pos += code_editor.lineInfo(j).text.length + 1;
                j += 1;
            }

            start_pos += change.from.ch;

            if (change.to.line != change.from.line || change.to.ch != change.from.ch) {
                chars = "";

                for (j = 0; j < change.removed.length; j += 1) { chars += change.removed[j]; if (j !== (change.removed.length - 1)) { chars += "\n"; } } op.o.push({ p: start_pos, d: chars }); } if (change.text) { op.o.push({ p: start_pos, i: change.text.join('\n') }); } } if (op.o.length > 0) {
            sharedb_doc.submitOp(op);
        }
    });

Here we are looping through all changes that happened, determinate what kind of change it is and the start position (remember: CodeMirror use lines and characters so we have to do some computations to transfom lines&characters to a character based position), we then submit the operation to ShareDB.

This is it, you should have a multi-user collaborative text editor working fully with CodeMirror…

For an easier way to add collaborative stuff to your application , you can also integrate TogetherJS which a library which will almost “automatically” allow it for many things and provide some nice widgets such as a chatbox, audio chat… my preference goes for ShareDB as it seem easier to control and manage while remaining fairly easy to use when doing advanced stuff and it does not have any fancy stuff.

09/08/2017: Added `changes.reverse()` to the CodeMirror changes function so that changes are processed in order, this avoid issues with same-time operations.

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Shell script to monitor SSD wear level

I bought some new computer hardware since a few days (i7 6700, GTX970 etc.), one of which is a Samsung 250Gb SSD on which Xubuntu was installed, before buying the SSD i have read reviews and benchmarks which gave some durability numbers, (the number of bytes written before the SSD become unusable), what is rather cool with SSD is that you can have a proper estimate of when the SSD will become unusable, SMART and other tools can give insight but i wanted a simple way to get an estimate for my SSD wear level so i started to find a way to get the number of written data and started to write some shell code.

With the ext4 filesystem (i don’t know if it is possible with others) it is possible to get the number of kbytes written to the file system since it was created (cat /sys/fs/ext4/your_ext4_partition/lifetime_write_kbytes)… so i wrote a small shell script which indicate the SSD wear level as percents and the days left before it become unusable so i can start to backup and buy another one before it is too late, the script also show the SSD lifetime write in mb/gb/tb units in case something wrong happen 😛

Before using it, the script need some inputs which are:

  • sys_fs_fs_device_path: Where is lifetime_write_kbytes located
  • ssd_date: The date at which the SSD begun to be used
  • ssd_tb_endurance: Endurance of the SSD in terabyte unit (gotten from reviews/benchmarks with a slightly decreased value to be safe)

Note: The script need slight modifications depending on the partitioning scheme the SSD has… right now it handle just a single partition.

#!/bin/sh
# Script displaying SSD wear level as percents and which estimate SSD days left
# This make use of ext4 "lifetime_write_kbytes" which indicate the number of kbytes written to the file system since it was created
# grz- / 2016

########
# lifetime_write_kbytes path (the one you use on your SSD)
sys_fs_fs_device_path="/sys/fs/ext4/sda1/lifetime_write_kbytes"
# when the ssd was used
ssd_date='09/17/2016'
# max ssd endurance (tb)
ssd_tb_endurance=30
########

ssd_date_as_timestamp=`date -d $ssd_date +%s`
now_timestamp=`date +%s`
ssd_days_elapsed="$((($now_timestamp - $ssd_date_as_timestamp)/(60*60*24)))"

lifetime_write=`cat $sys_fs_fs_device_path`

echo "\033[36mSSD wear levels:"
echo "\033[37m specified endurance: \033[32m${ssd_tb_endurance}tb"
echo "\033[37m ssd lifetime write: \033[32m\n\t$(echo "($lifetime_write/1024)" | bc)Mb\n\t$(echo "($lifetime_write/1048576)" | bc)Gb\n\t$(echo "($lifetime_write/1073741824)" | bc)Tb\n"
echo "\033[37m ~ssd wear: \033[32m$(echo "scale=2; (($lifetime_write / 1073741824) / $ssd_tb_endurance) * 100" | bc)%"

days_left=$(echo "($ssd_tb_endurance * 1073741824) / ($lifetime_write / $ssd_days_elapsed)" | bc)

echo "\033[37m ~ssd days left: \033[32m$days_left days"

To add SMART data “Wear_Leveling_Count” attribute value output, append this at the end of the script:

# device path
ssd_device_path=/dev/sda

wear_leveling_count=$(smartctl --format=brief -a $ssd_device_path | grep Wear_Leveling_Count)

echo "\n\033[37m SMART Wear_Leveling_Count attr.: \033[32m$(echo $wear_leveling_count | awk '{print $4}') (value) $(echo $wear_leveling_count | awk '{print $6}') (treshold) $(echo $wear_leveling_count | awk '{print $8}') (raw value)"

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...