Guide/tips for writing custom audio effects for Teensy Audio Library

Status
Not open for further replies.

d33k

New member
I'm interested in writing custom effects for Teensy 3.6 w/ audio shield. Googling has seemed to turn up nothing except for a few custom FXs people have created, but no insight into how they're created. I poked around in the effect_freeverb files in the library and am trying to wrap my head around what's going on. It looks like a lot of the reverb calculations are done in the effect_freeverb.cpp file. I'm guessing the reverb algorithm is modeled here through the various filters and parameters then sent to the DSP for calculation. Should I create a copy of the effect and change values to get an idea of what's going on? I'm assuming dspinst.h shouldn't be modified for creating custom effects. I suppose my question is can I create my own algorithms just by editing/creating effect source files? Is there more that needs to be done such as modifying or adding custom math to the dsp file?

If anyone has a guide or reference for creating effects specifically for Teensy I would appreciate it. I'm aware of the numerous guides of how to create FX algorithms in general, but am hoping for some more insight on how to do it specifically on the Teensy
 
No, you normally should avoid adding code to the dsp file.
I'd use a more simple effect for the beginning. Maybe the multiply. That's less code and easier to understand.
 
I came across that but was looking for something that covered more of what's going on behind the scenes. It focuses on object creation but not how the objects work unless I missed something
Everything is Open Source. Just open the .h and .cpp files for the objects of interest. It's all there to see.
 
It focuses on object creation but not how the objects work unless I missed something

The basic idea is update() gets called every 128 samples. You use the receive functions to get the data which has arrived at your inputs. Some effects just modify the data they receive. But if you need to get more audio memory buffers, you can use the allocate function (obviously this is needed for pure synth objects which don't have any inputs). Then you do whatever math you like to create the outputs, and use the transmit function to send them. You must release every block you received or allocated, which is normally done at the end up your update function.

If you need to store data between runs of update(), you can create whatever member variables you need. You can also create pointers to audio blocks, if you wish to hold on to data you haven't released. Just make sure you do eventually release every block you receive or allocate.

It's really that simple. You just get incoming audio samples, do math, and transmit the results.


I poked around in the effect_freeverb files in the library and am trying to wrap my head around what's going on.

You really should look first at the simpler objects for the sake of learning. The old saying about learning to walk before running applies.


I'm assuming dspinst.h shouldn't be modified for creating custom effects.

The many inline functions in dspinst.h are meant to give access to the special DSP extension instructions, within using asm stuff elsewhere in the library. Nearly all of those instructions already have inline functions in that file. Unless you find one of those instructions you really want to use (they're documented in ARM's architecture reference manual) which isn't already supported, adding stuff in that file doesn't make much sense.

Of course you can edit any file any way you like, regardless of whether it makes sense to the rest the world. But for the sake of getting help here and maybe someday contributing your code to others, the smart approach would be to only add code in dspinst.h if it really is for one of those special instructions.

But really, you probably should avoid those DSP instructions until you're very familiar with the library. Even I don't use them until I've made the code work with normal math (but I do choose the math functions and numerical ranges with the capability of those instructions in my mind). Everything those instructions do you can do with simple but (maybe) slower ordinary code. For example, there are instructions which multiply a 16 bit and 32 bit number for a 48 bit intermediate result, and give you the upper 32 bits. You can just write that sort of thing as "(int32_t)(((int64_t)a * (int64_t)b) >> 16)". The compiler will turn both a and b to 64 bit numbers, do the multiply as 64 bits, discard 16 bits, and then give you only 32 of the final result. That's slower, but much simpler to understand and troubleshoot.

Just remember, those DSP instructions are merely math operations. Almost all are just multiplies or multiply and add, in different combinations of bit widths and specific ways to access 16 bit data packed into the top & bottom halves of 32 bit registers. It's not something magical like a DSP core where you send it block of data and get huge results back. They're just specific and very basic math operations.

Those DSP instructions don't necessarily speed up most code. Using them to good effect is extremely difficult. You have to carefully plan your algorithm around the specific math operations they provide. You have to arrange for your data to be packed in the ways they can access. Most of the speed comes from optimizing memory bandwidth for loading and storing samples, not the math itself. Achieving high performance requires carefully planning how many registers the compiler will actually use, which (at least for me) means a *lot* of compiling the code and then looking at the disassembly to see what registers the compiler actually used. It's very difficult programming.

Do yourself a huge favor and just go with ordinary C math. Get that working first. Don't bother with the DSP extension instructions until you're an expert, and even then, only dive into that stuff if you really want to spend a lot of time and effort to make your already-working code run faster. It's very hard stuff.


I suppose my question is can I create my own algorithms just by editing/creating effect source files?

Yes. The library is meant to make this easy. You just write your update function to receive blocks of 128 samples, do whatever math you like, and transmit the results. The library takes care of moving the data between your object and all the others, so all you have to do is focus on what math you want to achieve your effect, and then it will integrate nicely with the rest of the library.
 
@martianredskies, you should probably start a new thread instead of hijacking this one. But yes, many of the Audio Library classes contain functions that are intended to be called from the main sketch.
 
Status
Not open for further replies.
Back
Top