Teensy3.1 Audio Synth Waveforms and WAV files

Status
Not open for further replies.

Teenfor3

Well-known member
I am trying out synth waveforms using teensy3.1 and the audio adaptor.
I can get it to work fine using the samples downloaded from your links.

I also tried converting some sound samples for arbitrary sounds from wav files and find alot of aliasing. I know it is mentioned on the forum....

I thought if I used wavs sampled at 44.1 that played at 44.1 on a PC , and teensy was sampling at 44.1 there would not be a problem.

What would be the difference in Audacity playing a 44.1 wave or teensy playing it.??...both at 44.1.

I understand teensy is playing it from a data array in memory and Audacity is playing direct from the file.

If I have a wav file of frequency 441 Hz say that gives me 100 samples for 1 period. To create the data array for teensy I need 256 samples (256 + 1 same start and end, an array of 257).

So I opened the wav file in Audacity and run the Effects Low pass filter corner freq. 2000 Hz and 48 db/octave rolloff. I know I think the filtering should actually be done at the analogue stage of recording before it is digitized, but I only had a digital wav file to start with.
I then copied a section of the audio, to the clipboard, set the project rate to (256 x 44100 / 100) = 112896, then opened a new mono track and pasted in the audio data. That gave me 257 samples for 1 period of the waveform. I exported the data for 1 period using Audacity sample data export, opened it in a spreadsheet, multiplied the values by 65535, appended a comma after each one and copied this into a header file in the Arduino IDE. And all compiled and worked providing I keep the corner freq about 2000 Hz. It sounds not bad just a bit "muffled".

When I record the playback from teensy using Audacity I get 100 samples again for the waveform at that freq. 440 Hz. and the waveform doesn't look too bad.

This is the bit puzzling me.....I don't seem to be using all to values put in the 257 array..??....when I play the recorded freq of the sound..??

I did a rough test and recorded teensy output in Audacity, and viewed it at 44.1 sample rate in audacity.

Playing a 440 sound sample of 257 sample points for a 1 period in the teensy array gave me....

maxFREQ = 1200;
wave0.begin(0.3, wavefreq, WAVEFORM_ARBITRARY);
wave0.arbitraryWaveform(mysound[3], maxFREQ);

wave0.frequency(100); .......

etc...etc for 100, 171, 200, 257, 300, 440 freqs ..............

Freq...100 gave 440 samples for 1 period playback.
Freq...171 gave 257 samples for 1 period playback....this is full table..??
Freq...200 gave 220 samples for 1 period playback.
Freq...257 gave 172 samples for 1 period playback.
Freq...300 gave 148 samples for 1 period playback.
Freq...440 gave 100 samples for 1 period playback.

The teensy sounded frequency and measured frequency always was correct for each.

Maybe someone can through some light on this and what is the best way to convert an already recorded wav sound file to a data array.

Generally 44100 sound files are anti-alliased at 20 khz OR 22050 files are anti-aliased at 10 khz already.

Thanks for your help......
 
This is the bit puzzling me.....I don't seem to be using all to values put in the 257 array..??....when I play the recorded freq of the sound..??

i'm not sure i understand your problem right, but that's how it (DDS) works; for instance, for wave0.frequency(100), the phase accumulator will overflow a 100 times per second, in which case you'll step through the full 257 array, advancing by 0.58 samples at each clock tick (ie 44k1 in this case, or "440 samples for 1 period playback"). wave0.frequency(171) overflows 171 times, and here the phase increment happens to correspond to 1 sample/clock tick, hence "257 samples for 1 period playback"; at higher frequencies, the you increment faster, so that's why samples are being skipped (eg 440 Hz = 440 cycles per second = leaves 100 samples per cycle at 44k1).

as for editing/band-limiting/etc wavetables, doing it with audacity seems a bit tedious. that said, i don't think there's any good/active single cycle editors; though there's useful stuff, take a look at https://www.facebook.com/Audioterm
 
It looks as if what is happening is that Audacity is giving you exactly as many samples as are needed at 44.1kHz to give one cycle of the waveform. So as the frequency gets higher, the period gets shorter.

44,100 ÷ 171 = 257.894736842105263 which is what you found (257). A 171Hz sinewave at 44.1kHz sampling requires 257 samples to play back one complete cycle.

The issue is not the 44.1 sampling rate. The issue is that you are telling Audacity to do a particular thing, and it is doing it; but that thing does not result in what you want. Instead, it is making as many samples as it needs at that rate, and the number it needs varies with frequency and sampling rate.

How the arbitrary waveform works in the Audio library is that all the tables are a fixed size. The library then moves a phase pointer at the speed required for the requested frequency (440Hz or whatever) which, with rounding, points at one element in that table. The fractional part of the phase pointer is used to linearly interpolate between that entry and the next entry in the table. (This is why there are 257 entries not 256, so for all 256 positions there is aleways a "next" entry).

In effect it is making a new table for the requested gfrequency, at 44.1kHz, using piecewise linear interpolation from the original table.

Getting back to your original question: you have some WAV sample and you have isoolated a particular portion which is to be your custom waveform. First you need to be sure that it loops correctly (the sample at the end and the sample at the beginning need to be close enough together to not cause a sharp discontinuity. Then you need to downsample or upsample it to whatever frequency will give you exactly 256 samples. Then you need to copy those into the first 256 elements (array index 0 to 255) of your 257-element array, putting a copy of the first sample into the 257th position (array index 256) as well.

This would be easier to explain with diagrams or a whiteboard but hopefully that helps.
 
I exported the data for 1 period using Audacity sample data export, opened it in a spreadsheet, multiplied the values by 65535, appended a comma after each one and copied this into a header file in the Arduino IDE. And all compiled and worked providing I keep the corner freq about 2000 Hz. It sounds not bad just a bit "muffled".

I'd like to point out the "forum rule".

While this description is nice, we can't see what you *actually* did to convert the data.

My blind guess is your might have gotten numbers from Audacity in the -1.0 to +1.0 range, which would become 17 bit integers when multiplied by 65535, and then would lose their most significant bit if you pack them into 16 bit integers (which we also can't see, since you didn't post the code or the spreadsheet).

Then again, lots of other things might have gone wrong. We have the "forum rule" for everyone's benefit, since it allows everyone to see what actually happened, which lets us give you a much more informed answer.
 
Thanks for your help.....I wasn't too sure that this was the way it is meant to operate.
My reason for posting was to try and find a method for converting an arbitrary WAV file to a data array for teensy.
I had already downloaded Audioterm but dont know how to use it, cannot find any manuals on the web. I don't have facebook.??
So that is why I had used Audacity.....

What I did in Audacity to give you more details as requested was..........
Open WAV in Audacity to get sample rate and samples for 1 period.....found 44100 and 100 samples... need 257 samples for 1 period.
I also ran the menu Effects, Low Pass Filter plugin and set it with low corner frequency (2000 Hz and 48 db/octave rolloff) to try and reduce high harmonics.
Then I calculated the upscaling as (257 x 44100 / 100) = 112896
Copied a few periods to clipboard.
Opened a new mono track with project sample rate set at 112896 and pasted in the audio into the track....this gve me 257 samples for 1 period.
Then selected 1 period of this track = 257 samples.....then from menu Analyse "Sample data export", set for 257 samples,
Linear measurement, Sample list (txt), and give it a name.
This creates a txt file with a single column list. Open this file in notepad, select and copy the single column of text numbers only and paste this as a single column in Excel spreadsheet. ( cells A1 to A257). A1 and A257 were numbere very near zero so I made both zero.
In Excel column cell B1 enter the formulae =INT(A1*65535). this calculates cell A1 multiplied by 65535 as an integer. Copy this down column B.
In Excel column cell C1 enter the formulae =(B1&",") and copy this down column C. this appends a comma after the number in the cell as required between each entry in the array in Arduino IDE.
I then selected the values in excel column C and copied to clipboard.
I opened my sketch in Arduino and pasted this as text into the header file for the sounds. I set it as another sound table with the same data type etc as the other sound tables in the file and a new name and no comma after 257th entry. Example of the text is given below attached file sound05.h.

I then compiled the sketch, downloaded it to teensy and all worked. Then recorded the sound and wavform played back from teensy...it is not exactly as looks like if plot a graph of the table in Excel but sounds not too bad.
 

Attachments

  • sound05.h
    2.1 KB · Views: 146
I had already downloaded Audioterm but dont know how to use it, cannot find any manuals on the web. I don't have facebook.??
So that is why I had used Audacity.....

there's no real manual, i think. there's a video IIRC that shows you how to use the single cycle feature; I haven't been using it a lot myself though, because it's not available for osx or linux and using it with wine didn't work so great. at the end of the day, it's not particularly convenient when you need a specific output format.

coming up with a processing sketch or something to process the wav file might be less tedious than doing it with audicity/. (i attach a semi-working thing which might at least get you started (the output isn't formatted properly, among others; and as it stands, it puts out arrays of 7 x 256 length); i came up with it before the days of the audio library, to convert some AKWF wavs to arrays, so that's why the array length is 256. it's meant to generate a series of bandlimited waveforms (which it kind of even does, but it's not particularly 'correct'), but you can ignore that. in the picture, you can see the effect. the topmost waveform is the input wav, the others the processed output).

Screen Shot 2014-12-25 at 10.25.48.jpg


well, someone with proper software development skills could whip up a useable/proper single cycle editor / import utility in no time, i guess.
 

Attachments

  • octFFT.pde
    2.7 KB · Views: 140
Yup, looks like sound.h has a problem.

The array type is int16_t

Code:
const int16_t sound1_05[257] = {
0,
7393,
12156,
15509,
18704,
21687,
24402,
26800,
28835,
30465,
31658,
32386,
32629,
32376,
31621,
30369,
28630,
26422,
23768,
20698,
17248,
13455,
9364,
5022,
478,
-4216,
-9006,
-13835,
-18647,
-23385,
-27988,
-32398,
-36557,
-40405,
-43889,
-46954,
-49548,
-51628,
-53151,
-54087,
-54408,

But you've got numbers outside 16 bit integer range. -32768 is the most negative number. Using -54408 won't work!

Likewise, later in the file the numbers go has high as 42728, but 32767 is the highest positive integer that fits in 16 bits.
 
Thanks Paul.........the difference you know these things....I have to look them up in google to find out........
I actually googled what was range of int16_t but must have read uint16_t.....but got iwrong anyway....
Yes I have changed the data table and tried it on teensy and it works fine now.....magic....no "raggedity" waves or rough sounds in the playback waveform.

I think I will stick to my audacity way of converting WAVs....because I understand it.

What I did to correct it with your suggestions.......I now multiply the data text file from Audacity by 32000 instead of 65535. and thats it.


I can save the formulaes etc in Excel so all I have to do to convert a new WAV is open it in Audacity export the Text data and paste the list in first column of Excel and then copy column C to my sound header file.
Thanks all for your help.....
 
Are you mainly trying to get your waveforms from previously recorded .wav files? Or do you want to synthesize and sculpt some synthetic waveforms from scratch?

Puredata could be a great fully cross platform option for this, i could set you up a patch if you explain a bit more about if you are just cutting various bits from wave files or? I'll post something really simple in a moment, for now here is a link to the puredata download page:

http://puredata.info/downloads
 
Thank for your reply. Currently I just want to be able to create a data array to play in Teensy Waveform synth. The previous posts sorted me out and all is working OK now.......I was multiplying by too big a number for int16_t array.

I copied the following from the GUI Audio Design tool........
"Array must be an array of 256 samples. Currently, the data is used without any filtering, which can cause aliasing with frequencies above 172 Hz. For higher frequency output, you must bandwidth limit your waveform data. Someday, "maxFreq" will be used to do this automatically."

A question....What does it mean "can cause aliasing with freq above 172 Hz".....I can convert audio WAVs files where spectrum frequencies go up to 10 or 15 Khz and it seems to work OK..?? I also can playback the waveform at any frequency 1000 Hz upward...I didn't check what limit.

Also what does "maxFreq" do now.?

Thanks again......
 
Any frequencies above the nyquist (1/2 the sample rate if I'm not mistaken) begin to fold back and cause aliasing (unintended harmonic distortion in the high frequencies)
http://en.m.wikipedia.org/wiki/Nyquist_frequency

In order to combat this we use a lowpass filter to limit the high frequencies in the original wavetable, if you remove the highest frequencies from the wavetable, it will make it to a higher oscillation frequency before it starts aliasing.

At least I think that's what it is :p.
 
A question....What does it mean "can cause aliasing with freq above 172 Hz".....I can convert audio WAVs files where spectrum frequencies go up to 10 or 15 Khz and it seems to work OK..?? I also can playback the waveform at any frequency 1000 Hz upward...I didn't check what limit.

To achieve good aliasing-free playback over a wide frequency range, you're going to need several different copies the waveform, with different low-pass filters applied.

When you play the waveform at higher frequency, you must use a copy with more stuff filtered away. Failure to do so will sound horrible. I'm not going to go into the Nyquist aliasing details in this message... I'm merely going to state this fact and ask you to believe me. If you don't believe this and want to argue this point, please be clear in your reply whether you want help doing this (probably using Audacity), or you're trying to argue for some (impossible) way to get around it.

Obviously you'll want to use copies of your waveform with less of the high frequency content removed by prefiltering the waveform when you play at lower frequencies. That's why you'll want several copies. When you play at lower frequencies, more detail in the waveform lets it sound better. But when you play at higher frequencies, you have to remove that stuff. The library doesn't do this for you (as documented), so you have to do it when creating those arrays.
 
I am curious, would it be difficult to add a low pass averaging filter inside the wave table playback that adaptively filters the wave table relative to its current playback frequency? I'd be into trying to add that feature. I'll see if I can figure it out.. Also maybe a 4point cubic interpolation for smoothing slow rate stuff?

Man I love this library! Good work :)
 
Yes, it'd be possible. I'd probably recycle/copy/repurpose the biquad or fir filter code.

You'd probably want to keep a copy of the unfiltered original. Or perhaps you'd just allocate several buffers, maybe one per octave, and pre-filter them all, which would cost more up-front, but it'd avoid running the filters while playing.

Eventually, when I work on proper wavetable synthesis support, a huge part of that work is going to be on a web-based GUI for composing the data. Implementing the support inside the library is not so difficult, but turning it into an easy-to-use system requires a lot more effort!
 
Hell yeah! It made me really happy to hear that! I really am driven to help in any way I can on this library and the gui. I am allllll about modular based configuration and programming. I feel like it could be cool to even add some more configuration elements into the graphic editor, let people connect controls like encoders and pots etc..

Also have you ever checked out spinCAD and the fv-1 DSP chip? I think you would dig it. In my dreams the teensy audio config and spinCAD would marry and make an incredible powerful audio manipulation software / hardware toolset that is easy and fun to explore.
 
Or perhaps you'd just allocate several buffers, maybe one per octave, and pre-filter them all, which would cost more up-front, but it'd avoid running the filters while playing.

i think that would be the more common approach. the processing sketch i posted above is meant to do this (it's not doing it properly), though typically i guess one would be using successively smaller arrays per octave [512, 256, 128, 64, 32, etc] and (in the DDS code) interpolate between the octaves, so the additional memory+cpu requirements are fairly benign compared to the way it's presently done.

but yeah, there's currently no tool out there doing this.
 
Good idea, eliminating the samples that aren't going to be written to the dac anyway and only serve to add to potential aliasing.
 
Status
Not open for further replies.
Back
Top