Saturday, 18 January 2014

The blog has moved to a sexier place!

I have moved to Wordpress: yan_g http out

Friday, 8 November 2013

Rather realistic bouncing marble with Make Noise's System 0

This is a beginner (myself) patch, using channel 4 to decrease the rise and fall times of channel 1. The resulting EOR gate is sent to the Optomix Strike input.
It's nothing impressive but I decided to post it because the DPO allows to create a rather realistic marble sound, not as beautiful as Autechre's Krib...

...but I hope still worth sharing:

Click to enlarge

The FM and oscillator knobs on the DPO have to be adjusted carefully. Linear FM knob on osc 2 has actually no effect. Maths' channels 1 & 4 are cycling.

Thursday, 10 October 2013

My DIY Arduino MIDI controller - 8. MIDI communication: Sparkfun's MIDI shield

Long time no write about this project. Actually I've been too busy this past year to work on the project (or should I say too busy the first months, and too lazy then), but I decided I should get back to it.

I decided to get a Sparkfun MIDI shield to test my code with a reliable MIDI circuit. Haven't tested my code yet but Sparkfun's test code seems to work just fine so I'll keep prototyping with it.

Buttons 2 & 3 send note on messages (as well as last note off), button 1 sends last note off. Potentiometer 1 defines the pitch of the note sent, pot 2 is set to adjust control #74 ("Brightness" according to the MIDI message table - which in Reason will control the synth's filter frequency).

Here is the edited code from Sparkfun's MIDI Shield and MIDI breakout test code:

// SparkFun MIDI Sheild and MIDI Breakout test code
// Defines bare-bones routines for sending and receiving MIDI data
// Written 02/16/10

// defines for MIDI Shield components only

//  Reason 6 MIDI implementation chart:
//  http://dl.propellerheads.se/Reason6/Reason%206%20MIDI%20Implementation%20Chart.pdf

#define KNOB1  0
#define KNOB2  1

#define BUTTON1  2
#define BUTTON2  3
#define BUTTON3  4

#define STAT1  7
#define STAT2  6

byte ccVal;
int pot;
int ccPot;
int note;
int lastNote = -1;
int lastCcVal = -1;

void setup() {
  pinMode(STAT1,OUTPUT);   
  pinMode(STAT2,OUTPUT);
  pinMode(BUTTON1,INPUT);
  pinMode(BUTTON2,INPUT);
  pinMode(BUTTON3,INPUT);

  digitalWrite(BUTTON1,HIGH);
  digitalWrite(BUTTON2,HIGH);
  digitalWrite(BUTTON3,HIGH);

  for(int i = 0;i < 10;i++) // flash MIDI Sheild LED's on startup
  {
    digitalWrite(STAT1,HIGH);  
    digitalWrite(STAT2,LOW);
    delay(30);
    digitalWrite(STAT1,LOW);  
    digitalWrite(STAT2,HIGH);
    delay(30);
  }
  digitalWrite(STAT1,HIGH);   
  digitalWrite(STAT2,HIGH);

  //start serial with midi baudrate 31250
  Serial.begin(31250);     
}

void loop () {

  //*************** MIDI OUT ***************//
  pot = analogRead(KNOB1);
  ccPot = analogRead(KNOB2);
  note = pot / 8;  // convert value to value 0-127
  ccVal = 127 - ccPot / 8;
  
  //  send notes
  if(button(BUTTON2) || button(BUTTON3))
  {
    if (lastNote > -1) Midi_Send(0x80,lastNote, 0x0);
    Midi_Send(0x90,note,0x45);
    lastNote = note;
    while(button(BUTTON2) || button(BUTTON3));
  }
  //  send last note off
  if (button(BUTTON1) && lastNote > -1) {
    Midi_Send(0x80, lastNote, 0x0);
  }
  
  // send cc
  // only if the value has changed
  if (ccVal != lastCcVal) {
    Midi_Send(0xB0, 74, ccVal);
    lastCcVal = ccVal;
  }
}

void Midi_Send(byte cmd, byte data1, byte data2) {
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

char button(char button_num) {
  return (!(digitalRead(button_num)));
}
<< Previous: 7. STUCK! (Help needed)

Tuesday, 24 September 2013

Conway's Game of life

Made Conway's famous Game of life in Processing, because I haven't been coding for a long time and need to get back into the swing of things...

Live cells are green, or eurgh if just born. Just dead cells are this green.

This is just a short gif...

And the messy code:

// univers
int cellSize = 4;
int cellsPerRow = 80;
int cellsPerCol = 80;
int margin = 20;

// horloge
int iterationInterval = 40; // millis
int lastIterationTime = millis();
boolean run = true;
boolean voisinsStep = true;

// cellules
int probabilityOfAliveAtStart = 10; // percent
int[][] cells;
int[][] cellsBuffer;
color cellColor[];
int deadCells;
int dyingCells;
int bornCells;
int liveCells;

//  messages
String[] messages;

void setup() {
  // définition de la taille
  size (cellsPerRow * (cellSize + 1) - 1 + margin*2,
        cellsPerCol * (cellSize + 1) - 1 + margin*2);
  
  // définition des couleurs
  stroke(128);
  cellColor = new color[4];
  cellColor[0] = color(0, 63, 0);    // morte
  cellColor[1] = color(63, 127, 0);  // mourante
  cellColor[2] = color(127, 127, 0); // née
  cellColor[3] = color(0, 255, 0);   // vive
  background(0);
  
  // remplissage des cellules
  cells = new int[cellsPerRow][cellsPerCol];
  cellsBuffer = new int[cellsPerRow][cellsPerCol];
  initializeCells();
  drawCells();
  
}


void draw() {
  // horloge
  if (millis() - lastIterationTime > iterationInterval && run == true) {
    lastIterationTime = millis();
    iterate();
    background(0);
    drawCells();
//    drawStack();
  }

  // grille
  for (int x = -1; x= probabilityOfAliveAtStart)
        cells[x][y] = 0;
      else cells[x][y] = 2;
    }
  }
}

void iterate() {
  /*
  born cell = 2
  live cell = 3
  dying cell = 1
  dead cell = 0
  */
  
  // buffer
  for (int x = 0; x < cellsPerRow; x++) {
    for (int y = 0; y < cellsPerCol; y++) {
      cellsBuffer[x][y] = cells[x][y];
    }
  }
  
  for (int x = 0; x < cellsPerRow; x++) {
    for (int y = 0; y < cellsPerCol; y++) {
      //println("Cell "+x+", "+y);
      // recensement des voisins
      int neighbours = 0;
      for (int xx = x - 1; xx <= x + 1; xx++) {
        for (int yy = y - 1; yy <= y + 1; yy++) {
          int xxx = xx;
          int yyy = yy;
          //  si on sort des limites on regarde de l'autre côté
          if (xx < 0) xxx = cellsPerRow - 1;
          if (yy < 0) yyy = cellsPerCol - 1;
          if (xx == cellsPerRow) xxx = 0;
          if (yy == cellsPerCol) yyy = 0;
          if (cellsBuffer[xxx][yyy] > 1 && (xx != x || yy != y))
            neighbours++;
        }
      }
      //println(neighbours+" voisins"); println();
      if (cells[x][y] > 1) {  // si vive
        if (neighbours < 2 || neighbours > 3) cells[x][y] = 1;
        else cells[x][y] = 3;
      }
      else { // si morte
        if (neighbours == 3) cells[x][y] = 2;
        else cells[x][y] = 0;
      }
    }
  }
}

void drawCells() {
  for (int x = 0; x < cellsPerRow; x++) {
    for (int y = 0; y < cellsPerCol; y++) {
      fill(cellColor[(cells[x][y])]);
      noStroke();
      rect(margin + x*(cellSize + 1), margin + y*(cellSize + 1), cellSize, cellSize);
    }
  }
}

int[] countCells(String output) {
  deadCells = dyingCells = bornCells = liveCells = 0;
  for (int x = 0; x < cellsPerRow; x++) {
    for (int y = 0; y < cellsPerCol; y++) {
      if (cells[x][y] == 0) deadCells++;
      if (cells[x][y] == 1) dyingCells++;
      if (cells[x][y] == 2) bornCells++;
      if (cells[x][y] == 3) liveCells++;
    }
  }
  if (output == "print") {
    deadCells += dyingCells;
    liveCells += bornCells;
    println(liveCells+" live cells ("+bornCells+" born)");
    println(deadCells+" dead cells ("+dyingCells+" dying)");
    println("Total: "+(liveCells+deadCells));
  }
  int[] a = {deadCells, dyingCells, bornCells, liveCells};
  return a; 
}

void drawStack() {
  int[] a = countCells("array");
  //  born
  int barYH = a[2]/(cellsPerCol*cellsPerRow)*(height - margin*2);
  fill(cellColor[2]);
  rect (width - margin - 10, height - margin,
        10, -a[2]);
  fill(cellColor[3]);
  rect (width - margin - 10, height - margin - a[2],
        10, -a[3]);
  fill(cellColor[1]);
  rect (width - margin, height - margin,
        10, -a[1]);
}

void keyPressed() {
  if (key == ' ') {
    if (run == true) {
      run = false;
      println("Pause");
    }
    else {
      run = true;
      println("Run");
    }
  }
  if (key == 'R' || key == 'r') {
    background(0);
    initializeCells();
    iterate();
    drawCells();
    drawStack();
  }
  if (key == 'c' || key == 'C') {
    countCells("print");
  }
}

For some reason, Blogger adds a </width> tag at the end of the code that should indeed be removed...

Monday, 23 September 2013

MIDI Arduino pause blah etc. + free music you should own

OK, winter's comming, and it should feel good to just stay home with nothing else to do than programming an Arduino. I know life's a bitch and it never lets anyone do as planned but I do hope to sit in front of my desk 1 day a week, hitting my keyboard and/or soldering stuff, and why not finish this fucking project before summer. I don't plan to use it live, since I'm too scared to face an audience but I decided that this project is my personal enemy, and that as such I shall terminate it.

As I'm waiting for my Sparkfun order to arrive (which includes a MIDI shield to help me prototype the fucker), I thought I'd post some of the free music I've encountered during these past years of online procrastination. I don't mean to post good free music, or quality free music, but free music that is essential to my record collection.

I'll start by wiping the dust off this old Merck release I own on CD, Bruxist Frog by Proswell, now available as a pay-what-you-want download on bandcamp. This excerpt may sound like video game music to many people (it's maybe 10 yeard older than Minecraft). It just sounds like music to me. Fucking lovely tune, beautiful. I wish I could do that.



Off the same album, Eu Auberderr. You think you hear beauty until the melody kicks in @ 3:00. Forget it.



RUN LOOP GOD.



Get the album if you don't have it already, you fucking criminal. I won't spoil it by posting the last track, it deserves more attention than you can provide right now.

This next track is from a more recent record, Meek by Bitbasic, released on rec72.net. The opening track is a killer, it reminds of Boards Of Canada eventhough it's better than anything they've released IMHO. :)



On the Atari ST side of things, I've been in love with this Tao track from 2000, released on the album Wave Upon Wave by the Atari collective YM Rockerz. The album is available as a ST disk image, MP3 and SNDH formats. You don't have to be into chiptunes to dig this by the way.



That's all for now, I've got some tracks on my drives that don't seem to be online anymore so I'll have to upload them somewhere. Gems.

Sunday, 16 September 2012

My DIY Arduino MIDI controller - 7. STUCK! (Help needed)

Ok, so... I've been away for some time because I had to focus on other projects, mostly professional but also musical (released a *free* EP in June, check it out @ rec72.net, it's 6 tracks of melodic electronica!) or vacational:

Florence, Italy

Anyway, I decided I should get back to work on my controller and started to proceed but I got quickly stuck with the next step: sending CC messages, which is kindof essential to a MIDI controller innit...

The problem is this: I'm trying to send CC messages on MIDI channel 1, on control number 16 (I tried various control numbers and got the same problem each time). My software (Reason 6) does receive MIDI data, but I get erratic values on erratic control numbers.

I tried the serial.write command as well as the MIDI Library v3.2, without success. Here is the very simple code, using the library:

#include 

// Variables:
int cc = 0;
int AnalogValue = 0; // define variables for the controller data
int lastAnalogValue = 0; // define the "lastValue" variables

void setup() {
  //  launch MIDI
  MIDI.begin(4);
}

void loop() {
  AnalogValue = analogRead(0);
  //  convert to a range from 0 to 127:
  cc = AnalogValue/8;
  // check if analog input has changed
  if (lastAnalogValue != cc) {
    MIDI.sendControlChange(16,cc,1);
    // update lastAnalogValue variable
    lastAnalogValue = cc;
  }  //  endif
}

I posted on the Arduino forums but got no useful reply yet, so I thought I might as well tell it here and maybe some charitable soul would post a comment to help me troubleshoot this issue... I did output my sensor value to the serial monitor and it was just as expected, nothing wrong there. Maybe I should use a delay at startup to prevent unwanted current to go to the serial port while the sketch uploads... I'll try that ASAP.

<< Previous: 6. MIDI communication, Part I: Most basic stuff :)

Sunday, 8 April 2012

My DIY Arduino MIDI controller - 6. MIDI communication, Part I: Most basic stuff :)

Ok so I'm back to MIDI communication!

In case you want to follow my steps this is the list of the few components I use in this chapter:

  • 1 x tact switch
  • 2 x 10 kΩ resistors
  • 1 x 240 Ω resistor (220 ohm is supposed to be better)
  • 1 x female MIDI DIN socket (5 pins)
  • 1 x LDR
  • 1 x SPDT switch
  • Wire jumpers
  • 1 x Arduino!

I tried MIDI communication before I started the blog, and successfully sent notes over to Reason (a music software in case you don't know) via MIDI. I had already forgotten how to do so I checked again this basic tutorial. Since I (believe it or not) don't have 220 Ω resistors, I used a 240 Ω resistor instead, and it worked fine.

Next step is just for fun: sending notes according to the reading of a LDR (Light Dependent Resistor). I followed this tutorial (scroll down to the 6th chapter) and modified the code:
const int switchPin = 10;  // The switch is on Arduino pin 10
const int middleC = 60;    // Middle C (MIDI note value 60) is the lowest note we'll play
const int LEDpin = 13;     //  Indicator LED

// Variables:
byte note = 0;              // The MIDI note value to be played
int AnalogValue = 0;        // value from the analog input
int lastNotePlayed = 0;     // note turned on when you press the switch
int lastSwitchState = 0;    // state of the switch during previous time through the main loop
int currentSwitchState = 0;
int tempo = 480;

void setup() {
  //  set the states of the I/O pins:
  pinMode(switchPin, INPUT);
  pinMode(LEDpin, OUTPUT);
  //  Set MIDI baud rate:
  Serial.begin(31250);
}

void loop() {
  //  My potentiometer gave a range from 0 to 1023:
  AnalogValue = 1023-analogRead(0);
  //  convert to a range from 0 to 127:
  note = AnalogValue/8;
  currentSwitchState = digitalRead(switchPin);
  // Check to see that the switch is pressed:
  if (currentSwitchState == 1) {
    // set the note value based on the analog value, plus a couple octaves:
    note = note + 20; // you might want to change that value depending on the sensor you're using
    // start a note playing:
    noteOn(0x90, note, 0x40);
    delay(60000/tempo); // 60000 milliseconds = 1 min
    // play same note with a 0 velocity
    noteOn(0x90, note, 0x00);
  }
}

//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void noteOn(byte cmd, byte data1, byte  data2) {
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}



The problem I have is on sketch upload (not on reset), the Arduino sends seemingly random notes to Reason, which I have to turn off by pressing them in Reason's integrated software keyboard. Looks like it is sending data interpreted as notes on, and no notes off (or not the good ones). Since the MIDI and Arduino to PC data are sent to the same pin, my MIDI device is receiving the data that the Arduino is sending to the PC during the sketch upload process, and apparently interprets it at notes ons. Shouldn't be a problem anyway after the prototyping stage, since we wouldn't upload the code to the final controller each time we use it. It should simply not be connected to a MIDI device during upload...

I'm currently studying MIDI control changes so I guess next post will get closer to what I actually want to do: control synth parameters using LDRs & pots.

<< Previous: 5. Finding more pins, part III: the shift register