瀏覽代碼

Add AudioEffectDelay

dds
PaulStoffregen 10 年之前
父節點
當前提交
68c410a501
共有 5 個檔案被更改,包括 303 行新增0 行删除
  1. +1
    -0
      Audio.h
  2. +147
    -0
      effect_delay.cpp
  3. +98
    -0
      effect_delay.h
  4. +56
    -0
      gui/list.html
  5. +1
    -0
      keywords.txt

+ 1
- 0
Audio.h 查看文件

@@ -57,6 +57,7 @@
#include "effect_flange.h"
#include "effect_envelope.h"
#include "effect_multiply.h"
#include "effect_delay.h"
#include "filter_biquad.h"
#include "filter_fir.h"
#include "input_adc.h"

+ 147
- 0
effect_delay.cpp 查看文件

@@ -0,0 +1,147 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* 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, development funding 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "effect_delay.h"

void AudioEffectDelay::update(void)
{
audio_block_t *output;
uint32_t head, tail, count, channel, index, prev, offset;
const int16_t *src, *end;
int16_t *dst;

// grab incoming data and put it into the queue
head = headindex;
tail = tailindex;
if (++head >= DELAY_QUEUE_SIZE) head = 0;
if (head == tail) {
release(queue[tail]);
if (++tail >= DELAY_QUEUE_SIZE) tail = 0;
}
queue[head] = receiveReadOnly();
headindex = head;

// testing only.... don't allow null pointers into the queue
// instead, fill the empty times with blocks of zeros
//if (queue[head] == NULL) {
// queue[head] = allocate();
// if (queue[head]) {
// dst = queue[head]->data;
// end = dst + AUDIO_BLOCK_SAMPLES;
// do {
// *dst++ = 0;
// } while (dst < end);
// } else {
// digitalWriteFast(2, HIGH);
// delayMicroseconds(5);
// digitalWriteFast(2, LOW);
// }
//}

// discard unneeded blocks from the queue
if (head >= tail) {
count = head - tail;
} else {
count = DELAY_QUEUE_SIZE + head - tail;
}
if (count > maxblocks) {
count -= maxblocks;
do {
release(queue[tail]);
queue[tail] = NULL;
if (++tail >= DELAY_QUEUE_SIZE) tail = 0;
} while (--count > 0);
}
tailindex = tail;

// transmit the delayed outputs using queue data
for (channel = 0; channel < 8; channel++) {
if (!(activemask & (1<<channel))) continue;
index = position[channel] / AUDIO_BLOCK_SAMPLES;
offset = position[channel] % AUDIO_BLOCK_SAMPLES;
if (head >= index) {
index = head - index;
} else {
index = DELAY_QUEUE_SIZE + head - index;
}
if (offset == 0) {
// delay falls on the block boundary
if (queue[index]) {
transmit(queue[index], channel);
}
} else {
// delay requires grabbing data from 2 blocks
output = allocate();
if (!output) continue;
dst = output->data;
if (index > 0) {
prev = index - 1;
} else {
prev = DELAY_QUEUE_SIZE-1;
}
if (queue[prev]) {
end = queue[prev]->data + AUDIO_BLOCK_SAMPLES;
src = end - offset;
while (src < end) {
*dst++ = *src++; // TODO: optimize
}
} else {
end = dst + offset;
while (dst < end) {
*dst++ = 0;
}
}
end = output->data + AUDIO_BLOCK_SAMPLES;
if (queue[index]) {
src = queue[index]->data;
while (dst < end) {
*dst++ = *src++; // TODO: optimize
}
} else {
while (dst < end) {
*dst++ = 0;
}
}
transmit(output, channel);
release(output);
}
}

}















+ 98
- 0
effect_delay.h 查看文件

@@ -0,0 +1,98 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* 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, development funding 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef effect_delay_h_
#define effect_delay_h_
#include "AudioStream.h"
#include "utility/dspinst.h"

#define DELAY_QUEUE_SIZE 117

class AudioEffectDelay : public AudioStream
{
public:
AudioEffectDelay() : AudioStream(1, inputQueueArray) {
activemask = 0;
headindex = 0;
tailindex = 0;
maxblocks = 0;
memset(queue, 0, sizeof(queue));
}
void delay(uint8_t channel, float milliseconds) {
if (channel >= 8) return;
if (milliseconds < 0.0) milliseconds = 0.0;
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0))+0.5;
uint32_t nmax = AUDIO_BLOCK_SAMPLES * (DELAY_QUEUE_SIZE-1);
if (n > nmax) n = nmax;
uint32_t blks = (n + (AUDIO_BLOCK_SAMPLES-1)) / AUDIO_BLOCK_SAMPLES + 1;
if (!(activemask & (1<<channel))) {
// enabling a previously disabled channel
position[channel] = n;
if (blks > maxblocks) maxblocks = blks;
activemask |= (1<<channel);
} else {
if (n > position[channel]) {
// new delay is greater than previous setting
if (blks > maxblocks) maxblocks = blks;
position[channel] = n;
} else {
// new delay is less than previous setting
position[channel] = n;
recompute_maxblocks();
}
}
}
void disable(uint8_t channel) {
if (channel >= 8) return;
// diable this channel
activemask &= ~(1<<channel);
// recompute maxblocks for remaining enabled channels
recompute_maxblocks();
}
virtual void update(void);
private:
void recompute_maxblocks(void) {
uint32_t max=0;
uint32_t channel = 0;
do {
if (activemask & (1<<channel)) {
uint32_t n = position[channel];
n = (n + (AUDIO_BLOCK_SAMPLES-1)) / AUDIO_BLOCK_SAMPLES + 1;
if (n > max) max = n;
}
} while(++channel < 8);
maxblocks = max;
}
uint8_t activemask; // which output channels are active
uint8_t headindex; // head index (incoming) data in quueu
uint8_t tailindex; // tail index (outgoing) data from queue
uint8_t maxblocks; // number of blocks needed in queue
uint16_t position[8]; // # of sample delay for each channel
audio_block_t *queue[DELAY_QUEUE_SIZE];
audio_block_t *inputQueueArray[1];
};

#endif

+ 56
- 0
gui/list.html 查看文件

@@ -1113,6 +1113,62 @@



<script type="text/javascript">
RED.nodes.registerType('AudioEffectDelay',{
shortName: "delay",
inputs:1,
outputs:8,
category: 'effect-function',
color:"#E6E0F8",
icon: "arrow-in.png"
});
</script>
<script type="text/x-red" data-help-name="AudioEffectDelay">
<h3>Summary</h3>
<p>Delay a signal. Up to 8 separate delay taps can be used.</p>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>In 0</td><td>Signal Input</td></tr>
<tr class=odd><td align=center>Out 0</td><td>Delay Tap #1</td></tr>
<tr class=odd><td align=center>Out 1</td><td>Delay Tap #2</td></tr>
<tr class=odd><td align=center>Out 2</td><td>Delay Tap #3</td></tr>
<tr class=odd><td align=center>Out 3</td><td>Delay Tap #4</td></tr>
<tr class=odd><td align=center>Out 4</td><td>Delay Tap #5</td></tr>
<tr class=odd><td align=center>Out 5</td><td>Delay Tap #6</td></tr>
<tr class=odd><td align=center>Out 6</td><td>Delay Tap #7</td></tr>
<tr class=odd><td align=center>Out 7</td><td>Delay Tap #8</td></tr>
</table>
<h3>Functions</h3>
<p class=func><span class=keyword>delay</span>(channel, milliseconds);</p>
<p class=desc>Set output channel (0 to 7) to delay the signals by
milliseconds. The maximum delay is approx 333 ms. The actual delay
is rounded to the nearest sample. Each channel can be configured for
any delay. There is no requirement to configure the "taps" in increasing
delay order.
</p>
<p class=func><span class=keyword>disable</span>(channel);</p>
<p class=desc>Disable a channel. The output of this channel becomes
silent. If this channel is the longest delay, memory usage is
automatically reduced to accomodate only the remaining channels used.
</p>
<h3>Notes</h3>
<p>Memory for the delayed signal is take from the memory pool allocated by
<a href="http://www.pjrc.com/teensy/td_libs_td_libs_AudioConnection.html" target="_blank">AudioMemory()</a>.
Each block allows about 3 milliseconds of delay, so AudioMemory
should be increased to allow for the longest delay tap.
</p>
</script>
<script type="text/x-red" data-template-name="AudioEffectDelay">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>




<script type="text/javascript">
RED.nodes.registerType('AudioFilterBiquad',{
shortName: "biquad",

+ 1
- 0
keywords.txt 查看文件

@@ -16,6 +16,7 @@ AudioEffectFade KEYWORD2
AudioEffectFlange KEYWORD2
AudioEffectEnvelope KEYWORD2
AudioEffectMultiply KEYWORD2
AudioEffectDelay KEYWORD2
AudioFilterBiquad KEYWORD2
AudioFilterFIR KEYWORD2
AudioInputAnalog KEYWORD2

Loading…
取消
儲存