Beruflich Dokumente
Kultur Dokumente
Antes que nada debo aclarar que no estamos hablando de msica con la calidad un CD, ni
stereo, ni nada por el estilo, es mas, dudo que tenga alguna calidad, lo digo para no crear
falsas expectativas.
En esta ocasin vamos a interpretar alguna meloda utilizando la tcnica que vimos en
"Generar sonido con PIC" y slo lo haremos a modo didctico, ya que es muy til para
comprender como el microcontrolador administra los tiempos y como se utilizan los puertos.
Este ejercicio bien podra reemplazar al ya mtico parpadeo de un LED con PIC16F84A ya que
es, en teora, el mismo principio pero con el agregado del control de la frecuencia.
Ahora bien, aqu viene lo mas interesante, investigando un poco me enter de como es esto
de las notas al encontrar este artculo: Frecuencias de las notas musicales , en el que se
explica la frmula para obtener la frecuencia de cada nota musical. Una de las frmulas, la
mas sencilla para llevar a cabo en un programa, es esta:
Con esta frmula pude sacar las frecuencias para las octavas 0 a la 6, que son las que mejor
se ejecutan en el PIC, mas arriba o mas abajo ya es molesto o inaudible. Dichas frecuencias
estan en la siguiente tabla:
DO
DO#
RE
RE#
MI
FA
FA#
SOL
SOL#
LA
LA#
SI
0
32,70
34,64
36,70
38,89
41,20
43,65
46,24
48,99
51,91
55,00
58,27
61,73
1
65,40
69,29
73,41
77,78
82,40
87,30
92,49
97,99
103,82
110,00
116,54
123,47
2
130,81
138,59
146,83
155,56
164,81
174,61
184,99
195,99
207,65
220,00
233,08
246,94
3
261,62
277,18
293,66
311,12
329,62
349,22
369,99
391,99
415,30
440,00
466,16
493,88
4
523,25
554,36
587,32
622,25
659,25
698,45
739,98
783,99
830,60
880,00
932,32
987,76
5
1046,50
1108,73
1174,65
1244,50
1318,51
1396,91
1479,97
1567,98
1661,21
1760,00
1864,65
1975,53
6
2093,00
2217,46
2349,31
2489,01
2637,02
2793,82
2959,95
3135,96
3322,43
3520,00
3729,31
3951,06
DO
DO#
RE
RE#
MI
FA
FA#
0
15289,02
14430,91
13620,97
12856,48
12134,90
11453,82
10810,97
1
7644,51
7215,45
6810,48
6428,24
6067,45
5726,91
5405,48
2
3822,25
3607,72
3405,24
3214,12
3033,72
2863,45
2702,74
3
1911,12
1803,86
1702,62
1607,06
1516,86
1431,72
1351,37
4
955,56
901,93
851,31
803,53
758,43
715,86
675,68
5
477,78
450,96
425,65
401,76
379,21
357,93
337,84
6
238,89
225,48
212,82
200,88
189,60
178,96
168,92
SOL
SOL#
LA
LA#
SI
10204,20
9631,48
9090,90
8580,67
8099,07
5102,10
4815,74
4545,45
4290,33
4049,53
2551,05
2407,87
2272,72
2145,16
2024,76
1275,52
1203,93
1136,36
1072,58
1012,38
637,76
601,96
568,18
536,29
506,19
318,88
300,98
284,09
268,14
253,09
159,44
150,49
142,04
134,07
126,54
#define Speaker PIN_B0 #define nDO 0 // DO #define nDO_ 1 // DO# #define nRE 2 //
RE #define nRE_ 3 // RE# #define nMI 4 // MI #define nFA 5 // FA #define nFA_ 6 //
FA# #define nSOL 7 // SOL #define nSOL_ 8 // SOL# #define nLA 9 // LA #define
nLA_ 10 // LA# #define nSI 11 // SI int16 FreqNota[12]={ // retardos entre estado alto //
y bajo para generar las notas 15289, // DO 14430, // DO# 13620, // RE 12856, // RE#
12134, // MI 11453, // FA 10810, // FA# 10204, // SOL 9631, // SOL# 9090, // LA
8580, // LA# 8099 // SI }; void Play(int nota, int octava, int16 duracion){ int16 fn; int16
mS_Transcurridos=0; // Contadores necesarios // para controlar la duracin int16
CiclosL=0; // Contandor de uS fn=FreqNota[nota]; // Define los retardos para generar //
la frecuencia de cada nota fn>>=(octava); // Adapta la frecuencia a la octava actual //
haciendo una rotacin // a la derecha por octava do{ output_high(Speaker); // Genera la
frecuancia delay_us(fn); // con los retardos mientras CiclosL+=(fn); // aumenta el
contador de // ciclos transcurridos output_low(Speaker); // en dos partes para repartir el
delay_us(fn); // trabajo entre estado alto y bajo. CiclosL+=(fn); // CiclosL+=25; //
Compensador. while(CiclosL>999){ // Se queda en el bucle mientras CiclosL // sea
menor a 1000 (1 mS) CiclosL-=1000; // Le resta 1000 a CiclosL mS_Transcurridos++; //
y le suma 1 a mS_Transcurridos. CiclosL+=25; // Compensador. } }while
(duracion>mS_Transcurridos); // Repite el bucle hasta que haya // pasado el tiempo
indicado. }
Bueno, sabiendo como ejecutar las notas musicales ahora es tiempo de interpretar una
meloda.
Como aclar antes de msica no tengo conocimientos, pero buscando alguna meloda a
interpretar en el PIC record que en BASIC (el antguo) haba una funcin llamada PLAY y que
interpretaba las notas musicales con el PC Speaker. Buscando en Google encontr un artculo
titulado DJ QBASIC
donde hay diez canciones conocidas. Ahora lo que resta es adaptar el
cdigo BASIC a CCS con la funcin PLAY para C que vimos en la entrada "Generar sonido con
PIC", y es cuando vemos otro pequeo inconveniente, las notas musicales en BASIC estn en el
sistema de notacin musical ingls y nosotros usamos el latino, en la WikiPedia encontr este
artculo donde hablan de eso y se muestra la equivalencia: Escala musical .
En base a eso hice este ejemplo que interpreta una meloda segn se pulse una tecla, si se
pulsa la tecla conectada a RB1 suena "Pop Corn", si se pulsa RB2 suena "Ecuador" y si se pulsa
RB3 suena "The lion sleep tonight".
(nMI ,3,125); delay_ms (250); play (nRE ,3,125); delay_ms (125); play (nDO ,3,125);
delay_ms (250); delay_ms (125); play (nMI ,3,125); delay_ms (125); play (nRE ,3,500);
break; } }
Si no lo quieres copiar, lo quieres modificar o lo quieres ya compilado, te puedes bajar el
proyecto completo haciendo click en este link .
http://picrobot.blogspot.com/2010/03/picmusic.html
generar sonido matlab
The duration for which a given vector will play depends on the number of elements in the
vector and the sampling rate. For example, a 1000-element vector, when played at 1 kHz,
will last 1 second. When played at 500 Hz, it will last 2 seconds. Therefore, the first choice
you should make is the sampling rate you want to use. To avoid aliasing, the sampling rate
should be twice as large as the largest frequency component of the signal. However, you
may want to make it even larger than that to avoid attenuation of frequencies close to the
sampling rate.
Given a sampling rate of 1 kHz, the following example creates a sound vector of a given
duration and tone frequency (using the LINSPACE and SIN functions):
Fs = 1000;
%# Samples per second
toneFreq = 50; %# Tone frequency, in Hertz
nSeconds = 2; %# Duration of the sound
y = sin(linspace(0, nSeconds*toneFreq*2*pi, round(nSeconds*Fs)));
When played at 1 kHz using the SOUND function, this vector will generate a 50 Hz tone for
2 seconds:
sound(y, Fs); %# Play sound at sampling rate Fs
The vector can then be saved as a wav file using the WAVWRITE function:
wavwrite(y, Fs, 8, 'tone_50Hz.wav'); %# Save as an 8-bit, 1 kHz signal
The sound vector can later be loaded using the WAVREAD function. If you're going to
concatenate two sound vectors, you should make sure that they are both designed to use
the same sampling rate.
amplitude = 1;
sampleFreq = 48000;
save2file = 0;
case 2
amplitude = 1;
sampleFreq = 48000;
save2file = 0;
case 3
sampleFreq = 48000;
save2file = 0;
case 4
save2file = 0;
end
Optional Reading
I cover the basics of this article in a multi-part blog series, which you should check out if you
have trouble:
Part 1 - How Audio Data is Represented
Part 2 - Demystifying the WAV Format
Part 3 - Synthesizing Simple WAV Audio Using C#
Part 4 - Algorithms for Different Sound Waves in C#
What's An Oscillator?
You can create a pretty neat sounding instrument by combining the outputs of multiple
oscillators. For example, if you have three oscillators oscillating at a frequency of 440Hz
(concert A pitch), but each of them has a different waveform (saw, square, sine) you get a very
interesting, layered sound.
But before we get too deep into this subject, let's briefly explore the physics of sound.
Sound happens when air pressure changes on your ear drum. When you clap in an empty
room, pressure waves bounce all over the place and dance on your eardrum. The changes in
pressure are detected continuously by your ear.
Digitally, pressure is referred to by a scalar value called amplitude. The amplitude (loudness)
of the wave is measured thousands of times per second (44,100 times per second on CDs).
Every measurement of pressure (aka amplitude) is called a sampleCDs are recorded with
44,100 samples per second, each with a value between the minimum and maximum amplitude
for the bit depth.
Think about 44,100 samples per second. That's a lot of stuff for your ear to detect. That's how
we're able to hear so much stuff going on in the mix of a song, especially in stereo tracks where
you have 44,100 samples per second, per ear.
It turns out that there is a horribly intense mathematical theorem which basically tells us that
44,100 samples per second is enough to accurately represent a pitch as high as 22 KHz. The
human ear can really hear only up to 20KHz, so a 44.1KHz sampling rate is a more than highenough sampling rate.
This whole section is expanded in detail on my blog:
Part 1 - How Audio Data is Represented
Terminology
So now you have a rather glancing overview of how sound works, and perhaps some clues as
to how we should go about representing it in computers. Let's go over all this new terminology
(plus some even newer terms) in delicious, bulleted format:
Sample: A measurement of a sound wave at a very small point in time. 44,100 of these
measurements in a row form a single channel of CD-quality audio.
Amplitude: The value of a sample. Max and min values are dependent upon the bit depth.
Bit depth: The number of bits used to represent a sample. 16-bit, 32-bit, etc. Max amplitude is
(2^depth) / 2 1.
Sample rate (aka sampling rate, aka bit rate): The number of samples per second of audio.
44,100 is standard for CD-quality audio.
By now, you've probably surmised that a second of audio data is somehow represented by an
array of some integer data type, which has a length of 44,100. You would be correct in that
assumption. However, if you want sound to play from a computer's sound card, that data has to
be accompanied with a bunch of format information. WAV is probably the easiest format to deal
with.
See more in the following article:
Part 2 - Demystifying the WAV Format
You can also see how to build out a WAV file, old school and binary style, in the 3 rd part of that
series:
Part 3 - Synthesizing Simple WAV Audio Using C#
However, we are taking a slightly easier route, by using DirectSound. DirectSound gives us a lot
of nice classes for all the format information, abstracting all that stuff away and allowing us to
pump a stream of data into a DirectSound object and play it. Perfect for a synthesizer app!
So, let's get started!
I learned some Blend while working with this app, since it's built on WPF. The image buttons are
just radio buttons. I had to differentiate the group number per instance of the user control at
runtime (in the constructor of the Oscillator class).
I'm a terrible UI designer for the most part, so this is about as sexy as I'm willing to make this
application. But feel free to make it look and act better!
Designing the UI
There's a dirty little secret in this application. It says it can oscillate 3 waves, but in truth, there's
a constant (set to 3) that you can modify. You could have six if you wanted. How did I
accomplish this? Each synth that you see is an instance of a WPF user control called
Oscillator.xaml:
I have a StackPanel called Oscs in the main window. In the Window_Loaded event handler of
the main window, I use this bit of code to add instances of the usercontrol:
C#
// Add 3 oscillators
Oscillator tmp;
for (int i = 0; i < NUM_GENERATORS; i++)
{
tmp = new Oscillator();
Oscs.Children.Add(tmp);
mixer.Oscillators.Add(tmp);
}
VB
' Add 3 oscillators
Dim tmp As Oscillator
Dim i As Integer = 0
While i < NUM_GENERATORS
tmp = New Oscillator()
Oscs.Children.Add(tmp)
mixer.Oscillators.Add(tmp)
System.Math.Max(System.Threading.Interlocked.Increment(i),i - 1)
End While
The long rectangular canvas is used to plot the values of the generated wave, so you can
visualize the wave as it's played. It is scaled along the X axis so you can see the general shape
of the wave, which would be impossible without scaling it with 44,100 samples per second.
Earlier in the article, I noted that a sound file is basically a really, really long array of 16- or 32-bit
floating point numbers between -1 and 1. We use this data to plot the graph as well. More on
that later.
Now that we have the UI figured out (dynamic addition of oscillators), let's take a look at exactly
how the sound is produced.
One of the many cool things about DirectSound is that it basically wraps the WAV format for
you. You set the buffering/format options and then shove a bunch of data into it, and it will play.
Magic.
The way I've architected the solution is a little more modular. None of the oscillators has the
ability to play itselfrather, uses its UI to control some values such as frequency, amplitude and
wave type. These values are tied to public properties. The Oscillator component does virtually
no audio work at all.
The generation of audio data is handled by the custom Mixer class, which takes a collection of
Oscillators and, based on their properties, creates a composite of all the generators. This is
done by averaging the samples in every oscillator and putting them into a new array of data.
One of the workhorses of the Mixer class is the method GenerateOscillatorSampleData. This
takes an Oscillator as an argument to give access to the public properties set in the UI. From
there, the algorithm generates 1 second of sample data (specified by the
member bufferDurationSeconds) based on the wave type that has been selected in the UI.
This is where the mathy stuff comes in to play. Check out this method and the different cases in
the switch statement that determine what kind of wave to create below.
C#
public short[] GenerateOscillatorSampleData(Oscillator osc)
{
// Creates a looping buffer based on the params given
// Fill the buffer with whatever waveform at the specified frequency
int numSamples = Convert.ToInt32(bufferDurationSeconds *
waveFormat.SamplesPerSecond);
short[] sampleData = new short[numSamples];
double frequency = osc.Frequency;
totalSamplesWritten++;
}
}
break;
case WaveType.Noise:
{
Random rnd = new Random();
for (int i = 0; i < numSamples; i++)
{
sampleData[i] = Convert.ToInt16(
rnd.Next(-amplitude, amplitude));
}
}
break;
}
return sampleData;
VB.Net
Public Function GenerateOscillatorSampleData(ByVal osc As Oscillator) As Short()
' Creates a looping buffer based on the params given
' Fill the buffer with whatever waveform at the specified frequency
Dim numSamples As Integer = Convert.ToInt32(
bufferDurationSeconds * waveFormat.SamplesPerSecond)
Dim sampleData As Short() = New Short(numSamples - 1) {}
Dim frequency As Double = osc.Frequency
Dim amplitude As Integer = osc.Amplitude
Dim angle As Double = (Math.PI * 2 * frequency) /
(waveFormat.SamplesPerSecond * waveFormat.Channels)
Select Case osc.WaveType
Case WaveType.Sine
If True Then
For i As Integer = 0 To numSamples - 1
' Generate a sine wave in both channels.
sampleData(i) =
Convert.ToInt16(amplitude * Math.Sin(angle * i))
Next
End If
Exit Select
Case WaveType.Square
If True Then
For i As Integer = 0 To numSamples - 1
' Generate a square wave in both channels.
If Math.Sin(angle * i) > 0 Then
sampleData(i) = Convert.ToInt16(amplitude)
Else
sampleData(i) = Convert.ToInt16(-amplitude)
End If
Next
End If
Exit Select
Case WaveType.Sawtooth
If True Then
Dim samplesPerPeriod As Integer =
Convert.ToInt32(waveFormat.SamplesPerSecond /
(frequency / waveFormat.Channels))
Dim sampleStep As Short =
Convert.ToInt16((amplitude * 2) / samplesPerPeriod)
Dim tempSample As Short = 0
Dim i As Integer = 0
Dim totalSamplesWritten As Integer = 0
While totalSamplesWritten < numSamples
tempSample = CShort(-amplitude)
i=0
While i < samplesPerPeriod AndAlso totalSamplesWritten <
numSamples
tempSample += sampleStep
sampleData(totalSamplesWritten) = tempSample
totalSamplesWritten += 1
i += 1
End While
End While
End If
Exit Select
Case WaveType.Noise
If True Then
Dim rnd As New Random()
For i As Integer = 0 To numSamples - 1
sampleData(i) = Convert.ToInt16(
rnd.[Next](-amplitude, amplitude))
Next
End If
Exit Select
End Select
Return sampleData
End Function
The Mixer is the heart of the app, and it's a beautiful example of object orientation and
cohesion. Give it three things (oscillators) and it spits out a new thing you can use (an array of
sample data).
Now that we have the sample data, all we have to do is play it back using DirectSound.
As I mentioned, DirectSound provides a wrapper over the WAV format. You set up your buffer
and format information and then feed it a bunch of data in the form of an array of shorts (arrays
of trousers are known to cause errors).
First, we initialize the format information and buffer in the Window_Loaded event handler of the
main form. The values below are not really arbitrary; there is an explanation of them in the
Optional Reading section above (see Demystifying the WAV Format). This code also contains
the code to add the oscillators, as shown earlier in the article.
C#
private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
WindowInteropHelper helper =
new WindowInteropHelper(Application.Current.MainWindow);
device.SetCooperativeLevel(helper.Handle, CooperativeLevel.Normal);
waveFormat = new Microsoft.DirectX.DirectSound.WaveFormat();
waveFormat.SamplesPerSecond = 44100;
waveFormat.Channels = 2;
waveFormat.FormatTag = WaveFormatTag.Pcm;
waveFormat.BitsPerSample = 16;
waveFormat.BlockAlign = 4;
waveFormat.AverageBytesPerSecond = 176400;
bufferDesc = new BufferDescription(waveFormat);
bufferDesc.DeferLocation = true;
bufferDesc.BufferBytes = Convert.ToInt32(
bufferDurationSeconds * waveFormat.AverageBytesPerSecond /
waveFormat.Channels);
// Add 3 oscillators
Oscillator tmp;
for (int i = 0; i < NUM_GENERATORS; i++)
{
tmp = new Oscillator();
Oscs.Children.Add(tmp);
mixer.Oscillators.Add(tmp);
}
VB
Private Sub Window_Loaded(ByVal sender As Object, ByVal e As
System.Windows.RoutedEventArgs)
Dim helper As New WindowInteropHelper(Application.Current.MainWindow)
device.SetCooperativeLevel(helper.Handle, CooperativeLevel.Normal)
waveFormat = New Microsoft.DirectX.DirectSound.WaveFormat()
waveFormat.SamplesPerSecond = 44100
waveFormat.Channels = 2
waveFormat.FormatTag = WaveFormatTag.Pcm
waveFormat.BitsPerSample = 16
waveFormat.BlockAlign = 4
waveFormat.AverageBytesPerSecond = 176400
bufferDesc = New BufferDescription(waveFormat)
bufferDesc.DeferLocation = True
bufferDesc.BufferBytes = Convert.ToInt32(
bufferDurationSeconds * waveFormat.AverageBytesPerSecond /
waveFormat.Channels)
' Add 3 oscillators
Dim tmp As Oscillator
For i As Integer = 0 To NUM_GENERATORS - 1
tmp = New Oscillator()
Oscs.Children.Add(tmp)
mixer.Oscillators.Add(tmp)
Next
End Sub
When you click the Play button, the application takes its collection of oscillators and passes the
values of the UI controls to the Mixer (which is initialized on each click with a reference to the
main form window, so it can grab the Oscillator user controls).
The mixer outputs an array of shorts, which we write to a DirectSound buffer.
Here is the code for the Play button's click event handler:
C#
private void btnPlay_Click(object sender, System.Windows.RoutedEventArgs e)
{
mixer.Initialize(Application.Current.MainWindow);
short[] sampleData = mixer.MixToStream();
buffer = new SecondaryBuffer(bufferDesc, device);
All that's left is to draw the graph of the waveform on the canvas. Below is the GraphWaveform
method. This method could graph anything it wanted to, as long as it was an array of shorts (not
trousers). It's reminiscent of trying to graph things using Flash back in the day, when you had to
actually figure out points and lines (most likely on paper), but WPF's Polyline object makes this
rather trivial.
C#
private void GraphWaveform(short[] data)
{
cvDrawingArea.Children.Clear();
double canvasHeight = cvDrawingArea.Height;
double canvasWidth = cvDrawingArea.Width;
int observablePoints = 1800;
double xScale = canvasWidth / observablePoints;
double yScale = (canvasHeight /
(double)(amplitude * 2)) * ((double)amplitude / MAX_AMPLITUDE);
Polyline graphLine = new Polyline();
graphLine.Stroke = Brushes.Black;
graphLine.StrokeThickness = 1;
for (int i = 0; i < observablePoints; i++)
{
graphLine.Points.Add(
new Point(i * xScale, (canvasHeight / 2) - (data[i] * yScale) ));
}
}
cvDrawingArea.Children.Add(graphLine);
VB
Conclusion
This was a really fun little project that took way less time to code than it does to explain. It's a
great exercise because it requires you to think about an ancillary field of science before you can
sit down and code, which is really what coding for fun's all about, anyway!
If you want to try this out, the download link for the source code is at the top of the article.
http://channel9.msdn.com/coding4fun/articles/Generating-Sound-Waveswith-C-Wave-Oscillators
Title : The title of the ring tone starts the string followed by a semicolon.
There are varying specifications on its maximum length but it is
suggested it shouldnt be any more than 10 characters long.
b (beats per minute). The BPM or tempo can be any one of the following
values 25, 28, 31, 35, 40, 45, 50, 56, 63, 70, 80, 90, 100, 112, 125, 140,
160, 180, 200, 225, 250, 285, 320, 355, 400, 450, 500, 565, 635, 715,
800, 900.
If any of the parameters is missing from the control section, the following
defaults are assumed : 4=duration, 6=scale, 63=beats-per-minute.
The circuit
As you can see the circuit required to generate tones is very simple. The
20MHz crystal controls the timing and can not be substituted with another value
without recalculating the divisors for each tone.
RB0
void InitTimer(void);
void delayms(unsigned char cnt);
void PlayNote(unsigned short note, unsigned char octave, unsigned int
duration);
unsigned
unsigned
unsigned
unsigned
unsigned
char beep;
char preloadTMR1L;
char preloadTMR1H;
short TMR0Count;
char beat_speed;
#define MissionImpossible
void main(void)
{
unsigned int pointer = 0;
unsigned int octave = 0;
unsigned int duration = 0;
unsigned short note = 0;
InitTimer();
PEIE = 1;
GIE = 1;
do {
octave = defaultoctave;
duration = 16;
pointer += 2;
}
else if (Melody[pointer] == '8') {
duration = 8;
pointer++;
}
else if (Melody[pointer] == '4') {
duration = 4;
pointer++;
}
else if (Melody[pointer] == '2') {
duration = 2;
pointer++;
}
else if (Melody[pointer] == '1') {
duration = 1;
pointer++;
} else duration = defaultduration;
if (Melody[pointer + 1] == '#') {
/* Process Sharps */
switch (Melody[pointer]) {
case 'a' : note = 10726;
break;
case 'c' : note = 9019;
break;
case 'd' : note = 8035;
break;
case 'f' : note = 6757;
break;
case 'g' : note = 6024;
break;
}
pointer +=2;
} else {
switch (Melody[pointer]) {
case 'a' : note = 11364;
break;
case 'b' : note = 10123;
break;
case 'c' : note = 9555;
break;
case 'd' : note =
break;
case 'e' : note =
break;
case 'f' : note =
break;
case 'g' : note =
break;
case 'p' : note =
break;
8513;
7584;
7158;
6378;
0;
}
pointer++;
if (Melody[pointer] == '.') {
/* Duration 1.5x */
duration = duration + 128;
pointer++;
}
if (Melody[pointer] == '4') {
octave = 4;
pointer++;
} else if (Melody[pointer] == '5') {
octave = 5;
pointer++;
} else
if (Melody[pointer] == '6') {
octave = 6;
pointer++;
} else
if (Melody[pointer] == '7') {
octave = 7;
pointer++;
}
if (Melody[pointer] == '.') {
/* Duration 1.5x */
duration = duration + 128;
pointer++;
}
PlayNote(note, octave, duration);
case 4 : /*
break;
case 5 : /*
note =
break;
case 6 : /*
note =
break;
case 7 : /*
note =
break;
Do noting */
%2 */
note >> 1;
%4 */
note >> 2;
%8 */
note >> 4;
*/
/* Set TMR0 to Internal CLk, 1:256 */
/* Clear TMR0 Flag, ready for use */
/* Enable Timer Overflow Interrupt */
/* Initialise Timer 1 */
T1CON = 0b00000001;
/* Counter Enabled, Using Ext Pin 1:1
Prescaler */
TMR1IF = 0;
/* Clear Flag */
TMR1IE = 1;
/* Enable Interrupt */
}
void interrupt interr(void)
{
if (T0IF) {
TMR0 = beat_speed;
if (TMR0Count) TMR0Count--;
T0IF = 0;
}
if (TMR1IF) {
if (beep) TONE = !TONE;
else
TONE = 0;
TMR1H = preloadTMR1H;
TMR1L = preloadTMR1L;
TMR1IF = 0; /* Clear Flag */
}
The above example compiled with the Mission Impossible theme takes a
modest 1K of memory. .
Memory Usage Map:
Program ROM
Program ROM
Program ROM
$0000 - $004D
$006F - $01BA
$05B9 - $07FF
$004E
$014C
$0247
$03E1
(
(
(
(
Bank 0 RAM
Bank 0 RAM
$0020 - $0038
$0071 - $0078
$0019 (
$0008 (
$0021 (
78)
332)
583)
993)
words
words
words
words total Program ROM
25) bytes
8) bytes
33) bytes total Bank 0 RAM
Program statistics:
Total ROM used
Total RAM used
Glossary
Minim - Minim is the British term for Half Note. A minim is worth 2 beats.
Quaver - Quaver is the British term for 8th Note. A quaver is worth 1/2 a
beat.
Octave - With the 12 musical notes, let's call note number one C. If we
start on C and work our way up the 12 notes in pitch, we will eventually
hit C again but of a higher pitch (exactly one octave higher). At this point
the C we are playing is in the next Octave on from the C we started on.
For example if we started on C4 (4th Octave) we would end up on C5
(5th Octave) and this can keep going endlessly until the frequency of the
pitch reaches beyond our aural hearing frequency range. The same can
apply going down in pitch / octaves. So Octave is specifiying what
Octave or Pitch/Frequency Range to play your specified note from.
Links
http://retired.beyondlogic.org/pic/ringtones.htm