1 /* notes.c -- Generate musical notes in chromatic scale
2 * $Id: notes.c,v 1.4 2005/06/29 03:20:34 kvance Exp $
3 * Copyright (C) 2001 Kev Vance <kvance@kvance.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place Suite 330; Boston, MA 02111-1307, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "notes.h"
29
30 short drums[DRUMCOUNT][DRUMCYCLES] = {
31 { 0, 0, 175, 175, 100, 90, 80, 70, 60, 50}, /* 0 */
32 { 500, 300, 520, 320, 540, 340, 550, 350, 540, 340}, /* 1 */
33 {1000,1200,1250,1400,1100,1150,1300,1000,1200, 500}, /* 2 */
34 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 3 (not a sound) */
35 { 950,1950, 750,1750, 550,1550, 350,1350, 150,1150}, /* 4 */
36 { 200, 210, 220, 230, 240, 250, 260, 270, 280, 600}, /* 5 */
37 { 900, 800, 700, 600, 500, 400, 300, 200, 100, 0}, /* 6 */
38 { 300, 200, 290, 190, 280, 180, 270, 170, 260, 160}, /* 7 */
39 { 400, 380, 360, 340, 320, 300, 280, 260, 250, 240}, /* 8 */
40 { 150, 100, 140, 90, 130, 80, 120, 70, 110, 60} /* 9 */
41 };
42
43 /* Delete a chain of notes */
deleteNoteChain(musicalNote * chain)44 void deleteNoteChain(musicalNote* chain)
45 {
46 /* Free each note in the chain recursively */
47 if (chain == NULL)
48 return;
49
50 deleteNoteChain(chain->next);
51 chain->next = NULL; /* Why not? */
52 free(chain);
53 }
54
55 /* Frequency notation (makes it easier to compute frequency):
56 C -3
57 C# -4
58 D -5
59 D# -6
60 E -7
61 F -8
62 F# -9
63 G -10
64 G# -11
65 A 0
66 A# 1
67 B 2
68 */
69
70 /* Translate a note index to frequency notation (above) */
frequencyNotation(int index)71 int frequencyNotation(int index)
72 {
73 /* If the note is A or above */
74 if (index >= 9)
75 return index - 9;
76 else
77 return -(index + 3);
78 }
79
noteFrequency(musicalNote mnote,musicSettings settings)80 float noteFrequency(musicalNote mnote, musicSettings settings)
81 {
82 double freq;
83 float fraction;
84 float basePitch = settings.basePitch;
85
86 int note = frequencyNotation(mnote.index);
87 int octave = mnote.octave;
88
89 if (mnote.type != NOTETYPE_NOTE)
90 return 0.0;
91
92 /* Multiply or divide the base frequency to get to the correct octave
93 relative to A */
94 if(octave > 0)
95 freq = basePitch*pow(2, octave);
96 else if (octave < 0)
97 freq = basePitch/pow(2, octave*(-1));
98 else
99 freq = basePitch;
100
101 if(note < 0)
102 freq /= 2.0;
103
104 /* Find the size of a half step */
105 fraction = (log(freq * 2.0) - log(freq)) / 12.0;
106
107 /* Move base freq to log */
108 freq = log(freq);
109
110 /* Add half-steps to reach the desired note)
111 desired note */
112 if(note < 0)
113 freq += (note*(-1))*fraction;
114 else if(note > 0)
115 freq += note*fraction;
116
117 /* Get out of log */
118 freq = exp(freq);
119
120 /* Return the frequency */
121 return freq;
122 }
123
noteDuration(musicalNote note,musicSettings settings)124 float noteDuration(musicalNote note, musicSettings settings)
125 {
126 float wholeDuration = settings.wholeDuration;
127 float duration;
128
129 /* Omit the triplet flag from the note length */
130 int length = note.length & ~NOTELEN_TRIPLET;
131
132 if (length <= 0) return 0;
133
134 /* Divide the whole duration by the length */
135 duration = wholeDuration / (float)length;
136
137 /* Adjust duration for dotted notes */
138 duration = duration * (2 - (1 / (float)(1 << note.dots)));
139
140 /* Note is a triplet: divide by 3 */
141 if (note.length & NOTELEN_TRIPLET)
142 duration /= 3;
143
144 /* Leave room for note spacing (except rests) */
145 if (!note.slur && note.type != NOTETYPE_REST)
146 duration -= settings.noteSpacing;
147
148 /* duration must be at least zero */
149 if (duration < 0) duration = 0;
150
151 return duration;
152 }
153
noteSpacing(musicalNote note,musicSettings settings)154 float noteSpacing(musicalNote note, musicSettings settings)
155 {
156 /* No break when slurring or for rests */
157 if (note.slur || note.type == NOTETYPE_REST)
158 return 0.0;
159
160 /* Otherwise return the noteSpacing setting. */
161 return settings.noteSpacing;
162 }
163