commit
525c1d7f09
@ -0,0 +1,261 @@
|
||||
/*
|
||||
Copyright (C) 2002 Anthony Van Groningen
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/transport.h>
|
||||
|
||||
#include <asoundlib.h>
|
||||
|
||||
#include "synth.h"
|
||||
struct Synth synth;
|
||||
|
||||
typedef jack_default_audio_sample_t sample_t;
|
||||
|
||||
const double PI = 3.14;
|
||||
|
||||
jack_client_t *client;
|
||||
jack_port_t *output_port;
|
||||
unsigned long sr;
|
||||
int freq = 880;
|
||||
int bpm;
|
||||
jack_nframes_t tone_length, wave_length;
|
||||
sample_t *wave;
|
||||
long offset = 0;
|
||||
int transport_aware = 0;
|
||||
jack_transport_state_t transport_state;
|
||||
|
||||
void usage () {
|
||||
fprintf (stderr, "\n"
|
||||
"usage: jack_metro \n"
|
||||
" [ --frequency OR -f frequency (in Hz) ]\n"
|
||||
" [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
|
||||
" [ --duration OR -D duration (in ms) ]\n"
|
||||
" [ --attack OR -a attack (in percent of duration) ]\n"
|
||||
" [ --decay OR -d decay (in percent of duration) ]\n"
|
||||
" [ --name OR -n jack name for metronome client ]\n"
|
||||
" [ --transport OR -t transport aware ]\n"
|
||||
" --bpm OR -b beats per minute\n"
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
process_silence (jack_nframes_t nframes)
|
||||
{
|
||||
sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
|
||||
memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
|
||||
}
|
||||
|
||||
void
|
||||
process_audio (jack_nframes_t nframes)
|
||||
{
|
||||
|
||||
sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
|
||||
for(int i = 0; i < nframes; i++) {
|
||||
buffer[i] = synth_render_sample(&synth) / 32767.0;
|
||||
}
|
||||
// jack_nframes_t frames_left = nframes;
|
||||
|
||||
// while (wave_length - offset < frames_left) {
|
||||
// memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
|
||||
// frames_left -= wave_length - offset;
|
||||
// offset = 0;
|
||||
// }
|
||||
// if (frames_left > 0) {
|
||||
// memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
|
||||
// offset += frames_left;
|
||||
// }
|
||||
}
|
||||
|
||||
int
|
||||
process (jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
if (transport_aware) {
|
||||
jack_position_t pos;
|
||||
|
||||
if (jack_transport_query (client, &pos)
|
||||
!= JackTransportRolling) {
|
||||
|
||||
process_silence (nframes);
|
||||
return 0;
|
||||
}
|
||||
offset = pos.frame % wave_length;
|
||||
}
|
||||
process_audio (nframes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sample_rate_change () {
|
||||
printf("Sample rate has changed! Exiting...\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static char *midi_note_names[12] = {
|
||||
"C",
|
||||
"C#",
|
||||
"D",
|
||||
"D#",
|
||||
"E",
|
||||
"F",
|
||||
"F#",
|
||||
"G",
|
||||
"G#",
|
||||
"A",
|
||||
"A#",
|
||||
"B",
|
||||
};
|
||||
|
||||
const char *midi_note_name(int note) {
|
||||
return midi_note_names[note % 12];
|
||||
}
|
||||
|
||||
snd_seq_t *open_seq();
|
||||
void midi_action(snd_seq_t *seq_handle);
|
||||
|
||||
snd_seq_t *open_seq() {
|
||||
|
||||
snd_seq_t *seq_handle;
|
||||
int portid;
|
||||
|
||||
if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
|
||||
fprintf(stderr, "Error opening ALSA sequencer.\n");
|
||||
exit(1);
|
||||
}
|
||||
snd_seq_set_client_name(seq_handle, "Vampi Synth");
|
||||
if ((portid = snd_seq_create_simple_port(seq_handle, "Cornhole",
|
||||
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
|
||||
SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
|
||||
fprintf(stderr, "Error creating sequencer port.\n");
|
||||
exit(1);
|
||||
}
|
||||
return(seq_handle);
|
||||
}
|
||||
|
||||
void midi_action(snd_seq_t *seq_handle) {
|
||||
|
||||
snd_seq_event_t *ev;
|
||||
|
||||
do {
|
||||
snd_seq_event_input(seq_handle, &ev);
|
||||
switch (ev->type) {
|
||||
case SND_SEQ_EVENT_NOTEON:
|
||||
printf("Note on %d (%s) %d\n", ev->data.note.note, midi_note_name(ev->data.note.note), ev->data.note.velocity);
|
||||
synth_note_on(&synth, ev->data.note.note, ev->data.note.velocity);
|
||||
break;
|
||||
case SND_SEQ_EVENT_NOTEOFF:
|
||||
printf("Note off %d\n", ev->data.note.note);
|
||||
synth_note_off(&synth, ev->data.note.note, ev->data.note.velocity);
|
||||
break;
|
||||
}
|
||||
snd_seq_free_event(ev);
|
||||
} while (snd_seq_event_input_pending(seq_handle, 0) > 0);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
sample_t scale;
|
||||
int i, attack_length, decay_length;
|
||||
double *amp;
|
||||
double max_amp = 0.5;
|
||||
int option_index;
|
||||
int opt;
|
||||
int got_bpm = 0;
|
||||
int attack_percent = 1, decay_percent = 10, dur_arg = 100;
|
||||
char *client_name = 0;
|
||||
char *bpm_string = "bpm";
|
||||
int verbose = 0;
|
||||
jack_status_t status;
|
||||
|
||||
const char *options = "f:A:D:a:d:b:n:thv";
|
||||
struct option long_options[] =
|
||||
{
|
||||
{"name", 1, 0, 'n'},
|
||||
{"transport", 0, 0, 't'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
client_name = (char *) malloc (strlen (optarg) * sizeof (char));
|
||||
strcpy (client_name, optarg);
|
||||
break;
|
||||
case 't':
|
||||
transport_aware = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "unknown option %c\n", opt);
|
||||
case 'h':
|
||||
usage ();
|
||||
return -1;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initial Jack setup, get sample rate */
|
||||
if (!client_name) {
|
||||
client_name = (char *) malloc (9 * sizeof (char));
|
||||
strcpy (client_name, "metro");
|
||||
}
|
||||
if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
|
||||
fprintf (stderr, "jack server not running?\n");
|
||||
return 1;
|
||||
}
|
||||
jack_set_process_callback (client, process, 0);
|
||||
output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
|
||||
sr = jack_get_sample_rate (client);
|
||||
|
||||
synth_init(&synth);
|
||||
synth.attack = 50;
|
||||
synth.decay = 200;
|
||||
synth.sustain = 60;
|
||||
synth.release = 100;
|
||||
|
||||
/* setup wave table parameters */
|
||||
|
||||
if (jack_activate (client)) {
|
||||
fprintf (stderr, "cannot activate client");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snd_seq_t *seq_handle;
|
||||
int npfd;
|
||||
struct pollfd *pfd;
|
||||
|
||||
seq_handle = open_seq();
|
||||
npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
|
||||
pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
|
||||
snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN);
|
||||
while (1) {
|
||||
printf("poll\n");
|
||||
if (poll(pfd, npfd, 100000) > 0) {
|
||||
midi_action(seq_handle);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "synth.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "tables.inc"
|
||||
|
||||
void synth_init(struct Synth *synth) {
|
||||
}
|
||||
|
||||
uint8_t midi_notes[128];
|
||||
void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity) {
|
||||
for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
|
||||
struct Voice *voice = synth->voices + i;
|
||||
if(voice->env_state == None) {
|
||||
voice->phase = voice->time = 0;
|
||||
voice->freq = (uint32_t)(midi_note_freq_table[note & 0x7f] * 256);
|
||||
midi_notes[note & 0x7f] = i;
|
||||
voice->attack = synth->attack;
|
||||
voice->decay = synth->decay;
|
||||
voice->sustain = synth->sustain;
|
||||
voice->release = synth->release;
|
||||
voice->volume = velocity;
|
||||
voice->env_state = Attack;
|
||||
printf("Attack %d\n", synth->attack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity) {
|
||||
(void)velocity;
|
||||
struct Voice *voice = synth->voices + midi_notes[note & 0x7f];
|
||||
voice->time = 0;
|
||||
voice->env_state = Release;
|
||||
printf("Release %d\n", voice->release);
|
||||
}
|
||||
|
||||
int16_t synth_render_sample(struct Synth *synth) {
|
||||
int32_t smpl = 0;
|
||||
for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
|
||||
struct Voice *v = synth->voices + i;
|
||||
if(v->env_state != None) {
|
||||
|
||||
v->time++;
|
||||
|
||||
int32_t amplitude = 0; // calculate based on velocity and envelope
|
||||
uint32_t ms_time = v->time * 1000 / SAMPLE_RATE;
|
||||
switch(v->env_state) {
|
||||
case Attack:
|
||||
if(v->attack > 0)
|
||||
amplitude = v->volume * ms_time / v->attack;
|
||||
if(ms_time > v->attack) {
|
||||
printf("Decay %d\n", v->decay);
|
||||
v->env_state = Decay;
|
||||
v->time = 0;
|
||||
}
|
||||
break;
|
||||
case Decay:
|
||||
if(v->decay > 0)
|
||||
amplitude = (100 * v->volume * (v->decay - ms_time) + v->sustain * v->volume * ms_time) / v->decay / 100;
|
||||
if(ms_time > v->decay) {
|
||||
printf("Sustain %d\n", v->sustain);
|
||||
v->env_state = Sustain;
|
||||
v->time = 0;
|
||||
}
|
||||
break;
|
||||
case Sustain:
|
||||
amplitude = v->volume * v->sustain / 100;
|
||||
break;
|
||||
case Release:
|
||||
amplitude = v->volume * (v->release - ms_time) * v->sustain / v->release / 100;
|
||||
if(ms_time > v->release) {
|
||||
v->time = 0;
|
||||
v->freq = 0;
|
||||
v->env_state = None;
|
||||
printf("None\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(v->env_state != None && v->freq) {
|
||||
v->phase += (1 << 8);
|
||||
uint32_t freq_phase = (SAMPLE_RATE << 16) / v->freq;
|
||||
while(v->phase >= freq_phase)
|
||||
v->phase -= freq_phase;
|
||||
int sine_phase = 256 * v->phase / freq_phase;
|
||||
int sine_phase_next = (sine_phase + 1) & 0xff;
|
||||
int sine_remainder = v->phase % freq_phase;
|
||||
// if(v->env_state == Release) {
|
||||
// printf("amplitude %d volume=%d time=%d ms_time=%d v->release=%d v->sustain=%d\n", amplitude, v->volume, v->time, ms_time, v->release, v->sustain);
|
||||
// }
|
||||
smpl += amplitude * sine_table_256[sine_phase] / 255;
|
||||
}
|
||||
if(smpl > 32767) smpl = 32767;
|
||||
if(smpl < -32768) smpl = -32768;
|
||||
}
|
||||
}
|
||||
return smpl & 0xffff;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
#ifndef SYNTH_H_
|
||||
#define SYNTH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SYNTH_NUM_VOICES 64
|
||||
#define TUNING 440
|
||||
|
||||
struct Voice {
|
||||
uint32_t phase;
|
||||
uint32_t time;
|
||||
uint16_t volume;
|
||||
uint32_t freq;
|
||||
|
||||
// Envelope
|
||||
enum {
|
||||
None,
|
||||
Attack,
|
||||
Decay,
|
||||
Sustain,
|
||||
Release
|
||||
} env_state;
|
||||
|
||||
uint16_t attack, decay, release; // in ms
|
||||
uint16_t sustain; // percentage
|
||||
};
|
||||
|
||||
struct Synth {
|
||||
struct Voice voices[SYNTH_NUM_VOICES];
|
||||
uint16_t attack, decay, sustain, release; // in ms
|
||||
};
|
||||
|
||||
void synth_init(struct Synth *synth);
|
||||
void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity);
|
||||
void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity);
|
||||
int16_t synth_render_sample(struct Synth *synth);
|
||||
|
||||
#endif /* SYNTH_H_ */
|
@ -0,0 +1,389 @@
|
||||
static const int16_t sine_table_256[256] = {
|
||||
0,
|
||||
402,
|
||||
804,
|
||||
1205,
|
||||
1606,
|
||||
2005,
|
||||
2404,
|
||||
2801,
|
||||
3196,
|
||||
3590,
|
||||
3981,
|
||||
4370,
|
||||
4756,
|
||||
5139,
|
||||
5519,
|
||||
5896,
|
||||
6270,
|
||||
6639,
|
||||
7005,
|
||||
7366,
|
||||
7723,
|
||||
8075,
|
||||
8423,
|
||||
8765,
|
||||
9102,
|
||||
9433,
|
||||
9759,
|
||||
10079,
|
||||
10393,
|
||||
10701,
|
||||
11002,
|
||||
11297,
|
||||
11585,
|
||||
11865,
|
||||
12139,
|
||||
12405,
|
||||
12664,
|
||||
12915,
|
||||
13159,
|
||||
13394,
|
||||
13622,
|
||||
13841,
|
||||
14052,
|
||||
14255,
|
||||
14449,
|
||||
14634,
|
||||
14810,
|
||||
14977,
|
||||
15136,
|
||||
15285,
|
||||
15425,
|
||||
15556,
|
||||
15678,
|
||||
15790,
|
||||
15892,
|
||||
15985,
|
||||
16068,
|
||||
16142,
|
||||
16206,
|
||||
16260,
|
||||
16304,
|
||||
16339,
|
||||
16363,
|
||||
16378,
|
||||
16383,
|
||||
16378,
|
||||
16363,
|
||||
16339,
|
||||
16304,
|
||||
16260,
|
||||
16206,
|
||||
16142,
|
||||
16068,
|
||||
15985,
|
||||
15892,
|
||||
15790,
|
||||
15678,
|
||||
15556,
|
||||
15425,
|
||||
15285,
|
||||
15136,
|
||||
14977,
|
||||
14810,
|
||||
14634,
|
||||
14449,
|
||||
14255,
|
||||
14052,
|
||||
13841,
|
||||
13622,
|
||||
13394,
|
||||
13159,
|
||||
12915,
|
||||
12664,
|
||||
12405,
|
||||
12139,
|
||||
11865,
|
||||
11585,
|
||||
11297,
|
||||
11002,
|
||||
10701,
|
||||
10393,
|
||||
10079,
|
||||
9759,
|
||||
9433,
|
||||
9102,
|
||||
8765,
|
||||
8423,
|
||||
8075,
|
||||
7723,
|
||||
7366,
|
||||
7005,
|
||||
6639,
|
||||
6270,
|
||||
5896,
|
||||
5519,
|
||||
5139,
|
||||
4756,
|
||||
4370,
|
||||
3981,
|
||||
3590,
|
||||
3196,
|
||||
2801,
|
||||
2404,
|
||||
2005,
|
||||
1606,
|
||||
1205,
|
||||
804,
|
||||
402,
|
||||
0,
|
||||
-402,
|
||||
-804,
|
||||
-1205,
|
||||
-1606,
|
||||
-2005,
|
||||
-2404,
|
||||
-2801,
|
||||
-3196,
|
||||
-3590,
|
||||
-3981,
|
||||
-4370,
|
||||
-4756,
|
||||
-5139,
|
||||
-5519,
|
||||
-5896,
|
||||
-6270,
|
||||
-6639,
|
||||
-7005,
|
||||
-7366,
|
||||
-7723,
|
||||
-8075,
|
||||
-8423,
|
||||
-8765,
|
||||
-9102,
|
||||
-9433,
|
||||
-9759,
|
||||
-10079,
|
||||
-10393,
|
||||
-10701,
|
||||
-11002,
|
||||
-11297,
|
||||
-11585,
|
||||
-11865,
|
||||
-12139,
|
||||
-12405,
|
||||
-12664,
|
||||
-12915,
|
||||
-13159,
|
||||
-13394,
|
||||
-13622,
|
||||
-13841,
|
||||
-14052,
|
||||
-14255,
|
||||
-14449,
|
||||
-14634,
|
||||
-14810,
|
||||
-14977,
|
||||
-15136,
|
||||
-15285,
|
||||
-15425,
|
||||
-15556,
|
||||
-15678,
|
||||
-15790,
|
||||
-15892,
|
||||
-15985,
|
||||
-16068,
|
||||
-16142,
|
||||
-16206,
|
||||
-16260,
|
||||
-16304,
|
||||
-16339,
|
||||
-16363,
|
||||
-16378,
|
||||
-16383,
|
||||
-16378,
|
||||
-16363,
|
||||
-16339,
|
||||
-16304,
|
||||
-16260,
|
||||
-16206,
|
||||
-16142,
|
||||
-16068,
|
||||
-15985,
|
||||
-15892,
|
||||
-15790,
|
||||
-15678,
|
||||
-15556,
|
||||
-15425,
|
||||
-15285,
|
||||
-15136,
|
||||
-14977,
|
||||
-14810,
|
||||
-14634,
|
||||
-14449,
|
||||
-14255,
|
||||
-14052,
|
||||
-13841,
|
||||
-13622,
|
||||
-13394,
|
||||
-13159,
|
||||
-12915,
|
||||
-12664,
|
||||
-12405,
|
||||
-12139,
|
||||
-11865,
|
||||
-11585,
|
||||
-11297,
|
||||
-11002,
|
||||
-10701,
|
||||
-10393,
|
||||
-10079,
|
||||
-9759,
|
||||
-9433,
|
||||
-9102,
|
||||
-8765,
|
||||
-8423,
|
||||
-8075,
|
||||
-7723,
|
||||
-7366,
|
||||
-7005,
|
||||
-6639,
|
||||
-6270,
|
||||
-5896,
|
||||
-5519,
|
||||
-5139,
|
||||
-4756,
|
||||
-4370,
|
||||
-3981,
|
||||
-3590,
|
||||
-3196,
|
||||
-2801,
|
||||
-2404,
|
||||
-2005,
|
||||
-1606,
|
||||
-1205,
|
||||
-804,
|
||||
};
|
||||
|
||||
// http://www.richardbrice.net/midi_notes.htm
|
||||
static const float midi_note_freq_table[128] = {
|
||||
8.176,
|
||||
8.662,
|
||||
9.177,
|
||||
9.723,
|
||||
10.301,
|
||||
10.913,
|
||||
11.562,
|
||||
12.250,
|
||||
12.978,
|
||||
13.750,
|
||||
14.568,
|
||||
15.434,
|
||||
16.352,
|
||||
17.324,
|
||||
18.354,
|
||||
19.445,
|
||||
20.601,
|
||||
21.826,
|
||||
23.124,
|
||||
24.499,
|
||||
25.956,
|
||||
27.500, // Lowest note on piano
|
||||
29.135,
|
||||
30.867,
|
||||
32.703,
|
||||
34.648,
|
||||
36.708,
|
||||
38.890,
|
||||
41.203,
|
||||
43.653,
|
||||
46.249,
|
||||
48.999,
|
||||
51.913,
|
||||
55.000,
|
||||
58.270,
|
||||
61.735,
|
||||
65.406,
|
||||
69.295,
|
||||
73.416,
|
||||
77.781,
|
||||
82.406,
|
||||
87.307,
|
||||
92.499,
|
||||
97.998,
|
||||
103.82,
|
||||
110.00,
|
||||
116.54,
|
||||
123.47,
|
||||
130.81,
|
||||
138.59,
|
||||
146.83,
|
||||
155.56,
|
||||
164.81,
|
||||
174.61,
|
||||
184.99,
|
||||
195.99,
|
||||
207.65,
|
||||
220.00,
|
||||
233.08,
|
||||
246.94,
|
||||
261.63, // Middle-C
|
||||
277.18,
|
||||
293.66,
|
||||
311.13,
|
||||
329.63,
|
||||
349.23,
|
||||
369.99,
|
||||
391.99,
|
||||
415.31,
|
||||
440.00,
|
||||
466.16,
|
||||
489.88,
|
||||
523.25,
|
||||
554.37,
|
||||
587.33,
|
||||
622.25,
|
||||
659.26,
|
||||
698.46,
|
||||
739.99,
|
||||
783.99,
|
||||
830.61,
|
||||
880.00,
|
||||
932.32,
|
||||
987.77,
|
||||
1046.5,
|
||||
1108.7,
|
||||
1174.7,
|
||||
1244.5,
|
||||
1318.5,
|
||||
1396.9,
|
||||
1480.0,
|
||||
1568.0,
|
||||
1661.2,
|
||||
1760.0,
|
||||
1864.7,
|
||||
1975.5,
|
||||
2093.0,
|
||||
2217.5,
|
||||
2349.3,
|
||||
2489.0,
|
||||
2637.0,
|
||||
2793.8,
|
||||
2960.0,
|
||||
3136.0,
|
||||
3322.4,
|
||||
3520.0,
|
||||
3729.3,
|
||||
3951.1,
|
||||
4186.0, // Highest note on piano
|
||||
4434.9,
|
||||
4698.6,
|
||||
4978.0,
|
||||
5274.0,
|
||||
5587.7,
|
||||
5919.9,
|
||||
6271.9,
|
||||
6644.9,
|
||||
7040.0,
|
||||
7458.6,
|
||||
7902.1,
|
||||
8372.0,
|
||||
8869.8,
|
||||
9397.3,
|
||||
9956.1,
|
||||
10548.1,
|
||||
11175.3,
|
||||
11839.8,
|
||||
12543.9,
|
||||
};
|
Loading…
Reference in new issue