Audio Library

Status
Not open for further replies.
I've done a WAV file streaming test, using a hobbytronics standard Transcend 4gb MicroSDHC. No speed rating on the packaging at all im afraid.

Summary
44Khz stereo = 3 voices
44khz mono = 5 voices
22khz stereo = 3 voices
22khz mono = 5 voices

WAVStreaming-test.jpg

note:
peak cpu readings were estimated based on 4 second updates detailing the current CPU usage and peak since last update.
Sometimes this would fluctuate very high, and i would ignore the higher ones which is bad form but at least it gives a feel for the capability.

I've left a 25% headroom for the rest of people code when detailing the maximums, so where we hit around 75% peak is where i capped it.

There were a lot more spare cpu cycles in mono mode, which werent represented by peak readings, however it would appear that 22khz mode doesn't actually save any cpu cycles really, even though all it has to do is double up the sample and do a 32bit transfer, I assume adding the two samples together for transmit is no quicker than pulling the stream over SPI once its rocking along.

Interesting, and 5 voices is not too shabby in mono for 16bit 44khz.

I'd like to do a u-law test next but I don't think the WAV reader supports u-law files at the moment.
 
That leaves the tracker-like resampling/repitching as discussed in recent messages in this thread. This has been done in the past on much more limited hardware, from the mid-80s onwards, at a time when a 12-bit DAC was an expensive component and 1MHz was a fast CPU speed. So there must be ways, as long as a certain amount of aliasing and other digital crunchiness can be passed off as "retro character".

It is also done a lot nowadays (sample-based instruments on platforms such as Kontakt) but those run on desktp/laptop CPUs with lots of CPU speed, RAM, and disk. They typically have multiple samples per note (to round-robin so it sounds less mechanical), sampled at multiple volumes (because a quiet note and a loud one have different spectral responses) and then extrapolate for note-ranges outside the ones sampled, or to do pitch bends. That translates to a very large amount of disk space and a fair CPU load (although the desktop ones are also doing things like 128-note polyphony) and would seem well outside Teensy capabilities, mainly because of the storage requirements.

I think you could get away with 3 or 4 sampled volumes and still get a good sound by adjusting the volumes through the velocity range, but i think all the aftertouch would need to be done programmatically rather than with samples, on a teensy, its jsut too many samples otherwise.

I'm currently struggling to see how i can fit everything in and i'm looking at one drumkit, a piano, a bass and strings, along with the program overhead.

I appreciate PAul's standpoint - if its worth doing - its worth doing well.
My approach (for my project) is a bit more MOD-like. You've got one sample. you can apply an envelope, effects and shift its frequency to a particular note when you play it if necessary.
But it will sound like a MOD player, you'll never make a decent synth out of that. Some would argue you'd never make a decent song out of it!!!
 
Seeing mention of SPI Flash, three of those arrived yesterday from an ebay vendor in Shenzen. I'm aware that the Eurorack module (Eurotrash) by mxxx uses them (but I don't yet have the PCB for that, nor the components). I'm aware the Audio Adapter has space for one, but no code to drive it. mxxx, would your code work for the Audio Adapter? (I'm aware the Flash SPI CS is on a different pin in your code). If so, would a pull requrest on the Audio Library to add SPI Flash support be something you would consider?

i put it there mostly for compatibility reasons. as it stands i haven't done much with it other than confirming it's working ok. so far, i've mostly/only focused on putting together a usable firmware for playing wav files, so that's all SD (also finishing up the terminal tedium stuff, not mentioning day job etc). but eventually i'll look into it; mostly i'm interested in lower latency for percussion samples. but whatever comes out of that will be entirely compatible, except for the chip select pin. so yes.

re wavetables/soundfont/resampling. i agree that's mostly three different things, likely of interest to different people.

- 'wavetable' / DDS type synthesis is mostly there, except the band-limiting and the various types of modulation. what's lacking (in general) is a decent editor that would generate such waveforms (ie, arrays of band-limited single cycles, or whatever format one might settle on). more generic than single cycles, as nantonos mentioned, would be nice, too. (tabread4~ is that, basically)

- soundfont: not my cup of tea, but i can imagine many people would be into it. it strikes me not particularly 'open'/'basic' (from the ugen perspective), more like a self contained application.

- phase vocoding. way above my head, especially considering the limited resources in this case. but i certainly wouldn't mind
 
Last edited:
I see a few pages back someone was developing a 24 db/oct audio lowpass filter. Has anyone implemented a Teensy 3.x-specific filter (lowpass or multimode) capable of self-oscillation at high resonance? I'm aware of this doc, which though for avr32 is probably tangential to ARM: http://www.atmel.com/Images/doc32120.pdf

That said, the "filter" library works well. Thanks, Paul, for writing it.
 
Has anyone managed to get the CC3000 WIFI chip to work at the same time while playing Audio from SD card?

I can not get both to work, it's either play sound, or stop and read WIFI.

... and is there a way to free up RX3 and TX3 on the teensy 3.1 while using audio board? If I can't get WIFI to work on SPI, then I need one more serial port, not sure how reliable soft serial would be...
 
Have you tried something similar to Paul's fix for using the ILI9341 display with the audio board?

To use the ILI9341 display with the Audio Board, connect the signals using the alternate pins shown above. In setup() before calling TFT.begin(), use SPI.setMOSI(7) and SPI.setSCK(14) to configure the SPI library for these alternate pins.

#define TFT_DC 20
#define TFT_CS 21
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

void setup() {
SPI.setMOSI(7);
SPI.setSCK(14);
tft.begin();
 
I may have missed this .. is there a way to take the Audio description in the source file and input it to the Audio System Design Tool, to see the design?

Thanks
David
 
Oh, I do indeed have so many big plans for the audio library and many other things. But everything takes time. This audio library was pretty much just a distant dream in April 2013 (around the time OctoWS2811 was wrapped up). Significant development started in August 2013, when I thought I'd manage to release something before the end of the year (the year 2013, that is). Turns out, the 1.0 release we're at now took a little over a year to develop!

Importing back into the GUI is definitely on my TO-DO list. So are a number of minor but annoying bugs in the GUI, and a lot of small but important usability improvements.

Long-term, I'm hoping to improve the library's constructors and add destructors, so it'll be possible to change the audio system dynamically. Today, it pretty much only works as a static system. Once it's dynamic, and with the small matter of a not-so-trivial browser plugin and a corresponding sketch on Teensy, I really want to make the board respond to the GUI as you draw, so you can hear the results immediately without having to go through Arduino. Obviously the GUI will have only limited ways to trigger notes, change settings, etc.

But today we're at a 1.0 release, where things are stable and work pretty well, but a lot of awesome stuff still remains to be added in future versions!
 
Last edited:
Any way to re-map MCLK to a different pin on Teensy 3.1?

I need to free up RX3 and TX3, already remapped TX2 and RX2.
 
In theory, it should be possible to make MCLK appear on pin 28, like this:

Code:
  CORE_PIN28_CONFIG = PORT_PCR_MUX(4);

Sweet, it worked! Thanks, I have learned how to use the manual to remap pins in chapter 10 multiplexing, thanks to your hints.

Code:
  CORE_PIN28_CONFIG = PORT_PCR_MUX(4); //remap MCLK from pin 11 to pin 28 (mux4) picks alternate ability #4, frees MOSI
  CORE_PIN32_CONFIG = PORT_PCR_MUX(4); //remap BCLK from pin 9 to pin 32 (mux4) picks alternate ability #4, frees RX2
  CORE_PIN7_CONFIG = PORT_PCR_MUX(3);//resets serial output RX3
  CORE_PIN8_CONFIG = PORT_PCR_MUX(3);//resets serial output TX3
  CORE_PIN9_CONFIG = PORT_PCR_MUX(3);//resets serial output RX2
  CORE_PIN10_CONFIG = PORT_PCR_MUX(3);//resets serial output TX2

SPI.setMOSI(11); //move from pin 7 to pin 11, frees RX3
  SPI.setSCK(14);  //move from pin 13 to pin 14 
  SD.begin(15); //set SD card cable pin select to pin 15 (#10 default)

Using the above pin declarations, and attaching the audio shield to the different pins listed above, you can free up Serial ports 2 and Serial ports 3 !! Now I can have all my serial ports open for 2 bluetooth devices and a wifi UART chip.
 
Last edited:
In my model, I've got playRAW > Envelope > BiQuad > FIR > Mixer.

In fact at the moment i have 16 of these little clusters - I need to be able to switch on and off the filters.

The FIR filter has a define PASSTHRU function - but the biQuad filter specifically states that by default it will not pass anything.

Without a passthru, it dictates the use of additional mixers which should not be necessary. Is this comment out of date, and if not, is there a particular reason why there is no pass through function? Or is it something that should just be added, as per FIR filter?

cheers

Jon
 
Since the net is currently static (connections are not hot rewirable), I agree it makes sense to have a togglable passthrough.
 
Nice! I was actually just starting to explore working with the wavetable. I actually got a halfway decent realtime pitchshifter, ill post it shortly.

are the val1 and val2 are adjacent locations in the buffer used with coefficient multiplication to give linear interpolation? Also what does the & 255 do in this case?

index = tone_phase >> 23;
val1 = *(arbdata + index);
val2 = *(arbdata + ((index + 1) & 255));
 
The expression:
Code:
(index + 1) & 255)

Implements a ring buffer of 256 elements. If index is not 255, then the & 255 does nothing. If it is 255, then the & 255 returns 0. So if you have an array of 256 elements, you don't have to check for the boundary condition. http://www.cprogramming.com/tutorial/bitwise_operators.html

You could also have written the expression as:
Code:
(index + 1) % 256)

It only works for the modulus (%) if the value is a power of 2 (2, 4, 8, 16, 32, 64, 128, 256, 512, etc.), you can use an and of the value-1 instead of the modulus. If index is an unsigned type, then the compiler will generate the and operation automatically. If it is a signed type, then the compiler needs to generate some fixup code to deal with the sign (note, in this case, I would imagine tone_phase and index should be unsigned types). Now, if the modulus was not a power of 2, the compiler has to generate the modulus operation (or division/multiplication if the machine does not have a direct modulus operation), which is much slower.

Typically when such bitwise operations are done, people use hex constants, which is clearer which bits are affected. Also, many people tend to use array indexing instead of *(pointer + offset):

Code:
index = tone_phase >> 23;
val1 = arbdata[index];
val2 = arbdata[(index + 1) & 0xff];
 
@nantonos

About the point of band limiting:

the same table is used for all notes so they are not bandlimited. This leads to aliasing at higher frequencies (and, for the table-based waveforms, a lack of higher harmonics at lower frequencies)

My teensy project happens to be a virtual analog synthesizer.
about wavetables: I use 14 band limited wavetables, with 1024 samples each (it fills the teensy quite fast!)
Each wavetables I covers half an octave, which gives around 7 octaves. This is almost, but not yet enough.
Still, the lowerest octaves can be relatively harmonically rich with 500 harmonics.
The higher notes use less aliases.
I can't hear the switching of wavetables, so that doesn't give any problems.

a possible optimization might be to use smaller wavetables for higher octaves with less harmonics.
I might implement it if I run out of memory.

Another optimization is that the pulse oscillator is made by subtracting 2 phase shifted saws.
shifting one of those saws changes the duty cycle of the pulse.

Perhaps my code can help, it can be found at my github


I also added hard sync, but haven't anti-aliased that part yet.
Is there an audible difference between hard and soft sync?
I couldn't find a good comparison.
 
I also added hard sync, but haven't anti-aliased that part yet.
Is there an audible difference between hard and soft sync?
I couldn't find a good comparison.

Yes, there is. Hard sync is a reset to zero phase, so can produce sharp discontinuities which may be above the bandwidth limit. Soft sync typically reverses the direction of movement of the phase pointer. They don't sound the same. In the analog domain, hard/reset sync is more common with sawcore oscillators and reversing/soft sync more common with tricore oscillators.
 
In flash_spi.cpp are only functions to read block-wise. It is not necessary to read blockwise.
Here's a little extension, I use it in my codec-lib:
Code:
void readserflash(uint8_t* buffer, const size_t position, const size_t bytes)
{//flash_spi.h has no such function.
	digitalWriteFast(SERFLASH_CS, LOW);
	SPI.transfer(0x0b);//CMD_READ_HIGH_SPEED
	SPI.transfer((position >> 16) & 0xff);
	SPI.transfer((position >> 8) & 0xff);
	SPI.transfer(position & 0xff);
	SPI.transfer(0);
	for(unsigned i = 0;i < bytes;i++) {
		*buffer++ = SPI.transfer(0);
	}
	digitalWriteFast(SERFLASH_CS, HIGH);
}

have Fun :)

Regards,
Frank
 
How were you able to use 1024 samples in the wave table? It says they are limited to 256? Or did I misunderstand the notes in the function on the audio config tool?
 
are you referring to #1071 ? that's some custom code; it shouldn't be too difficult though to change that in AudioSynthWaveform
 
Status
Not open for further replies.
Back
Top