How to interface axoloti with Plants ? Midi sprout 300 €?


#1

midi sprout 300 € ? WTF!!!!
lets adapt this to axo ..
this would push our axolotiy to the stars and beyond and back again ,,,,

secret life of plants is not only an album
its also film, with music made by a blind,
stevie wonder...
WATCH IT!!!!!!

a seed is a star, a star is a seed.....
iplant

aahhhh in germany there is no sound due to copyright ...so stevie have to watch it ....

and the link Midisprout
http://midisprout.com/


Generating external noise from analog in like on arduino
#2

well ...let me put it this way: how to interface axoloti with Plants ?


#3

Hi, this is Sam from Data Garden. If you are interested in working with a MIDI Sprout and coding Axoloti patches, I recommend building your own Sprout! The MIDI Sprout is quite easy to allocate parts and assemble. All of the code, schematics, board layouts, etc are open source on support.midisprout.com you can even buy packs of 3 circuit boards direct from OSHpark for ~25$. I just made a video of the solder build process, which I will be adding to the support forum later this week.

The Sprout will should immediately with the axoloti, no modification needed, outputting MIDI notes on Channel 1 with a single Control parameter on CC80, just need to push that MIDI data into your patcher!

I've had many people make the '300 WTF' comment, this is an educational and open source project intended to share what I have learned about Biodata Sonification with the world. Unlike some 'product' driven kickstarters, this project was not meant to kick-off production of commercial units, many supporters invest in companies through kickstarter not with the mindset of 'pay for this product' but actually considering their support can help build an organization, company, product, or individual. In the case of the MIDI Sprout, supporters who can put in a decent price have allowed every other person in the world to now have access to how this device works ... for free. So yeah, 300-WTF ... now get on that support forum and build a Sprout, i'd be very happy to provide any help which I can!

-sam


#4

Hi Datagarden! I now feel sorry for WTF!
Thanks for the infos, i have searched the web for
plant interfacing and most methods are too complex for me ....
using a 555 for sensoring is very convenient
From the Midisprout forum:


#5

midisprout.
here the image of watering my thirsty agave..
you can see/hear as it starts breathing again


but something is wrong with the scale, it folds at some point.
I still wish this could be done with axoloti ...


#6

How to measure conductance with an axoloti?


#7

hello! I i made now the part with the 555 and connected it to the axoloti.....still remains a mystery to me how to derive values from that input ... here is the code maybe someone can explain how it is done?

MIDI_PsychoGalvanometer v021
Accepts pulse inputs from a Galvanic Conductance sensor
consisting of a 555 timer set as an astablemultivibrator and two electrodes.
Through sampling pulse widths and identifying fluctuations, MIDI note and control messages
are generated. Features include Threshold, Scaling, Control Number, and Control Voltage
using PWM through an RC Low Pass filter.
-------------*/

include //manage LEDs without delay() jgillick/arduino-LEDFader https://github.com/jgillick/arduino-LEDFader.git

//******************************
//set scaled values, sorted array, first element scale length
int scaleMajor[] = {7,1, 3, 5, 6, 8, 10, 12};
int scaleDiaMinor[] = {7,1, 3, 4, 6, 8, 9, 11};
int scaleIndian[] = {7,1, 2, 2, 5, 6, 9, 11};
int scaleMinor[] = {7,1, 3, 4, 6, 8, 9, 11};
int scaleChrom[] = {12,1,2,3,4,5,6,7,8,9,10,11,12};
int *scaleSelect = scaleChrom; //initialize scaling
int root = 0; //initialize for root
//*******************************

const byte interruptPin = INT0; //galvanometer input
const byte knobPin = A0; //knob analog input

const byte samplesize = 10; //set sample array size
const byte analysize = samplesize - 1; //trim for analysis array

const byte polyphony = 5; //above 8 notes may run out of ram
byte channel = 1; //setting channel to 11 or 12 often helps simply computer midi routing setups
int noteMin = 36; //C2 - keyboard note minimum
int noteMax = 96; //C7 - keyboard note maximum
byte QY8= 0; //sends each note out chan 1-4, for use with General MIDI like Yamaha QY8 sequencer
byte controlNumber = 80; //set to mappable control, low values may interfere with other soft synth controls!!
byte controlVoltage = 1; //output PWM CV on controlLED, pin 17, PB3, digital 11 *lowpass filter
long batteryLimit = 3000; //voltage check minimum, 3.0~2.7V under load; causes lightshow to turn off (save power)
byte checkBat = 1;

volatile unsigned long microseconds; //sampling timer
volatile byte index = 0;
volatile unsigned long samples[samplesize];

float threshold = 2.3; //change threshold multiplier
float threshMin = 1.61; //scaling threshold min
float threshMax = 3.71; //scaling threshold max
float knobMin = 1;
float knobMax = 1023;

unsigned long previousMillis = 0;
unsigned long currentMillis = 1;
unsigned long batteryCheck = 0; //battery check delay timer

define LED_NUM 6

LEDFader leds[LED_NUM] = { // 6 LEDs (perhaps 2 RGB LEDs)
LEDFader(3),
LEDFader(5),
LEDFader(6),
LEDFader(9),
LEDFader(10),
LEDFader(11) //Control Voltage output or controlLED
};
int ledNums[LED_NUM] = {3,5,6,9,10,11};
byte controlLED = 5; //array index of control LED (CV out)
byte noteLEDs = 1; //performs lightshow set at noteOn event

typedef struct _MIDImessage { //build structure for Note and Control MIDImessages
unsigned int type;
int value;
int velocity;
long duration;
long period;
int channel;
}
MIDImessage;
MIDImessage noteArray[polyphony]; //manage MIDImessage data as an array with size polyphony
int noteIndex = 0;
MIDImessage controlMessage; //manage MIDImessage data for Control Message (CV out)

void setup()
{
pinMode(knobPin, INPUT);
randomSeed(analogRead(0)); //seed for QY8
Serial.begin(31250); //initialize at MIDI rate
controlMessage.value = 0; //begin CV at 0
//MIDIpanic(); //dont panic, unless you are sure it is nessisary
checkBattery(); // shut off lightshow if power is too low
if(noteLEDs) bootLightshow(); //a light show to display on system boot
attachInterrupt(interruptPin, sample, RISING); //begin sampling from interrupt

}

void loop()
{
currentMillis = millis(); //manage time
checkBattery(); //on low power, shutoff lightShow, continue MIDI operation
checkKnob(); //check knob value
if(index >= samplesize) { analyzeSample(); } //if samples array full, also checked in analyzeSample(), call sample analysis
checkNote(); //turn off expired notes
checkControl(); //update control value
//checkButton(); //not implemented in this build
checkLED(); //LED management without delay()
previousMillis = currentMillis; //manage time
}

void setNote(int value, int velocity, long duration, int notechannel)
{
//find available note in array (velocity = 0);
for(int i=0;i<polyphony;i++){
if(!noteArray[i].velocity){
//if velocity is 0, replace note in array
noteArray[i].type = 0;
noteArray[i].value = value;
noteArray[i].velocity = velocity;
noteArray[i].duration = currentMillis + duration;
noteArray[i].channel = notechannel;

    if(QY8) { midiSerial(144, notechannel, value, velocity); }
    else { midiSerial(144, channel, value, velocity); }


  if(noteLEDs){
      for(byte j=0; j<(LED_NUM-1); j++) {   //find available LED and set
        if(!leds[j].is_fading()) { rampUp(i, 255, duration);  break; }
      }
  }

  break;
}

}
}

void setControl(int type, int value, int velocity, long duration)
{
controlMessage.type = type;
controlMessage.value = value;
controlMessage.velocity = velocity;
controlMessage.period = duration;
controlMessage.duration = currentMillis + duration; //schedule for update cycle
}

void checkControl()
{
//need to make this a smooth slide transition, using high precision
//distance is current minus goal
signed int distance = controlMessage.velocity - controlMessage.value;
//if still sliding
if(distance != 0) {
//check timing
if(currentMillis>controlMessage.duration) { //and duration expired
controlMessage.duration = currentMillis + controlMessage.period; //extend duration
//update value
if(distance > 0) { controlMessage.value += 1; } else { controlMessage.value -=1; }

   //send MIDI control message after ramp duration expires, on each increment
   midiSerial(176, channel, controlMessage.type, controlMessage.value);

    //send out control voltage message on pin 17, PB3, digital 11
    if(controlVoltage) { if(distance > 0) { rampUp(controlLED, map(controlMessage.value, 0, 127, 0 , 255), 5); }
                                        else { rampDown(controlLED, map(controlMessage.value, 0, 127, 0 , 255), 5); }
    }
}

}
}

void checkNote()
{
for (int i = 0;i<polyphony;i++) {
if(noteArray[i].velocity) {
if (noteArray[i].duration <= currentMillis) {
//send noteOff for all notes with expired duration
if(QY8) { midiSerial(144, noteArray[i].channel, noteArray[i].value, 0); }
else { midiSerial(144, channel, noteArray[i].value, 0); }
noteArray[i].velocity = 0;
rampDown(i, 0, 225);
}
}
}

}

void MIDIpanic()
{
//120 - all sound off
//123 - All Notes off
// midiSerial(21, panicChannel, 123, 0); //123 kill all notes

//brute force all notes Off
for(byte i=1;i<128;i++) {
delay(1); //don't choke on note offs!
midiSerial(144, channel, i, 0); //clear notes on main channel

   if(QY8){ //clear on all four channels
     for(byte k=1;k<5;k++) {
      delay(1); //don't choke on note offs!
      midiSerial(144, k, i, 0);
     }
   }

}

}

void midiSerial(int type, int channel, int data1, int data2) {

cli(); //kill interrupts, probably unnessisary
// Note type = 144
// Control type = 176
// remove MSBs on data
data1 &= 0x7F; //number
data2 &= 0x7F; //velocity

	byte statusbyte = (type | ((channel-1) & 0x0F));

	Serial.write(statusbyte);
	Serial.write(data1);
	Serial.write(data2);

sei(); //enable interrupts
}

void checkKnob() {
//float knobValue
threshold = analogRead(knobPin);
//set threshold to knobValue mapping
threshold = mapfloat(threshold, knobMin, knobMax, threshMin, threshMax);

}

void knobMode() {
//scroll through menus and select values using only a single knob
//keep dreamin' kid,
}

void rampUp(int ledPin, int value, int time) {
LEDFader *led = &leds[ledPin];
// led->set_value(0);
led->fade(value, time);
}

void rampDown(int ledPin, int value, int time) {
LEDFader *led = &leds[ledPin];
// led->set_value(255); //turn on
led->fade(value, time); //fade out
}

void checkLED(){
//iterate through LED array and call update
for (byte i = 0; i < LED_NUM; i++) {
LEDFader *led = &leds[i];
led->update();
}
}

void checkButton() {
//no button in this build...
}

long readVcc() { //https://code.google.com/p/tinkerit/wiki/SecretVoltmeter
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate AVcc in mV
return result;
}

void checkBattery(){
//check battery voltage against internal 1.1v reference
//if below the minimum value, turn off the light show to save power
//don't check on every loop, settle delay in readVcc() slows things down a bit
if(batteryCheck < currentMillis){
batteryCheck = currentMillis+10000; //reset for next battery check

if(readVcc() < batteryLimit) { //if voltage > valueV
//battery failure
if(checkBat) { //first battery failure
for(byte j=0;j<LED_NUM;j++) { leds[j].stop_fade(); leds[j].set_value(0); } //reset leds, power savings
noteLEDs = 0; //shut off lightshow set at noteOn event, power savings
checkBat = 0; //update, first battery failure identified
} else { //not first low battery cycle
//do nothing, lights off indicates low battery
//MIDI continues to flow, MIDI data eventually garbles at very low voltages
//some USB-MIDI interfaces may crash due to garbled data
}
}
}
}

void bootLightshow(){
//light show to be displayed on boot
for (byte i = 5; i > 0; i--) {
LEDFader *led = &leds[i-1];
// led->set_value(200); //set to max

led->fade(200, 150); //fade up
while(led->is_fading()) checkLED();


led->fade(0,150+i*17);  //fade down
while(led->is_fading()) checkLED();

//move to next LED
}
}

//provide float map function
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//debug SRAM memory size
int freeRAM() {
extern int heap_start, *brkval;
int v;
return (int) &v - (brkval == 0 ? (int) &heap_start : (int) __brkval);
} // print free RAM at any point

//interrupt timing sample array
void sample()
{
if(index < samplesize) {
samples[index] = micros() - microseconds;
microseconds = samples[index] + microseconds; //rebuild micros() value w/o recalling
//micros() is very slow
//try a higher precision counter
//samples[index] = ((timer0_overflow_count << 8) + TCNT0) - microseconds;
index += 1;
}
}

void analyzeSample()
{
//eating up memory, one long at a time!
unsigned long averg = 0;
unsigned long maxim = 0;
unsigned long minim = 100000;
float stdevi = 0;
unsigned long delta = 0;
byte change = 0;

if (index = samplesize) { //array is full
unsigned long sampanalysis[analysize];
for (byte i=0; i<analysize; i++){
//skip first element in the array
sampanalysis[i] = samples[i+1]; //load analysis table (due to volitle)
//manual calculation
if(sampanalysis[i] > maxim) { maxim = sampanalysis[i]; }
if(sampanalysis[i] < minim) { minim = sampanalysis[i]; }
averg += sampanalysis[i];
stdevi += sampanalysis[i] * sampanalysis[i]; //prep stdevi
}

//manual calculation
averg = averg/analysize;
stdevi = sqrt(stdevi / analysize - averg * averg); //calculate stdevu
if (stdevi < 1) { stdevi = 1.0; } //min stdevi of 1
delta = maxim - minim;

//**********perform change detection
if (delta > (stdevi * threshold)){
  change = 1;
}
//*********

if(change){// set note and control vector
   int dur = 150+(map(delta%127,1,127,100,2500)); //length of note
   int ramp = 3 + (dur%100) ; //control slide rate, min 25 (or 3 ;)
   int notechannel = random(1,5); //gather a random channel for QY8 mode

   //set scaling, root key, note
   int setnote = map(averg%127,1,127,noteMin,noteMax);  //derive note, min and max note
   setnote = scaleNote(setnote, scaleSelect, root);  //scale the note
   // setnote = setnote + root; // (apply root?)
   if(QY8) { setNote(setnote, 100, dur, notechannel); } //set for QY8 mode
   else { setNote(setnote, 100, dur, channel); }

   //derive control parameters and set   
   setControl(controlNumber, controlMessage.value, delta%127, ramp); //set the ramp rate for the control
 }
 //reset array for next sample
index = 0;

}
}

int scaleSearch(int note, int scale[], int scalesize) {
for(byte i=1;i<scalesize;i++) {
if(note == scale[i]) { return note; }
else { if(note < scale[i]) { return scale[i]; } } //highest scale value less than or equal to note
//otherwise continue search
}
//didn't find note and didn't pass note value, uh oh!
return 6;//give arbitrary value rather than fail
}

int scaleNote(int note, int scale[], int root) {
//input note mod 12 for scaling, note/12 octave
//search array for nearest note, return scaled*octave
int scaled = note%12;
int octave = note/12;
int scalesize = (scale[0]);
//search entire array and return closest scaled note
scaled = scaleSearch(scaled, scale, scalesize);
scaled = (scaled + (12 * octave)) + root; //apply octave and root
return scaled;
}

/*--------
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN


#8

also i tried this approach with no luck , its translated from danish and is one of the most confusing instructionals i have ever read, tough the approach with an induktion is interessting

http://www.gunook.com/singende-pflanze-machen-sie-ihre-pflanze-mit-arduino-touche-und-einem-gameduino-singen/


#9

midisprout launchkontrol and axolti + liedetector https://soundcloud.com/phuck-dub/axoloti-with-midisprout-agave-versus-kurkuma


#10

MIDI Biodata Sonification Device v2.1 125 dollar


#11

300€.......

Damn......


#12

no this is a better version at tindie for 125 $ wich is really ok


#13

Yes, I was just referring to your first post in the thread.

125 is better, but still up there. I would love to hear which kind of sounds actually comes out of it :slight_smile: