|
|
Marc Clifton wrote: Ah, the joys of outsourcing with no code reviews. Combined, perhaps, with last minute changes, or unthinking copy/cut and paste, failing to step-through debug or sheer incompetence, or all of the above.
It is smdh funny, though.
Cheers,
Mike Fidler
"I intend to live forever - so far, so good." Steven Wright
"I almost had a psychic girlfriend but she left me before we met." Also Steven Wright
"I'm addicted to placebos. I could quit, but it wouldn't matter." Steven Wright yet again.
|
|
|
|
|
Better said - better done[^]
Ravings en masse^ |
---|
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein | "If you are searching for perfection in others, then you seek disappointment. If you are seek perfection in yourself, then you will find failure." - Balboos HaGadol Mar 2010 |
|
|
|
|
|
That is one sick puppy.
The person should be found, bound and brought out for public humiliation immediately.
We had something like the following in legacy code:
for (x = 0; x <= 20;x++){
unknownVariable = x;
}
unknownVariable = 55;
That brings up so many questions. Was the dev trying to slow something down?
What is unknownVariable? Why did dev set it to the specific value of 55?
arghgghgghg!!!!
|
|
|
|
|
Hey now, that could actually be a valid check!
public class Stringy
{
private string Value { get; set; }
public Stringy(string value)
{
Value = value;
}
public static implicit operator string(Stringy s)
{
string value = s.Value;
if (s.Value == "4") s.Value = "5";
return value;
}
}
Which lets you write code like this:
var str = new Stringy("4");
if (str == "4" && str == "5")
Console.WriteLine("LOL");
Which will, of course, print LOL to the console.
Though I imagine you'd only do something like this if you really, really hate your co-workers.
modified 25-Oct-18 11:17am.
|
|
|
|
|
|
Aren't you a consultant / contractor? And an experienced one at that?
Charlie Gilley
<italic>Stuck in a dysfunctional matrix from which I must escape...
"Where liberty dwells, there is my country." B. Franklin, 1783
“They who can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety.” BF, 1759
|
|
|
|
|
|
It's a long convoluted story about how I finally wound up on the following code (below).
It all started with a request from a friend:
naive friend "Can't you make a device for me that analyzes tones (frequencies) and turns them into MIDI and outputs them to my computer so I can play the guitar and have it turned into MIDI? Should be easy right?"
Me: Everything should be easy.
Well, there was a official arduino example using a MKR 1000 that has an incorrect schematic[^]*. And from there, I was down the rabbit-hole.
Okay, so now I was just trying to create a quick sound generator that I can use to input into the Analog 0 pin (A0) of my MKR Zero so I can test how the code works. I have a Grove Seeed Sound Sensor laying around so I find some sample code.
However, there is no explanation of this odd piece of code and I have to look at it closely.
Yes, it's a simple bitshift, but I had to think about what it does.
Do you see what it does?**
const int pinAdc = A0;
void setup()
{
Serial.begin(115200);
}
void loop()
{
long sum = 0;
for(int i=0; i<32; i++)
{
sum += analogRead(pinAdc);
}
sum >>= 5;
Serial.println(sum);
delay(10);
}
So it looks like it takes 32 samples each time through the loop and then it does that bit shift.
Interesting.
The code is from Grove - Sound Sensor[^]
*Bonus Material
The error in the schematic that is not in the breadboard example is that the schematic uses Amp2 OUT to go into the A0 pin on the Arduino even though there is no input on Amp2. The output should be from Amp1 to A0 on the schematic. See schematic at : https://www.arduino.cc/en/uploads/Tutorial/ArduinoMKR1000AudioInput_schem.png[^]
** spoiler Yep, it just clips off the 5 least significant bits, right? Well, it seems weird to do something like that without even mentioning why. This would've been a nice place in the code (or at the article) for a comment. But no.
modified 16-Oct-18 8:25am.
|
|
|
|
|
This is a much more difficult project than it might seem. There are several commercial, OTS products that do this and have been around for several years but very few of them do it really well. The basic operation of determining the fundamental frequency of an input signal is fairly easy but it gets complex quickly when more than one note is played, with a complex waveform, and when the pitch is varied away from that of a standard musical note.
|
|
|
|
|
A very good summary of the difficulties and I really appreciate you chiming in on this.
I was attempting to explain to him why it would be difficult but since I don't understand it all it was difficult for me to explain all of the challenges. I know it is processor intensive though as I was thinking about how many samples do you take per time instance to be sure that the note you are transcribing to is the correct note and not just some noise that is coming thru.
I think that the simplicity of finding the Arduino sample convinced him that it must be simple. Wire up the parts, upload the code and go. If only.
|
|
|
|
|
Yes, exactly : if only...
|
|
|
|
|
The bit shifting is a tool from older times, when bit shifting was faster than a division by 32. The value you get is the arithmetic mean, but not the moving average.
|
|
|
|
|
Thanks for the additional explanation. Great stuff.
Yeah, I remember reading a Stephen Holzner book to learn C++ a long time ago in a galaxy far away and learning about bitshifting and all the fun little bit stuff.
You don't see it much but then when you go back to Arduino code you do and it's kind of fun.
|
|
|
|
|
msk4711 wrote: arithmetic mean That is, the variable sum has an appropriate name.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
It seems to me it's filtering out noise. 32 samples = 2^5, so the code might be easier understood if it read like:
long sum = 0;
int noisybits = 5;
for(int i=0; i<2^noisybits; i++)
{
sum += analogRead(pinAdc);
}
sum >>= noisybits;
raddevus wrote: the value of the sum variable will always be 0 or perfectly divisible by 32.
The value of the sum variable will not be perfectly divisible by 32, either before or after the shift. Now, if you did this:
sum = (sum >> 5) << 5;
then yes.
Latest Article - A Concise Overview of Threads
Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny
Artificial intelligence is the only remedy for natural stupidity. - CDP1802
|
|
|
|
|
Marc Clifton wrote: The value of the sum variable will not be perfectly divisible by 32
Oh, I think you're right. I was messing around with it in Linqpad to see the values and I think I slightly altered the original.
|
|
|
|
|
You probably need to look at Fast Fourier transform to convert the input waveform into discrete levels for each 'note' currently being played.
|
|
|
|
|
THanks for the link. I'll read up on it. I've heard of FFT before but never understood it because I didn't have a particular application of it. Maybe I'll get closer to understanding this time.
|
|
|
|
|
FFT is a good technique to use but I am not sure how well it will work in this situation - using a Pi. You can probably get by with testing for fundamentals up to about 4K. The reasoning is the low E on a 4-string bass is ~40Hz, 80 for a guitar. Five octaves above that would be 2560Hz so, according to Mr. Nyquist, you need to sample at 5.1KHz minimum. Probably 6KHz or 8KHz would be better. If you do FFTs on 256 samples you would need to do 32 of them per second to keep up and that would mean bursts of data would come every 30mS. You will need to use the fastest Pi available to keep up with that. I might be thinking about this wrongly though.
There are a few free programs you can play around with to get an understanding of this. Here's one : Audio Spectrum Analyser[^] and here is another : Sound Frequency Analyzer[^]. I think there is source code for them available too.
|
|
|
|
|
That's really great info in your post. I'm going to read it again even more slowly.
The interesting thing is that this is not even running on an RPi. This is a MKR Zero which has a SAMD21 Cortex-M0+ 32bit low power ARM MCU (compared to RPi 3+ Quadcore ARM Cortex-A53, 64Bit)
|
|
|
|
|
The main things in there are the frequency range of interest which is summarized well on this page: Table of Musical Notes and Their Frequencies and Wavelengths[^] and the Nyquist sampling theorem which basically means you have to sample at a minimum of twice the frequency of interest. This is why the sample rate of CD audio is 44.1KHz in order to reproduce frequencies of up to 20KHz. That sample rate caused some other major issues but it was the best technology could do in the early 1980s.
|
|
|
|
|
Exactly.
The code shown will give a readout of the DC (static) input voltage, it will not tell you anything about the tone signal.
To sample the input at a decent frequency, forget about using analogRead(). It can't sample faster than about 9000 Hz. You will need to set the ADC in free-running mode and after the necessary code changes to support that, you then need to see how much RAM you have availble for sampling, and how fine-grained an FFT you can do on that given the limited processing power you have.
Let's assume that you can get a fine-grained FFT. If you play a single string on the guitar it will be fairly simple to determine the base frequency and convert that to MIDI. Now strike a chord. Now you have six different strings that all produce base frequencies and overtones and you need to deconvolute them.
To produce correct MIDI you have to do all this in real-time. The delay from string-played to MIDI-produced has to be below 10 ms if you want to use the MIDI signal to trigger a guitar synth or another instrument without noticeable delay. If you "only" want to record and can live with a fixed larger latency, fine, but you still have to be able to process all input in real-time.
One of my friends has a home studio and he uses a piece of software that can analyze all kinds of instruments and e.g. split a guitar voice into the respective strings and display what is played as finger settings. Really awesome, but of course, it costs .
You can buy dedicated hardware to plug into your guitar that outputs MIDI for around $100. Just saying ...
|
|
|
|
|
So have you realized yet that musical notes on the Western scale don't really correspond to any absolute frequencies?
They're relatively tuned, to each other on the scale by ratio, not to a fixed frequency. Even if you assume that A=440, what temperament are you going to use? Just intonation won't work out right on a fretted instrument, you know.
It's a complicated problem, aside from the programming. There are commercial products that do this, but they all involve compromises. Also, latency is a big problem with these things, so there's that too.
|
|
|
|
|
Right, I know there basically is a solid way to say XXX frequency is a particular note. I know that A=440Hz but then where do you go from there?
And yes, you are also correct about the latency issue because you have to do so much sampling and there is noise to deal with and all the rest. It is an interesting experiment to try and to think about though.
|
|
|
|