Good day comrades!
Today we talk about the software part of our melody generator. To begin, I want to explain why do we need it, because the Arduino has a built-in PWM, through which a lot of people do stuff like that. Let's see:
- wav - the most simple and clear audio format having a sampling frequency of 44,100 Hz, each signal is coded 16 bits. Uncompressed format, thereby obtain 700 kbit / s;
- mp3 - very popular format, but with a lot of difficulties, bit rate is usually 320 kbit / s;
- yaf - "Yuri's Audio Format" has a bit rate of 0.8 kbit / s and is compatible only with the described sound card.
Given the relatively low productivity of Arduino everything falls into place: the work of classic audio formats requires a full download of MCU, whereas, yaf offloads MCU providing simultaneous playback of sound and movement of the robot.
Now, when it became clear why I made my own analog sound card, let's see how to work with it. Let's start with the simplest example - an electronic piano. By the way!
You know it? Yes Yes! It's my good old stand, known to readers of my series of articles about tricopter.
So, the idea is this: connecting some contacts of sound cards with GND we achieve playing back a note. Since the last time I‘ve improved the circuit and now I‘ve managed to avoid stray harmonics 3.3 kHz (if you're interested - I can write about this in the next article). To play sound I use Arduino Duemilanove, digital lines which are connected to the inputs of the sound card, it uses the following program:
char pins[] = {7,6,5,4,3,2,2,2}; // pin2 - reserved void set_bit(char b) // set a single bit to GND { if (b==-1) for (char i=0; i<8; i++) { pinMode(pins[i],OUTPUT); digitalWrite(pins[i],LOW); } else for (char i=0; i<8; i++) { if (i != b) pinMode(pins[i],INPUT); // high impedance else { pinMode(pins[i],OUTPUT); // grounded (0V) digitalWrite(pins[i],LOW); } } } void simple_loop(void) // piano { static char i = 0; delay(1000); set_bit(++i); if (i > 4) i = 0; } void setup(void) { for (char i=0; i<8; i++) // all pins = GND { pinMode(pins[i],OUTPUT); digitalWrite(pins[i],LOW); } } void loop(void) { simple_loop(); // piano //sound_loop(10); // music }
Let's see how it works:
But then the question arises, how to play music? It's very simple - if you change the tone in every 10ms, you get a monophonic melody. The melody is stored in the array sound_data and to play it, I use the procedure sound_loop:
void sound_loop(int del) // music { static int i = 0; delay(20); set_bit(sound_data[++i]-1); i++; if (i >= 992) // length of array { i = 0; } }
But where can we take the melody? My favorite Matlab will help us with it! The problem can be divided into 5 steps:
1. We need a melody. For the experiment, I chose the Imperial March from Star Wars. The file is called imperial2.wav
2. matlab has a function audioread(), Let’s use it to read the file:
close all clear all clc [x,fs] = audioread('imperial2.wav');
3. To select the notes we use the fast Fourier transform. An important point: we need only one harmonic, so let’s find the one whose amplitude is maximal:
% ------------------------------------------------ % fft codding % ------------------------------------------------ T = 0.01; t = length(x) / fs; Ts = t / T; x = x.'; ff = zeros(int32(Ts),1); d = length(x) / Ts; amp = zeros(round(Ts),1); for l = 1:Ts start = (l-1)*d + 1; stop = l*d; now = x(start:stop); L = length(now); NFFT = 2^nextpow2(L); % Next power of 2 from length of y Y = fft(now,NFFT)/L; f = 2*abs(Y(1:NFFT/2+1)); s = length(f); r = find(f == max(f),1); ff(l) = r; amp(l) = max(f); end amp = amp ./ max(amp); tm = max (fs/2*linspace(0,1,NFFT/2+1));
4. After the preceding paragraph, we have an array that stores the codes of notes (and even amplitude, but more about that another time), forming the composition, let's try to restore the melody:
% ------------------------------------------------ % uncodding % ------------------------------------------------ time = linspace(0,t,length(x)); for l = 1:Ts strt = int32 ( (l-1)*d + 1 ); stp = int32 ( l*d ); w = 2*pi* ff(l) * tm/s; time(strt:stp) = sin(w.*time(strt:stp));%.*amp(l); end sound(time/2.0,fs)
5. And now, instead of thousand words, I suggest you to see one short video about how the magic is created:
Well, today that is probably over. Now, briefly about my future plans: the fact is that I have not got yet the components to build the robot, but I hope that they can come to me next week. So the plan is as follows:
- If I get components this week - the next week there will be unboxing;
- If I do not get components – I will wait until June 1;
- if by June 1 will not have got them - I write the continuation of series of articles about the sound-card
In any case, do not switch – more interesting is ahead! See you soon!
Top Comments