Thinking about the network that connects the Space Rocks. Initially I started with the idea of all four rocks connecting equally, which isn’t really possible.
The network will be connected as a star formation, as shown here:
Similar to this diagram I drew a while back:
Ending up with something akin to this:
The co-ordinator would be loaded with one Mozzi synth, and the same synth is installed on the three nodes, with each node changing a different filter (attack, decay and sustain). The code for this looks like so:
Co-ordinator:
// include all libraries #include <XBee.h> #include <SoftwareSerial.h> #include <MozziGuts.h> #include <Oscil.h> #include <EventDelay.h> #include <ADSR.h> #include <tables/sin8192_int8.h> #include <mozzi_rand.h> #include <mozzi_midi.h> // uncomment the following line to enable debug output #define DEBUG // debug macros #ifdef DEBUG #define DEBUG_BEGIN(x) Serial.begin (x) #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_BEGIN(x) #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #endif // Mozzi control rate in Hz #define CONTROL_RATE 128 Oscil <8192, AUDIO_RATE> aOscil(SIN8192_DATA); // for triggering the envelope EventDelay noteDelay; ADSR <CONTROL_RATE, CONTROL_RATE> envelope; boolean note_is_on = true; byte gain; // XBee packet reception timeout in ms #define XBEE_PACKET_TIMEOUT 250 // RSSI reading timeout in us #define RSSI_READING_TIMEOUT 100 // Arduino pin connections #define RSSI_PIN 5 #define XBEE_DOUT 6 #define XBEE_DIN 7 #define AUDIO_PIN 9 // freqency range bounds in Hz #define ATTACK_LOW 0 #define ATTACK_HIGH 1000 #define DECAY_LOW 0 #define DECAY_HIGH 1000 #define SUSTAIN_LOW 0 #define SUSTAIN_HIGH 1000 // RSSI range bounds int RSSI_LOW = 25; int RSSI_HIGH = 45; int RSSI_LOW_2 = 25; int RSSI_HIGH_2 = 45; int RSSI_LOW_3 = 25; int RSSI_HIGH_3 = 45; // number of samples for moving average filter #define SAMPLES 10 // XBee object instance XBee xbee = XBee(); // address of destination XBee (node address) XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, 0x40A58A5D); // packet to be sent to coordinator uint8_t ping[] = {0xAA, 0xAA}; ZBTxRequest pingRequest = ZBTxRequest(addr64, ping, sizeof(ping)); XBeeResponse response = XBeeResponse(); // create reusable response objects for responses we expect to handle ZBRxResponse rx = ZBRxResponse(); // SoftwareSerial port SoftwareSerial beeSerial(XBEE_DOUT, XBEE_DIN); // Mozzi sine oscillator //Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA); // array to hold RSSI samples for filter float rssiSamples[SAMPLES]; // current position in array int pos = 0; float rssiAttack = 0; float rssiDecay = 0; float rssiSustain = 0; // moving average filter float movingAverage(float* arr, int newValue, int pos) { // update array arr[pos] = newValue; // get array total float total = 0; for (int i = 0; i < SAMPLES; i++) { total += arr[i]; } // get average float average = total / (float)SAMPLES; return (average); } void setup() { randSeed(); // fresh random noteDelay.set(2000); // begin Serial communication with PC DEBUG_BEGIN(9600); // set pin modes pinMode(RSSI_PIN, INPUT); pinMode(AUDIO_PIN, OUTPUT); // initialize array contents to 0 for (int i = 0; i < SAMPLES; i++) { rssiSamples[i] = 0; } // begin Serial communication with XBee beeSerial.begin(9600); // set XBee serial port xbee.setSerial(beeSerial); // start Mozzi startMozzi(CONTROL_RATE); // set output frequency to the lowest value //aSin.setFreq(FREQ_LOW); } unsigned int duration, attack, decay, sustain, release_ms; void updateControl() { // send packet to node xbee.send(pingRequest); // try to receive pong packet if (xbee.readPacket(XBEE_PACKET_TIMEOUT)) { if (xbee.getResponse().isAvailable()) { if (xbee.getResponse().getApiId() == 16) { xbee.getResponse().getZBRxResponse(rx); uint16_t sender = rx.getRemoteAddress16(); //DEBUG_PRINTLN(sender); if (sender == 18431) { // try to read raw RSSI value int rssiRaw = pulseIn(RSSI_PIN, HIGH, RSSI_READING_TIMEOUT); // check if the read was successful if (rssiRaw > 0) { if (rssiRaw <= RSSI_LOW) { RSSI_LOW = rssiRaw; } if (rssiRaw >= RSSI_HIGH) { RSSI_HIGH = rssiRaw; } // if so, map the raw RSSI value to frequency range int rssiMapped = map(rssiRaw, RSSI_LOW, RSSI_HIGH, ATTACK_LOW, ATTACK_HIGH); // filter RSSI value rssiAttack = movingAverage(rssiSamples, rssiMapped, pos); // check array position overflow if (pos == SAMPLES - 1) { pos = 0; } else { pos++; } // print both values to PC for debugging /*DEBUG_PRINT(rssiRaw); DEBUG_PRINT('\t'); DEBUG_PRINT(rssiMapped); DEBUG_PRINT('\t'); DEBUG_PRINTLN(rssiFiltered);*/ } } else if (sender == 24063) { int rssiRaw = pulseIn(RSSI_PIN, HIGH, RSSI_READING_TIMEOUT); // check if the read was successful if (rssiRaw > 0) { if (rssiRaw <= RSSI_LOW_2) { RSSI_LOW_2 = rssiRaw; } if (rssiRaw >= RSSI_HIGH_2) { RSSI_HIGH_2 = rssiRaw; } // if so, map the raw RSSI value to frequency range int rssiMapped = map(rssiRaw, RSSI_LOW_2, RSSI_HIGH_2, DECAY_LOW, DECAY_HIGH); // filter RSSI value rssiDecay = movingAverage(rssiSamples, rssiMapped, pos); // check array position overflow if (pos == SAMPLES - 1) { pos = 0; } else { pos++; } // print both values to PC for debugging /*DEBUG_PRINT(rssiRaw); DEBUG_PRINT('\t'); DEBUG_PRINT(rssiMapped); DEBUG_PRINT('\t'); DEBUG_PRINTLN(rssiFiltered);*/ } } else if (sender == 20479) { int rssiRaw = pulseIn(RSSI_PIN, HIGH, RSSI_READING_TIMEOUT); // check if the read was successful if (rssiRaw > 0) { if (rssiRaw <= RSSI_LOW_3) { RSSI_LOW_3 = rssiRaw; } if (rssiRaw >= RSSI_HIGH_3) { RSSI_HIGH_3 = rssiRaw; } // if so, map the raw RSSI value to frequency range int rssiMapped = map(rssiRaw, RSSI_LOW_3, RSSI_HIGH_3, SUSTAIN_LOW, SUSTAIN_HIGH); // filter RSSI value rssiSustain = movingAverage(rssiSamples, rssiMapped, pos); // check array position overflow if (pos == SAMPLES - 1) { pos = 0; } else { pos++; } // print both values to PC for debugging /*DEBUG_PRINT(rssiRaw); DEBUG_PRINT('\t'); DEBUG_PRINT(rssiMapped); DEBUG_PRINT('\t'); DEBUG_PRINTLN(rssiFiltered);*/ } } } } } if (noteDelay.ready()) { // choose envelope levels byte attack_level = rand(128) + 127; byte decay_level = rand(255); envelope.setADLevels(attack_level, decay_level); // generate a random new adsr parameter value in milliseconds int r = rand(1000) - rand(1000); unsigned int new_value = abs(r); release_ms = new_value; // randomly choose one of the adsr parameters and set the new value /*switch (rand(4)){ case 0: attack = new_value; break; case 1: decay = new_value; break; case 2: sustain = new_value; break; case 3: release_ms = new_value; break; }*/ attack = rssiAttack; decay = rssiDecay; sustain = rssiSustain; envelope.setTimes(attack, decay, sustain, release_ms); envelope.noteOn(); byte midi_note = rand(107) + 20; aOscil.setFreq((int)mtof(midi_note)); DEBUG_PRINT("ATTACK - "); DEBUG_PRINTLN(attack); DEBUG_PRINT("DECAY - "); DEBUG_PRINTLN(decay); DEBUG_PRINT("SUSTAIN - "); DEBUG_PRINTLN(sustain); // print to screen /*Serial.print("midi_note\t"); Serial.println(midi_note); Serial.print("attack_level\t"); Serial.println(attack_level); Serial.print("decay_level\t"); Serial.println(decay_level); Serial.print("attack\t\t"); Serial.println(attack); Serial.print("decay\t\t"); Serial.println(decay); Serial.print("sustain\t\t"); Serial.println(sustain); Serial.print("release\t\t"); Serial.println(release_ms); Serial.println();*/ noteDelay.start(attack + decay + sustain + release_ms); } envelope.update(); gain = envelope.next(); // this is where it's different to an audio rate envelope } int updateAudio() { return (int) (gain * aOscil.next()) >> 8; } void loop() { audioHook(); }
And the three nodes:
// include all libraries #include <XBee.h> #include <SoftwareSerial.h> #include <MozziGuts.h> #include <Oscil.h> // oscillator template #include <tables/sin2048_int8.h> // sine table for oscillator #include <RollingAverage.h> #include <ControlDelay.h> // uncomment the following line to enable debug output #define DEBUG // debug macros #ifdef DEBUG #define DEBUG_BEGIN(x) Serial.begin (x) #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_BEGIN(x) #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #endif unsigned int echo_cells_1 = 32; unsigned int echo_cells_2 = 60; unsigned int echo_cells_3 = 127; // Mozzi control rate in Hz ControlDelay <128, int> kDelay; // 2seconds // oscils to compare bumpy to averaged control input Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin0(SIN2048_DATA); Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin1(SIN2048_DATA); Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA); Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin3(SIN2048_DATA); // use: RollingAverage <number_type, how_many_to_average> myThing RollingAverage <int, 32> kAverage; // how_many_to_average has to be power of 2 int averaged; float rssiFiltered = 512; // XBee packet reception timeout in ms #define XBEE_PACKET_TIMEOUT 250 // RSSI reading timeout in us #define RSSI_READING_TIMEOUT 100 // Arduino pin connections #define RSSI_PIN 5 #define XBEE_DOUT 6 #define XBEE_DIN 7 #define AUDIO_PIN 9 // freqency range bounds in Hz #define FREQ_LOW 512 #define FREQ_HIGH 1023 // RSSI range bounds int RSSI_LOW = 11; int RSSI_HIGH = 20; // number of samples for moving average filter #define SAMPLES 10 // XBee object instance XBee xbee = XBee(); // address of destination XBee (coordinator address) XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, 0x4176E94F); // packet to be sent to coordinator uint8_t pong[] = {0xAA, 0xAA}; ZBTxRequest pongRequest = ZBTxRequest(addr64, pong, sizeof(pong)); XBeeResponse response = XBeeResponse(); // create reusable response objects for responses we expect to handle ZBRxResponse rx = ZBRxResponse(); // SoftwareSerial port SoftwareSerial beeSerial(XBEE_DOUT, XBEE_DIN); // Mozzi sine oscillator Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA); // array to hold RSSI samples for filter float rssiSamples[SAMPLES]; // current position in array int pos = 0; // moving average filter float movingAverage(float* arr, int newValue, int pos) { // update array arr[pos] = newValue; // get array total float total = 0; for (int i = 0; i < SAMPLES; i++) { total += arr[i]; } // get average float average = total / (float)SAMPLES; return (average); } void setup() { // begin Serial communication with PC DEBUG_BEGIN(9600); // set pin modes pinMode(RSSI_PIN, INPUT); pinMode(AUDIO_PIN, OUTPUT); // initialize array contents to 0 for (int i = 0; i < SAMPLES; i++) { rssiSamples[i] = 0; } // begin Serial communication with XBee beeSerial.begin(9600); // set XBee serial port xbee.setSerial(beeSerial); // start Mozzi kDelay.set(echo_cells_1); startMozzi(); // set output frequency to the lowest value //aSin.setFreq(FREQ_LOW); } void updateControl() { // try to receive ping packet with 250 ms timeout if (xbee.readPacket(XBEE_PACKET_TIMEOUT)) { if (xbee.getResponse().isAvailable()) { //DEBUG_PRINTLN(xbee.getResponse().getApiId()); if (xbee.getResponse().getApiId() == 16) { xbee.getResponse().getZBRxResponse(rx); uint16_t sender = rx.getRemoteAddress16(); //DEBUG_PRINTLN(sender); } } // try to read raw RSSI value with 100 us timeout int rssiRaw = pulseIn(RSSI_PIN, LOW, RSSI_READING_TIMEOUT); // check if the read was successful if (rssiRaw > 0) { // if so, map the raw RSSI value to frequency range if (rssiRaw <= RSSI_LOW) { RSSI_LOW = rssiRaw; } if (rssiRaw >= RSSI_HIGH) { RSSI_HIGH = rssiRaw; } int rssiMapped = map(rssiRaw, RSSI_LOW, RSSI_HIGH, FREQ_LOW, FREQ_HIGH); // filter RSSI value rssiFiltered = movingAverage(rssiSamples, rssiMapped, pos); // check array position overflow if (pos == SAMPLES - 1) { pos = 0; } else { pos++; } // print both values to PC for debugging /*DEBUG_PRINT(rssiRaw); DEBUG_PRINT('\t'); DEBUG_PRINT(rssiMapped); DEBUG_PRINT('\t'); DEBUG_PRINTLN(rssiFiltered);*/ DEBUG_PRINT(rssiFiltered); DEBUG_PRINT(" - "); DEBUG_PRINT(RSSI_LOW); DEBUG_PRINT(" - "); DEBUG_PRINTLN(RSSI_HIGH); //rssiFiltered); // adjust sine wave frequency //aSin.setFreq(rssiFiltered); } } averaged = kAverage.next(rssiFiltered); aSin0.setFreq(averaged); aSin1.setFreq(kDelay.next(averaged)); aSin2.setFreq(kDelay.read(echo_cells_2)); aSin3.setFreq(kDelay.read(echo_cells_3)); // send packet to coordinator xbee.send(pongRequest); // delay(2000); } int updateAudio() { return 3 * ((int)aSin0.next() + aSin1.next() + (aSin2.next() >> 1) + (aSin3.next() >> 2)) >> 3; //return aSin.next(); } void loop() { pong[0] = 100 >> 8 & 0xff; pong[1] = 100 & 0xff; audioHook(); }
You must be logged in to post a comment.