Resampling and Mixing Input and Output #556
-
I have tried the examples in resampling and mixing Inputs and Outputs from the Wiki documentation. The only examples I can fing is resampling only of single waves or mixing of waves that are not resampled. I want to be able to have 2 or more arrays generate 2 or more sounds each one resampled so that I can vary the frequency and also the amplitude or volume. I assume then I need them mixed so as to play out via the DAC pin25 and pin26 of the ESP32. I am able to do the "Input Mixer" with each wave resampled and it plays quite well, but I find there is a slight click of about 1 Hz at some frequencies, I think when multiplier is a very odd number eg 1.3333, or 1.555, or 1.7777 for example, other multipliers eg. 1.5, 2.0, 3.0 etc are OK and good sound. Below is example of what I have been trying.... xxxxxxxxxxxxxxxxxxx This gives good sound but some frequencies eg. uint16_t sample_rate=44100; GeneratorFromArray<int16_t> waveR1(arrayR1,0,false); AnalogAudioStream out; // out is DAC pin 25 and 26 analog InputMixer<int16_t> mixer; StreamCopy copier1(out, mixer); // copies mixer sound to out //OutputMixer<int16_t> mixer(out, 2); // Arduino Setup mixer.add(resample1); // add resampled sounds as input to mixer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx This is resampling of Output Example...... gives a better clear sound. GeneratorFromArray<int16_t> waveR1(arrayR1,0,false); ResampleStream<int16_t> resample1(out); // this gives a clear sound playing copier1 only //xxxxxxOutputMixer<int16_t> mixer(out,2); StreamCopy copier1(resample1, sndR1); // copies sound to resample and out //OutputMixer<int16_t> mixer(out,2); //StreamCopy copier1(mixer, resample1); // Arduino Setup |
Beta Was this translation helpful? Give feedback.
Replies: 19 comments 87 replies
-
I have looked at all combinations of resampling and mixing I can find available and still cannot find a solution to the clicking background sounds when the "real resampled sounds" are playing. Using an OutputMixer to output direct to "out" and Resample the GeneratedSoundStream of each array then copy these into mixer has the clicks at some frequencies. I can play 1 sound or both sounds still get clicks. Using an InputMixer with " StreamCopy copier1(out, mixer); " to combine the 2 resampled streams and copier the mixed streams in loop means I can play 2sounds but still get clicks. The best option for sound quality is using Resampled direct "out" but I need to mix my 2 sound somewhere....?? xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx uint16_t sample_rate=44100; GeneratorFromArray<int16_t> waveR1(arrayR1,0,false); AnalogAudioStream out; //ResampleStream<int16_t> resample1(sndR1); // not send this to avoid interference ResampleStream<int16_t> resample2(sndH1); //resample sndH1 only send this to test OutputMixer<int16_t> mixer(out, 1); // define outputmixer with direct output out. had to set channels to 1 here, if set to 2 gettingcombination of 2 waveforms mixed up. StreamCopy copier1(mixer, resample2); // copier1 copies resample2 sound into mixer .... this works but has a click sound at some frequencies of resampling //StreamCopy buffer_size(128); //copier.buffer_size = 128); ..... size of buffer seems to not matter here xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx This below is resample to "out" Only. no mixer ... good sound all frequencies xxxxxxxx uint16_t sample_rate=44100; GeneratorFromArray<int16_t> waveR1(arrayR1,0,false); AnalogAudioStream out; ResampleStream<int16_t> resample1(out); // does this mean resample direct to out ...?? //AnalogAudioStream out; StreamCopy buffer_size(128); //copier.buffer_size = 128); // This works perfect (NO Clicks) when copier1 only or copier2 only sent out in loop eg. ...
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx uint16_t sample_rate=44100; GeneratorFromArray<int16_t> waveR1(arrayR1,0,false); AnalogAudioStream out; InputMixer<int16_t> mixer; StreamCopy copier1(out, mixer); StreamCopy buffer_size(128); //copier.buffer_size = 128); void setup(void) { mixer.add(resample1, 0.5); // 0.5 amplitude volume settings R1 // ................xxxx etc etc void loop() { //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
Beta Was this translation helpful? Give feedback.
-
I think you would need to find out the root cause of your clicking sounds. Did you try to send the output to the Serial Printer to figure out where this is coming from ? |
Beta Was this translation helpful? Give feedback.
-
I tried to reproduce your issue with the 1.0/1.2 combination in Jupyterlab : int channels = 1;
int sample_rate = 44100;
int frequency = 800;
// data
SineWaveGenerator<int16_t> sineWave1(32000);
SineWaveGenerator<int16_t> sineWave2(32000);
GeneratedSoundStream<int16_t> sound1(sineWave1);
GeneratedSoundStream<int16_t> sound2(sineWave2);
ResampleStream<int16_t> resample1(sound1);
ResampleStream<int16_t> resample2(sound2);
InputMixer<int16_t> mixer;
// setup mixer
mixer.add(resample1);
mixer.add(resample2);
// begin objects
sineWave1.begin(channels, sample_rate, frequency);
sineWave2.begin(channels, sample_rate, frequency);
resample1.begin(1.0);
resample1.begin(1.2);
mixer.begin(sound1.audioInfo()); This gives the following result / and input; The major difference seems to be that you load the data from an array and I use a continuous generator. Are you sure that you provide 1 full/complete waves from the beginning to the end for both inputs ? |
Beta Was this translation helpful? Give feedback.
-
What is the difference between arsineC256 and arsineD256 ? |
Beta Was this translation helpful? Give feedback.
-
I thought this to be quite obvious: if you provide mono data the number of channels is 1 and if you provide stereo the channels is 2. See https://github.com/pschatzmann/arduino-audio-tools/wiki/Introduction You might get away with this (w/o samples being lost) but with the impact that the frequency is doubled, but only if number of samples is a multiple of the number of channels. ps. The mixer is mixing all channels from all input sources. Therefore if you provide a mono input you get the same signal on both I2S output channels. |
Beta Was this translation helpful? Give feedback.
-
I added a new InputMerge class which (does not mix but) interleaves the samples from the defined input streams. With this you can create a stereo output (channels=2) from 2 mono inputs (channels=1). The API is the same like the InputMixer. Please note, that I did not have the time to test the functionality yet.... |
Beta Was this translation helpful? Give feedback.
-
It would really help to draw some nice pictures to explain how the mixing is working. Here is a simple expanation:
When 1 channel is sent to I2S, I automatically convert it to stereo duplicating the samples (because I2S needs 2 channels). This is a functionality of the I2SStream. 2 Channels (= Stereo)
I am not sure that the impact of different frequency combinations is on the (perceived) amplitude and there is is no logic on my side to deal with this. |
Beta Was this translation helpful? Give feedback.
-
I suggest that you keep it with Maximilian for the time being. |
Beta Was this translation helpful? Give feedback.
-
It is rather a question of application design: You would never measure a frequency by doing counts in an Arduino loop and do other things there as well. On the output side you should not use delays or long running operations (like serial output) in the same output loop or if you do so make sure that you can still provide enough samples (as defined by the sample rate) Are these mesurement for audio generated by Maximilan ? |
Beta Was this translation helpful? Give feedback.
-
I guess that F64 just indicates a 64bit float (=8 byte float) which is the same like a regular double on most processors. |
Beta Was this translation helpful? Give feedback.
-
I tried your sketch on an AI Thinker AudioKit (which uses I2S) and to me it sounds pretty good. Maybe this is because you use the internal DAC which usually has plenty of noise and has only a resolution of 8 bits. I usually just use this for testing... |
Beta Was this translation helpful? Give feedback.
-
So far I was mainly concerned that recorded audio (e.g. as mp3) is sounding good and I never thought about measuring the exactness of any waves. So I will need to do some thinking how to deal with this. Normally you don't need to care abut interrupts this is nicely hidden by the API: You just need to make sure that the DMA buffer is not running empty by providing it enough data. If you need to cover some variability you would increase the buffer size, because the generation of samples is usually much faster then the consumption... |
Beta Was this translation helpful? Give feedback.
-
What do you mean with you renamed it: Arduino libraries are loaded independent on their name! |
Beta Was this translation helpful? Give feedback.
-
I already answered the first question quite some time ago: I added a new InputMerge class which (does not mix but) interleaves the samples from the defined input streams. With this you can create a stereo output (channels=2) from 2 mono inputs (channels=1). The API is the same like the InputMixer. If you wrap the output in a VolumeStream you can manage the amplitude. I am pretty sure that the max amplitude says fixed across all combinations. You could double check by wrapping the output in a VolumePrint class. I can't reproduce your issue with the range between 0.1 and 1.0. I was testing this with a sine input. I guess the issue with the wrong frequency is because you specify that I2S receives stereo data but you provide mono data. Just remove the comments for the I2S config If you feel that the InputMixer is missing functionality, feel free to create a subclass and add your needed functionality. You just might need to overwrite the size_t readBytes(uint8_t* data, size_t len) method... |
Beta Was this translation helpful? Give feedback.
-
My mixer is just providing the weighted average of multiple input channels and if you don't provide any weights it's just the simple mathematical average. Feel free to add your own implementation if this is not satisfying your need. Here is the recording with 1.0 / float stepArray[] = { 1.0, 1.125, 1.25, 1.333, 1.5, 1.667, 1.75, 2.0, 2.125 }; using the AudioKit: As you can see the max or min amplitudes are pretty consistent. I also added a startIndex parameter to the GeneratorFromArray because I read that it is recommended to use a different phase when mixing. If you plan to build some instruments you might also apply an ADSR effect which I think makes your issue only audible during a short period of time when both instruments are hitting together a common peak. |
Beta Was this translation helpful? Give feedback.
-
Here we go test.mp3.zip |
Beta Was this translation helpful? Give feedback.
-
It's called merge because it merges the (mono) input channel streams into 1 output channel stream with the following logic
I am not sure what you mean with "Is there an option to mix these outputs", but in my understanding it would really end up with the current implementation: 1 Channel (=Mono) Mixing
|
Beta Was this translation helpful? Give feedback.
-
Thanks for letting me know. I corrected the documentation. I suggest that you do a code review of the ResamplingStream and the InputMerge class. Maybe you discover something I was missing. ps. I just simplified the implementation of getValue() in the ResamplingStream in order to minimize the risk of errors. I do not hear any difference though... |
Beta Was this translation helpful? Give feedback.
-
The class PitchShiftStream currently extends AudioPrint, so only write is possible but no readBytes(). |
Beta Was this translation helpful? Give feedback.
I think you would need to find out the root cause of your clicking sounds. Did you try to send the output to the Serial Printer to figure out where this is coming from ?