457 lines
22 KiB
PHP
Executable File
457 lines
22 KiB
PHP
Executable File
<?php
|
|
/*
|
|
array format:
|
|
the ID of each button is the distortion and note number (from the Atari)
|
|
noteArray[distortion][atari note index][0] = MIDI file
|
|
noteArray[distortion][atari note index][1] = note name
|
|
noteArray[distortion][atari note index][2] = octave
|
|
noteArray[distortion][atari note index][3] = frequency
|
|
noteArray[distortion][atari note index][4] = error
|
|
noteArray[distortion][atari note index][5] = MIDI note index *these last three values are used when creating the new MIDI file
|
|
noteArray[distortion][atari note index][6] = pitch bend- left bits
|
|
noteArray[distortion][atari note index][7] = pitch bend- right bits
|
|
noteArray[distortion][atari note index][8] = color
|
|
*/
|
|
|
|
if (isset($_POST['format']))
|
|
{
|
|
$c1 = explode("\n",$_POST['c1_display']);
|
|
$c2 = explode("\n",$_POST['c2_display']);
|
|
$c1_data = array();
|
|
$c2_data = array();
|
|
|
|
for ($i = 0; $i < count($c1); $i++)
|
|
if (str_word_count($c1[$i],0,"#.0123456789") == 4)
|
|
array_push($c1_data,explode(" ",$c1[$i]));
|
|
|
|
for ($i = 0; $i < count($c2); $i++)
|
|
if (str_word_count($c2[$i],0,"#.0123456789") == 4)
|
|
array_push($c2_data,explode(" ",$c2[$i]));
|
|
|
|
$total = 0;
|
|
$measureval = $_POST['timesig_num']/$_POST['timesig_de'];
|
|
$measure = 1;
|
|
$newvalue1 = "-------$measure-------\n"; //the value of the textarea gets set to this after the formatting is complete
|
|
$newvalue2 = "-------$measure-------\n";
|
|
|
|
foreach ($c1_data as $i => $arr)
|
|
{
|
|
$total += 1/$arr[3];
|
|
$newvalue1 .= $arr[0]." ".$arr[1]." ".$arr[2]." ".$arr[3];
|
|
//echo $i." ".$total."<br />";
|
|
if ($total >= $measureval)
|
|
{
|
|
$total -= $measureval;
|
|
//add a bar and a measure number to the display
|
|
$measure++;
|
|
$newvalue1 .= "-------$measure-------\n";
|
|
}
|
|
}
|
|
//exit;
|
|
$measure = 1;
|
|
$total = 0;
|
|
|
|
foreach ($c2_data as $i => $arr)
|
|
{
|
|
$total += 1/$arr[3];
|
|
$newvalue2 .= $arr[0]." ".$arr[1]." ".$arr[2]." ".$arr[3];
|
|
if ($total >= $measureval)
|
|
{
|
|
$total -= $measureval;
|
|
//add a bar and a measure number to the display
|
|
$measure++;
|
|
$newvalue2 .= "-------$measure-------\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
$dir = opendir("midi");
|
|
$note_array = array("square"=>array(),"lead"=>array(),"saw"=>array(),"bass"=>array());
|
|
|
|
while (($file = readdir($dir)) != null)
|
|
{
|
|
//format: distortion_atari note index_note name_octave_freq_error_MIDI note index_pitch bend left bits_pitch bend right bits
|
|
if (strpos($file,".ogg"))
|
|
{
|
|
$info = explode("_",$file);
|
|
$info[2] = str_replace("+","#",$info[2]);
|
|
$info[count($info)-1] = substr($info[count($info)-1],0,strpos($info[count($info)-1],".ogg"));
|
|
|
|
if (!isset($note_array[$info[0]][$info[1]]))
|
|
$note_array[$info[0]][$info[1]] = array();
|
|
|
|
array_push($note_array[$info[0]][$info[1]],$file);
|
|
for ($i = 2; $i < count($info); $i++)
|
|
array_push($note_array[$info[0]][$info[1]],$info[$i]);
|
|
|
|
|
|
$red = str_pad(dechex(100+2*$note_array[$info[0]][$info[1]][4]),2,"0",STR_PAD_LEFT);
|
|
$green = str_pad(dechex(150),2,"0",STR_PAD_LEFT);
|
|
$blue = str_pad(dechex(100-2*$note_array[$info[0]][$info[1]][4]),2,"0",STR_PAD_LEFT);
|
|
$color = $red.$green.$blue;
|
|
$note_array[$info[0]][$info[1]][8] = '#' . $color;
|
|
}
|
|
}
|
|
|
|
require ("createmidi.php");
|
|
?>
|
|
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>Atari 2600 Music Utility</title>
|
|
<meta name='description' content='Enables easier composing of Atari 2600 music.' />
|
|
<meta name='keywords' content='atari, 2600, music, composing, midi' />
|
|
<link rel='stylesheet' type='text/css' href='style.css' />
|
|
<script type='text/javascript'>
|
|
var noteValue = 4;
|
|
var channel = 1;
|
|
var showColor = false;
|
|
var dotted = false;
|
|
var bufferCount = 1;
|
|
<?php
|
|
if (isset($_POST['format']))
|
|
echo "var bufferMin = 3;";
|
|
else
|
|
echo "var bufferMin = 2;";
|
|
?>
|
|
|
|
//these were made global because javascript annoys me
|
|
var activeKeyID = 0;
|
|
var mouseX = 0;
|
|
var mouseY = 0;
|
|
|
|
var bufferArray = new Array(2);
|
|
bufferArray[0] = new Array();
|
|
bufferArray[1] = new Array();
|
|
bufferArray[0][0] = "";
|
|
bufferArray[1][0] = "";
|
|
|
|
|
|
var noteArray = new Array(4);
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
noteArray[i] = new Array(32);
|
|
for (j = 0; j < 32; j++)
|
|
{
|
|
noteArray[i][j] = new Array(8);
|
|
for (k = 0; k < 8; k++)
|
|
noteArray[i][j][k] = null;
|
|
}
|
|
}
|
|
|
|
//populate noteArray, copying values from $note_array
|
|
<?php
|
|
foreach ($note_array as $dist => $a)
|
|
foreach ($a as $atariIndex => $b)
|
|
foreach ($b as $i => $c)
|
|
{
|
|
if ($i == 0 || $i == 1 || $i == 8)
|
|
$c = "'$c'"; //convert to string
|
|
|
|
if ($dist == "square")
|
|
echo "noteArray[0][$atariIndex][$i] = $c;\n\t\t";
|
|
else if ($dist == "lead")
|
|
echo "noteArray[1][$atariIndex][$i] = $c;\n\t\t";
|
|
else if ($dist == "saw")
|
|
echo "noteArray[2][$atariIndex][$i] = $c;\n\t\t";
|
|
else if ($dist == "bass")
|
|
echo "noteArray[3][$atariIndex][$i] = $c;\n\t\t";
|
|
}
|
|
?>
|
|
</script>
|
|
<script type='text/javascript' src='functions.js'></script>
|
|
</head>
|
|
|
|
<body>
|
|
<?php
|
|
|
|
$xstart = 10;
|
|
$ystart = 33;
|
|
$numoctaves = 7;
|
|
$octavestart = 1;
|
|
|
|
$wwidth = 20;
|
|
$wheight = 70;
|
|
$bwidth = 16;
|
|
$bheight = 45;
|
|
|
|
$keyarr = array("C","C#","D","D#","E","F","F#","G","G#","A","A#","B");
|
|
|
|
$wcount = 0;
|
|
$bcount = 0;
|
|
|
|
for ($i = 0; $i < 12*$numoctaves; $i++)
|
|
{
|
|
$index = $i%12;
|
|
$octave = $octavestart+floor($i/12);
|
|
|
|
if (strpos($keyarr[$index],"#"))
|
|
{
|
|
$space = 0;
|
|
switch ($bcount%5)
|
|
{
|
|
case 0: $space = ($wwidth-$bwidth/2)+($wwidth*7*floor($i/12)); break;
|
|
case 1: $space = ($wwidth*2-$bwidth/2)+($wwidth*7*floor($i/12)); break;
|
|
case 2: $space = ($wwidth*4-$bwidth/2)+($wwidth*7*floor($i/12)); break;
|
|
case 3: $space = ($wwidth*5-$bwidth/2)+($wwidth*7*floor($i/12)); break;
|
|
case 4: $space = ($wwidth*6-$bwidth/2)+($wwidth*7*floor($i/12)); break;
|
|
}
|
|
|
|
$class = "bkey";
|
|
$top = $ystart;
|
|
$left = $xstart+$space;
|
|
$width = $bwidth;
|
|
$height = $bheight;
|
|
$bcount++;
|
|
}
|
|
else
|
|
{
|
|
$class = "wkey";
|
|
$top = $ystart;
|
|
$left = $xstart+$wwidth*$wcount;
|
|
$wcount++;
|
|
$width = $wwidth;
|
|
$height = $wheight;
|
|
}
|
|
|
|
//determine the atari note index of the key in question for all four distortions
|
|
$noteName = $keyarr[$index].$octave;
|
|
$atariIndex = array("square"=>"nil","lead"=>"nil","saw"=>"nil","bass"=>"nil");
|
|
foreach ($note_array as $dist => $a)
|
|
foreach ($a as $aIndex => $b)
|
|
if ($b[1] == $noteName)
|
|
{
|
|
$atariIndex[$dist] = $aIndex;
|
|
$color = "#".$b[8];
|
|
}
|
|
|
|
if ($noteName == "C4")
|
|
$class .= " C4";
|
|
|
|
echo "\t<button id='square_$atariIndex[square]' name='key' class='$class' style='position: absolute; top: $top"."px; left: $left"."px; height: $height"."px; width: $width"."px;' onclick='playNote(id)' oncontextmenu='return false;' onmousedown='if (event.button == 2) showFloatingDiv(id,event);'></button>\n";
|
|
echo "\t<button id='lead_$atariIndex[lead]' name='key' class='$class' style='position: absolute; top: ".($top+($wheight+$ystart))."px; left: $left"."px; height: $height"."px; width: $width"."px;' onclick='playNote(id)' oncontextmenu='return false;' onmousedown='if (event.button == 2) showFloatingDiv(id,event);'></button>\n";
|
|
echo "\t<button id='saw_$atariIndex[saw]' name='key' class='$class' style='position: absolute; top: ".($top+2*($wheight+$ystart))."px; left: $left"."px; height: $height"."px; width: $width"."px;' onclick='playNote(id)' oncontextmenu='return false;' onmousedown='if (event.button == 2) showFloatingDiv(id,event);'></button>\n";
|
|
echo "\t<button id='bass_$atariIndex[bass]' name='key' class='$class' style='position: absolute; top: ".($top+3*($wheight+$ystart))."px; left: $left"."px; height: $height"."px; width: $width"."px;' onclick='playNote(id)' oncontextmenu='return false;' onmousedown='if (event.button == 2) showFloatingDiv(id,event);'></button>\n";
|
|
}
|
|
|
|
echo "\n\n\t<span style='font-weight: bold; font-size: 14pt; position: absolute; top: ".($top-25)."px; left: ".(-20+($xstart+$wwidth*$numoctaves*7)/2)."px;'>Square</span>";
|
|
echo "\n\t<span style='font-weight: bold; font-size: 14pt; position: absolute; top: ".($top+($wheight+$ystart)-25)."px; left: ".(-20+($xstart+$wwidth*$numoctaves*7)/2)."px;'>Lead</span>";
|
|
echo "\n\t<span style='font-weight: bold; font-size: 14pt; position: absolute; top: ".($top+2*($wheight+$ystart)-25)."px; left: ".(-20+($xstart+$wwidth*$numoctaves*7)/2)."px;'>Saw</span>";
|
|
echo "\n\t<span style='font-weight: bold; font-size: 14pt; position: absolute; top: ".($top+3*($wheight+$ystart)-25)."px; left: ".(-20+($xstart+$wwidth*$numoctaves*7)/2)."px;'>Bass</span>\n\n";
|
|
echo "\n\t<div align='center' style='margin-top: ".(4 * ($wheight + $ystart))."px; width: ".($xstart+$wwidth*$numoctaves*7)."px'>\n";
|
|
|
|
echo "\n\t<span style='text-align: left; position: absolute; left: $xstart"."px; top:".(4*($wheight+$ystart))."px'>";
|
|
echo "\n\t\t<label title='[c]'><input type='checkbox' accesskey='c' onclick='toggleColor()' autocomplete='off' />Color Me Blind</label>";
|
|
echo "\n\t</span>";
|
|
echo "\n\t<span style='text-align: left; position: absolute; left: ".(-35+$xstart+$numoctaves*7*$wwidth)."px; top:".(4*($wheight+$ystart))."px'>";
|
|
echo "\n\t\t<a title='[q]' accesskey='q' onfocus='showFAQ()' href='javascript:void(0)'>FAQ</a>";
|
|
echo "\n\t</span>";
|
|
?>
|
|
|
|
|
|
<table border='0' align='center'>
|
|
|
|
<tr><td colspan='2'>
|
|
<table align='center'>
|
|
<tr>
|
|
<td><button accesskey='1' name='note-select' title='whole note [1]' class='note-select' onclick='selectNote(1)'><img src='img/1.gif' /></button></td>
|
|
<td><button accesskey='2' name='note-select' title='half note [2]' class='note-select' onclick='selectNote(2)'><img src='img/2.gif' /></button></td>
|
|
<td><button accesskey='3' name='note-select' title='quarter note [3]' class='note-select' onclick='selectNote(4)' disabled='disabled' style='cursor: default;'><img src='img/4.gif' /></button></td>
|
|
<td><button accesskey='4' name='note-select' title='8th note [4]' class='note-select' onclick='selectNote(8)'><img src='img/8.gif' /></button></td>
|
|
<td><button accesskey='5' name='note-select' title='16th note [5]' class='note-select' onclick='selectNote(16)'><img src='img/16.gif' /></button></td>
|
|
<td><button accesskey='6' name='note-select' title='32nd note [6]' class='note-select' onclick='selectNote(32)'><img src='img/32.gif' /></button></td>
|
|
<td><button accesskey='7' name='note-select' title='64th note [7]' class='note-select' onclick='selectNote(64)'><img src='img/64.gif' /></button></td>
|
|
<td><label title='dot [w]'><input type='checkbox' accesskey='w' onclick='setDotted()' />Dotted</label></td>
|
|
</tr>
|
|
<tr>
|
|
<td align='center'><button name='note-select' title='whole rest' class='rest-select' onclick='writeRestData(1)'><img src='img/r1.gif' /></button></td>
|
|
<td align='center'><button name='note-select' title='half rest' class='rest-select' onclick='writeRestData(2)'><img src='img/r2.gif' /></button></td>
|
|
<td align='center'><button name='note-select' title='quarter rest' class='rest-select' onclick='writeRestData(4)'><img src='img/r4.gif' /></button></td>
|
|
<td align='center'><button name='note-select' title='8th rest' class='rest-select' onclick='writeRestData(8)'><img src='img/r8.gif' /></button></td>
|
|
<td align='center'><button name='note-select' title='16th rest' class='rest-select' onclick='writeRestData(16)'><img src='img/r16.gif' /></button></td>
|
|
<td align='center'><button name='note-select' title='32nd rest' class='rest-select' onclick='writeRestData(32)'><img src='img/r32.gif' /></button></td>
|
|
<td align='center'><button name='note-select' title='64th rest' class='rest-select' onclick='writeRestData(64)'><img src='img/r64.gif' /></button></td>
|
|
</tr>
|
|
</table>
|
|
</td></tr>
|
|
|
|
<form name='createMidiForm' action='index.php' method='post' style='display: inline;'>
|
|
|
|
<tr>
|
|
<td colspan='2' align='center'>
|
|
Tempo:
|
|
<input type='text' name='tempo' id='tempo' size='2' maxlength='3' value='<?php if (isset($_POST['tempo'])) echo $_POST['tempo']; else echo "120";?>' onblur='validateForm()' />
|
|
Time Signature:
|
|
<input type='text' name='timesig_num' id='timesig_num' size='1' maxlength='3' value='<?php if (isset($_POST['timesig_num'])) echo $_POST['timesig_num']; else echo "1";?>' onblur='validateForm()' />
|
|
/ <select id='timesig_de' name='timesig_de'>
|
|
<option value='1' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 1) echo "selected='selected'";?>>1</option>
|
|
<option value='2' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 2) echo "selected='selected'";?>>2</option>
|
|
<option value='4' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 4) echo "selected='selected'";?>>4</option>
|
|
<option value='8' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 8) echo "selected='selected'";?>>8</option>
|
|
<option value='16' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 16) echo "selected='selected'";?>>16</option>
|
|
<option value='32' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 32) echo "selected='selected'";?>>32</option>
|
|
<option value='64' <?php if (isset($_POST['timesig_de']) && $_POST['timesig_de'] == 64) echo "selected='selected'";?>>64</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align='center'>
|
|
<label>
|
|
<input type='radio' name='channel_select' checked='checked' onclick='toggleChannel(1)' />
|
|
Channel 1
|
|
</label>
|
|
</td>
|
|
<td align='center'>
|
|
<label>
|
|
<input type='radio' name='channel_select' onclick='toggleChannel(2)' />
|
|
Channel 2
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<textarea rows='20' cols='25' id='c1_display' name='c1_display'><?php if (isset($_POST['format'])) echo $newvalue1; else if (isset($_POST['c1_display'])) echo $_POST['c1_display']; ?></textarea>
|
|
</td>
|
|
<td>
|
|
<textarea rows='20' cols='25' id='c2_display' name='c2_display'><?php if (isset($_POST['format'])) echo $newvalue2; else if (isset($_POST['c2_display'])) echo $_POST['c2_display'];?></textarea>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td align='center'><input style='cursor: pointer;' type='button' value='Clear' onclick='clearChannelData(1)' title='Clear channel 1 data'></input></td>
|
|
<td align='center'><input style='cursor: pointer;' type='button' value='Clear' onclick='clearChannelData(2)' title='Clear channel 2 data'></input></td>
|
|
</tr>
|
|
|
|
|
|
<tr><td colspan='2' align='center'>
|
|
<input style='color:#339966; font-family: Georgia; font-size: 150%; cursor: pointer;' type='submit' name='submit' value='Listen' title='Download the MIDI file'></input>
|
|
<input accesskey='f' style='color:#339966; font-family: Georgia; font-size: 150%; cursor: pointer;' type='submit' name='format' value='Format' title='Partition the measures [f]'></input>
|
|
<input accesskey='z' style='color:#339966; font-family: Georgia; font-size: 150%; cursor: pointer;' type='button' name='undo' value='Undo' onclick='undoLastKeypress()' title='Undo last keypress [z]'></input>
|
|
</td></tr>
|
|
|
|
</form>
|
|
</table>
|
|
</div>
|
|
|
|
<div id='floatDiv' class='floater' onclick='hideFloatingDiv()'></div>
|
|
|
|
<!-- FAQ -->
|
|
<div id='faq' class='faq' onclick='hideFAQ()'>
|
|
<h3>Shut the FAQ up</h3><br />
|
|
<span class='faq_q'>How do I close this pink window?</span>
|
|
<blockquote class='faq_a'>Click anywhere inside it.</blockquote>
|
|
<span class='faq_q'>Who? | What? | When? | Where? | Why?</span>
|
|
<blockquote class='faq_a'>
|
|
Tommy Montgomery |
|
|
Atari 2600 Music Composing Utility |
|
|
January, 2007 |
|
|
On the internet |
|
|
Why not
|
|
</blockquote>
|
|
<span class='faq_q'>How?</span>
|
|
<blockquote class='faq_a'>
|
|
An unholy union of PHP, Javascript and the HTML DOM. The MIDI files used to
|
|
play the sounds were created using Java because I didn't know PHP
|
|
could write to binary files at the time. 15 years later in April 2022
|
|
I converted them to OGG.
|
|
</blockquote>
|
|
<span class='faq_q'>Why is this useful?</span>
|
|
<blockquote class='faq_a'>
|
|
Writing music for the 2600 is difficult, because of the variations in
|
|
pitch. The frequencies don't conform to any sort of useful or intelligible
|
|
scale, so we have to approximate to get what we want. This utility makes
|
|
that process easier, by supplying a visual and aural cue of the
|
|
(musical) limitations of the 2600.
|
|
</blockquote>
|
|
<span class='faq_q'>Why are there four keyboards?</span>
|
|
<blockquote class='faq_a'>
|
|
The four keyboards correspond to the four "melodic" distortions (meaning
|
|
the ones that don't sound like noise). They are labeled for your
|
|
convenience. The grayed keys are notes whose frequencies are
|
|
unavailable in that distortion. Middle C is outlined in red.
|
|
</blockquote>
|
|
<span class='faq_q'>What about the other distortions?</span>
|
|
<blockquote class='faq_a'>
|
|
The primary reason I didn't include them is because there aren't any
|
|
MIDI voices that can approximate them. The secondary reason is because
|
|
this utility is for making <em>music</em>, not <em>noise</em>, which is
|
|
generally what the other distortions are used for; making noise is generally
|
|
much easier and doesn't need a fancy tool.
|
|
</blockquote>
|
|
<span class='faq_q'>How do I write songs?</span>
|
|
<blockquote class='faq_a'>
|
|
The Atari 2600 has two sound channels available (or so I've heard). The
|
|
two textareas at the bottom of the screen correspond to each channel. They are
|
|
labeled for your convenience. When you click on a key, you will hear its sound and the
|
|
data will be written to the channel's textarea (that data can also be typed in
|
|
manually). To listen to your song, press "Listen." The best way to learn how
|
|
to use this is to experiment. Use the "Format" and "Listen" buttons liberally.
|
|
</blockquote>
|
|
<span class='faq_q'>What does "Format" do?</span>
|
|
<blockquote class='faq_a'>
|
|
Pressing this button formats each channel's data into something more
|
|
comprehensible. It groups all the data into measures (this is dependent
|
|
on the time signature).
|
|
</blockquote>
|
|
<span class='faq_q'>How do I change the note value/channel/tempo/time signature?</span>
|
|
<blockquote class='faq_a'>
|
|
Find the labels and/or pictures and click something until it does what you want.
|
|
</blockquote>
|
|
<span class='faq_q'>How do I insert a rest in my song?</span>
|
|
<blockquote class='faq_a'>
|
|
See above.
|
|
</blockquote>
|
|
<span class='faq_q'>What does "Dotted" do?</span>
|
|
<blockquote class='faq_a'>
|
|
Checking this elongates the note by 50%.
|
|
</blockquote>
|
|
<span class='faq_q'>What do all the numbers in the textareas mean?</span>
|
|
<blockquote class='faq_a'>
|
|
<ul>
|
|
<li>The first thing is the note name and octave (e.g. <code>E3</code>).</li>
|
|
<li>The second thing is the distortion (<code>0</code> = square, <code>1</code> =
|
|
lead, <code>2</code> = saw, <code>3</code> = bass. Note that these do <em>not</em>
|
|
correspond to the distortion numbers in the text file linked to below).</li>
|
|
<li>The third thing is the pitch index, mentioned below.</li>
|
|
<li>The last thing is the note value (<code>1</code> = whole note, <code>2</code> =
|
|
half note, <code>4</code> = quarter note, etc.).</li>
|
|
</ul>
|
|
</blockquote>
|
|
<span class='faq_q'>I know stuff about some stuff. How do I look at this stuff?</span>
|
|
<blockquote class='faq_a'>
|
|
Right click on a key to view info about that note (doesn't work in Opera). <code>Pitch</code> is the
|
|
Atari 2600 pitch index (see <a href='http://home.arcor.de/estolberg/texts/freqform.txt'>here</a>
|
|
for details); <code>Freq</code> is the note's frequency; <code>Error</code> is the
|
|
distance in cents from "perfect" pitch. If you don't know what that means, the closer
|
|
to 0 is better. Unless you're doing something weird and/or painful, you'll want
|
|
all the notes in your song to have approximately the same error.
|
|
</blockquote>
|
|
<span class='faq_q'>What does "Exchange" mean?</span>
|
|
<blockquote class='faq_a'>
|
|
Some notes have more than one frequency that approximates that note. Clicking on
|
|
"Exchange" toggles between the two. Such notes are generally in the lower half
|
|
of the keyboard.
|
|
</blockquote>
|
|
<span class='faq_q'>What does "Color Me Blind" do?</span>
|
|
<blockquote class='faq_a'>
|
|
Checking this color codes all the keys. Keys with the same color are in tune
|
|
with each other. Keys that are different colors probably shouldn't be used in
|
|
succession.
|
|
</blockquote>
|
|
<span class='faq_q'>Dude, seriously. Using the mouse is a bother. Are there any keyboard shortcuts?</span>
|
|
<blockquote class='faq_a'>
|
|
Glad you asked. If you hover the cursor over various objects on the page, you'll notice
|
|
a single character in square brackets in the tooltip for some of them (try one of the
|
|
note value buttons, for example). Check
|
|
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/accesskey">here</a>
|
|
to see your access key combination (generally <code>ALT</code> or <code>ALT+SHIFT</code>).
|
|
</blockquote>
|
|
</div>
|
|
<!-- END FAQ -->
|
|
|
|
<script type='text/javascript'>disableNils();</script>
|
|
<audio id='sound'></audio>
|
|
|
|
</body>
|
|
</html>
|