From f6f4142a4b59346ccb7d5f63bd1173fdd13a713d Mon Sep 17 00:00:00 2001 From: Tomas Mudrunka Date: Mon, 8 Feb 2021 21:17:58 +0100 Subject: [PATCH] Nekobee --- .../Nekobee_test_blemidi.ino | 314 ++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 arduino/Nekobee_test_blemidi/Nekobee_test_blemidi.ino diff --git a/arduino/Nekobee_test_blemidi/Nekobee_test_blemidi.ino b/arduino/Nekobee_test_blemidi/Nekobee_test_blemidi.ino new file mode 100644 index 0000000..abc20d5 --- /dev/null +++ b/arduino/Nekobee_test_blemidi/Nekobee_test_blemidi.ino @@ -0,0 +1,314 @@ +#include +#include +//#include +#include +#include +#include +#include "driver/i2s.h" +#include "freertos/queue.h" + + +#include +//void connected(); +//void disconnected(); + + +nekobee_synth_t fSynth; + +#define SAMPLE_RATE 30000 +#define BUF_LEN XSYNTH_NUGGET_SIZE //512 + +void nekobee_handle_raw_event(nekobee_synth_t* const synth, const uint8_t size, const uint8_t* const data) +{ + if (size != 3) + return; + + switch (data[0] & 0xf0) + { + case 0x80: + nekobee_synth_note_off(synth, data[1], data[2]); + break; + case 0x90: + if (data[2] > 0) + nekobee_synth_note_on(synth, data[1], data[2]); + else + nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */ + break; + case 0xB0: + nekobee_synth_control_change(synth, data[1], data[2]); + break; + default: + break; + } +} + + +static const i2s_port_t i2s_num = I2S_NUM_0; // i2s port number + + + static const i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX /*| I2S_MODE_DAC_BUILT_IN*/ ), + .sample_rate = SAMPLE_RATE, + .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // only the top 8 bits will actually be used by the internal DAC, but using 8 bits stra> + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // always use stereo output. mono seems to be buggy, and the overhead is insignifcant o> + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB), // this appears to be the correct setting> + .intr_alloc_flags = 0, // default interrupt priority + .dma_buf_count = 4, // 8*128 bytes of buffer corresponds to 256 samples (2 channels, see above, 2 bytes per sample per channel) + .dma_buf_len = BUF_LEN, + .use_apll = false + }; + +static const i2s_pin_config_t pin_config = { + .bck_io_num = 26, + .ws_io_num = 25, + .data_out_num = 17, + .data_in_num = I2S_PIN_NO_CHANGE +}; + +uint8_t midii=0, midichar, mididata[8]; + + +void synth_task( void * pvParameters ) { + + + + i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver + + //i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels + i2s_set_pin(i2s_num, &pin_config); + + //You can call i2s_set_dac_mode to set built-in DAC output mode. + //i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); + + //i2s_set_sample_rates(i2s_num, SAMPLE_RATE); //set sample rates + + //i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver + + //i2s_adc_disable(i2s_num); + + + + + + + float *out; + out = (float*)malloc(sizeof(float)*BUF_LEN); + int32_t *outdma; + outdma = (int32_t*)malloc(sizeof(int32_t)*BUF_LEN*8); + + int i = 0, n=60, v=60; + //nekobee_synth_note_on(&fSynth, n , v); + while(1) { + if(i==0) { + esp_task_wdt_reset(); + //nekobee_synth_note_off(&fSynth, n , v); + n = 16+rand()%63; + v = 16+rand()%63; + n = rand()%127; + v = rand()%127; + //nekobee_synth_note_on(&fSynth, n , v); + } + + + + + while(Serial.available()) { + + midichar = Serial.read(); + if(midichar & 0b10000000) { + midii = 0; + } else if(midii == 0) continue; + mididata[midii] = midichar; + midii++; + + if(midii >= 3) { + nekobee_handle_raw_event(&fSynth, midii, mididata); + midii = 0; + } + } + + nekobee_synth_render_voices(&fSynth, out, BUF_LEN, 1); + for(int i = 0; i < BUF_LEN; i++) { + outdma[i*2] = outdma[(i*2)+1] = lrintf(out[i] * 2147483647); //((127)+round((out[i]*120.0)))*255; + } + + size_t bytes_written; + i2s_write(i2s_num, outdma, BUF_LEN*4*2, &bytes_written, portMAX_DELAY); + + //printf("%d\t%f\n", outdma[0], out[0]); + //fwrite (out, sizeof(float)*BUF_LEN, 1, stdout); + //Serial.println(out[0]); + //Serial.println(uxTaskGetStackHighWaterMark(NULL)); + //Serial.printf("%d\n", outdma[0]); + //mgos_msleep(30); + //delay(1); + i++; if(i>400) i=0; + } + + } + + +uint8_t bn=0, bv=0; + +void onNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) +{ + nekobee_synth_note_off(&fSynth, bn , bv); + nekobee_synth_note_on(&fSynth, note , velocity); + bn = note, bv = velocity; + Serial.print("on"); + Serial.println(note); +} + +void onNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) +{ + nekobee_synth_note_off(&fSynth, note , velocity); + Serial.print("off"); + Serial.println(note); +} + + + + +void setup() { + Serial.begin(115200); + + nekobee_init_tables(); + + // init synth + fSynth.sample_rate = SAMPLE_RATE; + fSynth.deltat = 1.0f / (float)SAMPLE_RATE; + fSynth.nugget_remains = 0; + + fSynth.note_id = 0; + fSynth.polyphony = XSYNTH_DEFAULT_POLYPHONY; + fSynth.voices = XSYNTH_DEFAULT_POLYPHONY; + fSynth.monophonic = XSYNTH_MONO_MODE_ONCE; + fSynth.glide = 0; + fSynth.last_noteon_pitch = 0.0f; + fSynth.vcf_accent = 0.0f; + fSynth.vca_accent = 0.0f; + + for (int i=0; i<8; ++i) + fSynth.held_keys[i] = -1; + + fSynth.voice = nekobee_voice_new(); + fSynth.voicelist_mutex_grab_failed = 0; + //pthread_mutex_init(&fSynth.voicelist_mutex, nullptr); + + fSynth.channel_pressure = 0; + fSynth.pitch_wheel_sensitivity = 0; + fSynth.pitch_wheel = 0; + + for (int i=0; i<128; ++i) + { + fSynth.key_pressure[i] = 0; + fSynth.cc[i] = 0; + } + fSynth.cc[7] = 127; // full volume + + fSynth.mod_wheel = 1.0f; + fSynth.pitch_bend = 1.0f; + fSynth.cc_volume = 1.0f; + + // Default values + /* + fParams.waveform = 0.0f; + fParams.tuning = 0.0f; + fParams.cutoff = 25.0f; + fParams.resonance = 25.0f; + fParams.envMod = 50.0f; + fParams.decay = 75.0f; + fParams.accent = 25.0f; + fParams.volume = 75.0f; + fParams.bypass = false; + */ + + // Internal stuff + fSynth.waveform = 0.0f; + fSynth.tuning = 1.0f; + fSynth.cutoff = 5.0f; + fSynth.resonance = 0.8f; + fSynth.envmod = 0.3f; + fSynth.decay = 0.0002f; + fSynth.accent = 0.3f; + fSynth.volume = 0.75f; + + //nekobee_synth_render_voices(&fSynth, NULL, 0, 1); //Update controls + nekobee_synth_init_controls(&fSynth); + //nekobee_synth_note_on(&fSynth, 80, 128); + + Serial.println("READY"); + + xTaskCreate(&synth_task, "blinking_led", 5*configMINIMAL_STACK_SIZE, NULL, 0, NULL); + + + + BLEMidiServer.begin("NekoMIDI"); + BLEMidiServer.setOnConnectCallback([](){ // To show how to make a callback with a lambda function + Serial.println("Connected"); + }); + BLEMidiServer.setOnDisconnectCallback([](){ // To show how to make a callback with a lambda function + Serial.println("Disconnected"); + }); + BLEMidiServer.setNoteOnCallback(onNoteOn); + BLEMidiServer.setNoteOffCallback(onNoteOff); + //BLEMidiServer.setControlChangeCallback(onControlChange); + //BLEMidiServer.enableDebugging(); + +} + + + +int i=0; +void loop() { + /* + void + nekobee_voice_render(nekobee_synth_t *synth, nekobee_voice_t *voice, + float *out, unsigned long sample_count, + int do_control_update) + + void nekobee_synth_render_voices(nekobee_synth_t *synth, float *out, + unsigned long sample_count, + int do_control_update); + */ + + //nekobee_synth_render_voices(&fSynth, outbuffer, len, update_controls); + + //float out; + + //nekobee_synth_render_voices(&fSynth, &out, 1, 0); + + //Serial.println(out); + //Serial.println(i++); + delay(30); + + + + //fSynth.waveform = 0.0f; + //fSynth.tuning = 1.0f; + + int adc2 = 0; + if(adc2_get_raw(ADC2_CHANNEL_2, ADC_WIDTH_12Bit, &adc2) == ESP_OK) + fSynth.cutoff = ((float)adc2)/(4095.0f/40.0f); + if(adc2_get_raw(ADC2_CHANNEL_0, ADC_WIDTH_12Bit, &adc2) == ESP_OK) + fSynth.resonance = ((float)adc2)/(4095.0f); + + fSynth.envmod = ((float)analogRead(35))/4095.0f; + + //fSynth.decay = 0.0002f; + fSynth.decay = ((float)analogRead(34))/(4095.0f/0.0004f); + fSynth.accent = ((float)analogRead(36))/4095.0f; + fSynth.volume = ((float)analogRead(39))/4095.0f; + + /* + Serial.print("SYNTH:"); + Serial.print("\tCUT:"); Serial.print(fSynth.cutoff); + Serial.print("\tRES:"); Serial.print(fSynth.resonance); + Serial.print("\tENV:"); Serial.print(fSynth.envmod); + Serial.print("\tDEC:"); Serial.printf("%.7f", fSynth.decay); + Serial.print("\tACC:"); Serial.print(fSynth.accent); + Serial.print("\tVOL:"); Serial.print(fSynth.volume); + Serial.println(); + */ + +} -- 2.30.2