예제 #1
1
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);
}
예제 #2
0
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);
    }
}
예제 #3
0
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);
}
예제 #4
0
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);
}
예제 #5
0
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);
}
예제 #6
0
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);
	}
}
예제 #7
0
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);
		}
	}
}
예제 #8
0
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);
}
예제 #9
0
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;
}
예제 #10
0
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);
		}
	}
}
예제 #11
0
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);
}
예제 #12
0
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);
		}
	}
}
예제 #13
0
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
}
예제 #14
0
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);
}
예제 #15
0
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);
	}
}
예제 #16
0
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;
	}
}