void AMDemod::update(void) { if (!pass) return; audio_block_t *blocki, *blockq; int16_t *pi, *pq, *end; int32_t sum; blocki = receiveWritable(0); // receives I, end result is written in channel 0 blockq = receiveReadOnly(1); // receives Q if (!blocki) { if (blockq) release(blockq); return; } if (!blockq) { release(blocki); return; } pi = (int16_t *)(blocki->data); pq = (int16_t *)(blockq->data); end = pi + AUDIO_BLOCK_SAMPLES; while (pi < end) { // square and sum I and Q sum = *pi * *pi; sum += *pq * *pq; // The result of squaring a 1.15 is 2.30. // Shift the sum up one bit to make it 1.31 (Q31) // and then that becomes the input to the arm sqrt function sum <<= 1; arm_sqrt_q31((q31_t)sum,(q31_t *) &sum); // The result is in the high order 16 bits of sum *pi++ = sum >> 16; pq++; } transmit(blocki); release(blocki); release(blockq); }
void AudioSynthDigiFilter::update(void) { audio_block_t *block, *modBlock; uint16_t baseFreq,envIn; int16_t modIn; uint8_t pot1value; block = receiveReadOnly(0); modBlock = receiveReadOnly(1); if (block) { if (modBlock) { //final frequency = baseFreq + envIn * envAmt + modIn * modAmt; //following implementation isn't correct yet: negative envIns aren't possible envIn = (block->data[64] * (envAmt)) >> 15;//32768 is the middle here, so we can have inverting and non in modIn = (modBlock->data[64] * modAmt) >> 15; baseFreq = freq; int32_t totalfreq = baseFreq + envIn + modIn; if(totalfreq > 65535) totalfreq = 65535; if(totalfreq < 0) totalfreq = 0; pot1value = totalfreq >> 8; outvalue = pot1value; digitalPotWrite(pot1value); release(modBlock); } release(block); } }
void AudioFilterFIR::update(void) { audio_block_t *block,*b_new; // If there's no coefficient table, give up. if(coeff_p == NULL)return; // do passthru if(coeff_p == FIR_PASSTHRU) { // Just passthrough block = receiveReadOnly(0); if(block) { transmit(block,0); release(block); } return; } // Left Channel block = receiveReadOnly(0); // get a block for the FIR output b_new = allocate(); if(block && b_new) { if(arm_fast) arm_fir_fast_q15(&l_fir_inst, (q15_t *)block->data, (q15_t *)b_new->data, AUDIO_BLOCK_SAMPLES); else arm_fir_q15(&l_fir_inst, (q15_t *)block->data, (q15_t *)b_new->data, AUDIO_BLOCK_SAMPLES); // send the FIR output to the left channel transmit(b_new,0); } if(block)release(block); if(b_new)release(b_new); }
void AudioOutputI2SQuad::update(void) { audio_block_t *block; block = receiveReadOnly(0); if (block) release(block); block = receiveReadOnly(1); if (block) release(block); block = receiveReadOnly(2); if (block) release(block); block = receiveReadOnly(3); if (block) release(block); }
void AudioAnalyzePeak::update(void) { audio_block_t *block; const int16_t *p, *end; int32_t min, max; block = receiveReadOnly(); if (!block) { return; } p = block->data; end = p + AUDIO_BLOCK_SAMPLES; min = min_sample; max = max_sample; do { int16_t d=*p++; // TODO: can we speed this up with SSUB16 and SEL // http://www.m4-unleashed.com/parallel-comparison/ if (d<min) min=d; if (d>max) max=d; } while (p < end); min_sample = min; max_sample = max; new_output = true; release(block); }
void AudioMixer2::update(void) { audio_block_t *in, *out=NULL; unsigned int channel; for (channel=0; channel < 2; channel++) { if (!out) { out = receiveWritable(channel); if (out) { int32_t mult = multiplier[channel]; if (mult != 65536) applyGain(out->data, mult); } } else { in = receiveReadOnly(channel); if (in) { applyGainThenAdd(out->data, in->data, multiplier[channel]); release(in); } } } if (out) { transmit(out); release(out); } }
void AudioOutputI2S::update(void) { // null audio device: discard all incoming data //if (!active) return; //audio_block_t *block = receiveReadOnly(); //if (block) release(block); audio_block_t *block; block = receiveReadOnly(0); // input 0 = left channel if (block) { __disable_irq(); if (block_left_1st == NULL) { block_left_1st = block; block_left_offset = 0; __enable_irq(); } else if (block_left_2nd == NULL) { block_left_2nd = block; __enable_irq(); } else { audio_block_t *tmp = block_left_1st; block_left_1st = block_left_2nd; block_left_2nd = block; block_left_offset = 0; __enable_irq(); release(tmp); } } block = receiveReadOnly(1); // input 1 = right channel if (block) { __disable_irq(); if (block_right_1st == NULL) { block_right_1st = block; block_right_offset = 0; __enable_irq(); } else if (block_right_2nd == NULL) { block_right_2nd = block; __enable_irq(); } else { audio_block_t *tmp = block_right_1st; block_right_1st = block_right_2nd; block_right_2nd = block; block_right_offset = 0; __enable_irq(); release(tmp); } } }
void AudioAnalyzePrint::update(void) { audio_block_t *block; uint32_t offset = 0; uint32_t remain, n; block = receiveReadOnly(); if (!block) return; while (offset < AUDIO_BLOCK_SAMPLES) { remain = AUDIO_BLOCK_SAMPLES - offset; switch (state) { case STATE_WAIT_TRIGGER: // TODO: implement this.... offset = AUDIO_BLOCK_SAMPLES; break; case STATE_DELAY: //Serial.printf("STATE_DELAY, count = %u\n", count); if (remain < count) { count -= remain; offset = AUDIO_BLOCK_SAMPLES; } else { offset += count; count = print_length; state = STATE_PRINTING; } break; case STATE_PRINTING: n = count; if (n > remain) n = remain; count -= n; while (n > 0) { Serial.println(block->data[offset++]); n--; } if (count == 0) state = STATE_IDLE; break; default: // STATE_IDLE offset = AUDIO_BLOCK_SAMPLES; break; } } release(block); }
void AudioAnalyzeFFT256::update(void) { audio_block_t *block; block = receiveReadOnly(); if (!block) return; if (!prevblock) { prevblock = block; return; } copy_to_fft_buffer(buffer, prevblock->data); copy_to_fft_buffer(buffer+256, block->data); //window = AudioWindowBlackmanNuttall256; //window = NULL; if (window) apply_window_to_fft_buffer(buffer, window); arm_cfft_radix4_q15(&fft_inst, buffer); // G. Heinzel's paper says we're supposed to average the magnitude // squared, then do the square root at the end. if (count == 0) { for (int i=0; i < 128; i++) { uint32_t tmp = *((uint32_t *)buffer + i); uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); sum[i] = magsq / naverage; } } else { for (int i=0; i < 128; i++) { uint32_t tmp = *((uint32_t *)buffer + i); uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); sum[i] += magsq / naverage; } } if (++count == naverage) { count = 0; for (int i=0; i < 128; i++) { output[i] = sqrt_uint32_approx(sum[i]); } outputflag = true; } release(prevblock); prevblock = block; }
void AudioOutputAnalog::update(void) { audio_block_t *block; block = receiveReadOnly(0); // input 0 if (block) { __disable_irq(); if (block_left_1st == NULL) { block_left_1st = block; __enable_irq(); } else if (block_left_2nd == NULL) { block_left_2nd = block; __enable_irq(); } else { audio_block_t *tmp = block_left_1st; block_left_1st = block_left_2nd; block_left_2nd = block; __enable_irq(); release(tmp); } } }
void Beat_detector::update() { audio_block_t *block = receiveReadOnly(); if (!block) { return; } const int16_t *p = block->data; const int16_t *end = p + AUDIO_BLOCK_SAMPLES; do { m_energy += *p * *p; if (m_count >= ENERGY_SAMPLES) { memmove(m_history + 1, m_history, sizeof(m_history) - sizeof(m_history[0])); m_history[0] = m_energy; m_energy = 0; m_count = 0; } ++p; } while (p < end); release(block); }
void AudioOutputI2SQuad::update(void) { audio_block_t *block, *tmp; block = receiveReadOnly(0); // channel 1 if (block) { __disable_irq(); if (block_ch1_1st == NULL) { block_ch1_1st = block; ch1_offset = 0; __enable_irq(); } else if (block_ch1_2nd == NULL) { block_ch1_2nd = block; __enable_irq(); } else { tmp = block_ch1_1st; block_ch1_1st = block_ch1_2nd; block_ch1_2nd = block; ch1_offset = 0; __enable_irq(); release(tmp); } } block = receiveReadOnly(1); // channel 2 if (block) { __disable_irq(); if (block_ch2_1st == NULL) { block_ch2_1st = block; ch2_offset = 0; __enable_irq(); } else if (block_ch2_2nd == NULL) { block_ch2_2nd = block; __enable_irq(); } else { tmp = block_ch2_1st; block_ch2_1st = block_ch2_2nd; block_ch2_2nd = block; ch2_offset = 0; __enable_irq(); release(tmp); } } block = receiveReadOnly(2); // channel 3 if (block) { __disable_irq(); if (block_ch3_1st == NULL) { block_ch3_1st = block; ch3_offset = 0; __enable_irq(); } else if (block_ch3_2nd == NULL) { block_ch3_2nd = block; __enable_irq(); } else { tmp = block_ch3_1st; block_ch3_1st = block_ch3_2nd; block_ch3_2nd = block; ch3_offset = 0; __enable_irq(); release(tmp); } } block = receiveReadOnly(3); // channel 4 if (block) { __disable_irq(); if (block_ch4_1st == NULL) { block_ch4_1st = block; ch4_offset = 0; __enable_irq(); } else if (block_ch4_2nd == NULL) { block_ch4_2nd = block; __enable_irq(); } else { tmp = block_ch4_1st; block_ch4_1st = block_ch4_2nd; block_ch4_2nd = block; ch4_offset = 0; __enable_irq(); release(tmp); } } }
void AudioAnalyzeFFT256::update(void) { audio_block_t *block; block = receiveReadOnly(); if (!block) return; #if AUDIO_BLOCK_SAMPLES == 128 if (!prevblock) { prevblock = block; return; } copy_to_fft_buffer(buffer, prevblock->data); copy_to_fft_buffer(buffer+256, block->data); //window = AudioWindowBlackmanNuttall256; //window = NULL; if (window) apply_window_to_fft_buffer(buffer, window); arm_cfft_radix4_q15(&fft_inst, buffer); // G. Heinzel's paper says we're supposed to average the magnitude // squared, then do the square root at the end. if (count == 0) { for (int i=0; i < 128; i++) { uint32_t tmp = *((uint32_t *)buffer + i); uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); sum[i] = magsq / naverage; } } else { for (int i=0; i < 128; i++) { uint32_t tmp = *((uint32_t *)buffer + i); uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); sum[i] += magsq / naverage; } } if (++count == naverage) { count = 0; for (int i=0; i < 128; i++) { output[i] = sqrt_uint32_approx(sum[i]); } outputflag = true; } release(prevblock); prevblock = block; #elif AUDIO_BLOCK_SAMPLES == 64 if (prevblocks[2] == NULL) { prevblocks[2] = prevblocks[1]; prevblocks[1] = prevblocks[0]; prevblocks[0] = block; return; } if (count == 0) { count = 1; copy_to_fft_buffer(buffer, prevblocks[2]->data); copy_to_fft_buffer(buffer+128, prevblocks[1]->data); copy_to_fft_buffer(buffer+256, prevblocks[1]->data); copy_to_fft_buffer(buffer+384, block->data); if (window) apply_window_to_fft_buffer(buffer, window); arm_cfft_radix4_q15(&fft_inst, buffer); } else { count = 2; const uint32_t *p = (uint32_t *)buffer; for (int i=0; i < 128; i++) { uint32_t tmp = *p++; int16_t v1 = tmp & 0xFFFF; int16_t v2 = tmp >> 16; output[i] = sqrt_uint32_approx(v1 * v1 + v2 * v2); } } release(prevblocks[2]); prevblocks[2] = prevblocks[1]; prevblocks[1] = prevblocks[0]; prevblocks[0] = block; #endif }
void AudioSynthKS::update(void){ audio_block_t *block, *excitement; int32_t s0, s1, s2, s3; int32_t acc; int i; if (!running) return; block = allocate(); if (block == NULL) return; // If buflen has been reduced by a wavelength change & cursor is now outside of bounds, reposition cursor. // while (cursor >= buflen) { // cursor -= buflen; // } if (triggering) { // We've just been asked to excite our buffer triggering = false; triggered = true; triggerPoint = cursorPlus(buflen); Serial.print("triggerPoint: "); Serial.println(triggerPoint, DEC); } if (triggered) { //DEBUG // read a block of input excitement (noise, or whatever you got) excitement = receiveReadOnly(_exciter); // could be null? if (excitement == NULL) { Serial.println("z"); // DEBUG release(block); return; //DEBUG } } for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { if (triggered) { block->data[i] = buffer[cursor] = excitement->data[i]; } else { // K/S algorithm at its simplest: // load the cursor sample & the one just behind it // (In our travelling-buffer implementation, cursor-buflen == cursor) s0 = buffer[cursorMinus(1)]; s1 = buffer[cursorMinus(buflen)]; // TODO: put a knob on this bug: // Overshooting the beginning of the buffer throws tiny specs of random bugnoise into the tube ... which ends up sounding kind of nice // Seems like values past 32 become insipid ... adjust exponentially. //s1 = buffer[cursorMinus(buflen + 1)]; // Adding a third element creates ring-mod-type stuff, and also brings about some tremolo related to _bufmax. // That would be a nice effect to control ... s2 = buffer[cursorMinus(_magic1)]; // // Also: when this is a fixed value (not relative to buflen) then crazy FM-sounding shit happens ... // TODO: an absolute/pitched toggle for these knob vals. //s2 = buffer[cursorMinus(128)]; // average them (comb filter), // then mix them back into the buffer (using decayBalance), // and put that in the output. // block->data[i] = buffer[cursor] = ((s0 + s1) / 2); // "drum variant" according to K and S? acc = ((s0 + s1) / 2) ; if (random(0,128) >= _drumness) // flip a coin acc = 0 - acc; // negate the samplE block->data[i] = buffer[cursor] = acc; /* workingish but parked for now? block->data[i] = buffer[cursor] = (int16_t) // how much of the original sample (s0) to mix? (((65535 - _decayBalance) * s0)>>16) // will be zero when decayBalance = 0xffff + // how much of the new value to mix? ((_decayBalance * ((s0 + s1) / 2) )>>16); // will be zero when decayBalance = 0; */ // This ought to do the same thing, but it causes noise and crashes ... wtf? //block->data[i] = buffer[cursor] = (int16_t)((s0 + s1) * 0.5); // Other things we could do instead: // If we subtract instead of adding, the whole thing drops an octave & also sounds slightly more lowpass filtered ... // I believe the octave thing is because the entire waveform is inverted on every pass, so it becomes a half-wave. // The filter thing may be math rounding issues or similar ... otherwise i don't know. At any rate, this does sound nice. // TODO: my kingdom for a 'scope ... // block->data[i] = buffer[cursor] = ((s0 - s1) / 2); // Here's the same thing redrawn in the more 'general' form of a digital comb filter: // (feedbackGain * buffer[cursor - feedbackDistance]) + (feedforwardGain * buffer[cursor + feedforwardDistance]) // (with feedforwardDistance = 0, feedbackDistance = 1, and both gains at 0.5. // block->data[i] = buffer[cursor] = int( (0.5 * buffer[cursorMinus(1)]) + (0.5 * buffer[cursorMinus(buflen + 0)])); // much obliged: https://www.dsprelated.com/freebooks/filters/Analysis_Digital_Comb_Filter.html // three element version: //block->data[i] = buffer[cursor] = (int16_t)((s0 + s1 + s2) / 3); //block->data[i] = buffer[cursor] = ((s0 + s1 + s2) / 3); // four element version: //s3 = buffer[cursorMinus(23)]; //block->data[i] = buffer[cursor] = ((s0 + s1 + s2 + s3) / 4); } // increment cursor if (++cursor == _bufmax) { cursor = 0; } if (cursor == triggerPoint) { triggered = false; } } if (excitement != NULL) { release(excitement); } transmit(block); release(block); }
void BandPassFilter::update() {/* if(enabled) { AudioFilterStateVariable::update(); }*/ audio_block_t *input_block=NULL, *control_block=NULL; audio_block_t *lowpass_block=NULL, *bandpass_block=NULL, *highpass_block=NULL; input_block = receiveReadOnly(0); control_block = receiveReadOnly(1); if (!input_block) { if (control_block) release(control_block); return; } if(enabled) { lowpass_block = allocate(); if (!lowpass_block) { release(input_block); if (control_block) release(control_block); return; } bandpass_block = allocate(); if (!bandpass_block) { release(input_block); release(lowpass_block); if (control_block) release(control_block); return; } highpass_block = allocate(); if (!highpass_block) { release(input_block); release(lowpass_block); release(bandpass_block); if (control_block) release(control_block); return; } if (control_block) { AudioFilterStateVariable::update_variable(input_block->data, control_block->data, lowpass_block->data, bandpass_block->data, highpass_block->data); release(control_block); } else { AudioFilterStateVariable::update_fixed(input_block->data, lowpass_block->data, bandpass_block->data, highpass_block->data); } release(input_block); transmit(lowpass_block, 0); release(lowpass_block); transmit(bandpass_block, 1); release(bandpass_block); transmit(highpass_block, 2); release(highpass_block); return; } else { transmit(input_block, 0); transmit(input_block, 1); transmit(input_block, 2); release(input_block); } }
void AudioAnalyzeFFT1024::update(void) { audio_block_t *block; block = receiveReadOnly(); if (!block) return; switch (state) { case 0: blocklist[0] = block; state = 1; break; case 1: blocklist[1] = block; state = 2; break; case 2: blocklist[2] = block; state = 3; break; case 3: blocklist[3] = block; state = 4; break; case 4: blocklist[4] = block; state = 5; break; case 5: blocklist[5] = block; state = 6; break; case 6: blocklist[6] = block; state = 7; break; case 7: blocklist[7] = block; // TODO: perhaps distribute the work over multiple update() ?? // github pull requsts welcome...... copy_to_fft_buffer(buffer+0x000, blocklist[0]->data); copy_to_fft_buffer(buffer+0x100, blocklist[1]->data); copy_to_fft_buffer(buffer+0x200, blocklist[2]->data); copy_to_fft_buffer(buffer+0x300, blocklist[3]->data); copy_to_fft_buffer(buffer+0x400, blocklist[4]->data); copy_to_fft_buffer(buffer+0x500, blocklist[5]->data); copy_to_fft_buffer(buffer+0x600, blocklist[6]->data); copy_to_fft_buffer(buffer+0x700, blocklist[7]->data); if (window) apply_window_to_fft_buffer(buffer, window); arm_cfft_radix4_q15(&fft_inst, buffer); // TODO: support averaging multiple copies for (int i=0; i < 512; i++) { uint32_t tmp = *((uint32_t *)buffer + i); // real & imag uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); output[i] = sqrt_uint32_approx(magsq); } outputflag = true; release(blocklist[0]); release(blocklist[1]); release(blocklist[2]); release(blocklist[3]); blocklist[0] = blocklist[4]; blocklist[1] = blocklist[5]; blocklist[2] = blocklist[6]; blocklist[3] = blocklist[7]; state = 4; break; } }