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