Skip to content

Instantly share code, notes, and snippets.

@andlima
Created March 14, 2011 02:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andlima/868657 to your computer and use it in GitHub Desktop.
Save andlima/868657 to your computer and use it in GitHub Desktop.
Simple ear training script
import math
import time
import ossaudiodev
import random
# Simple ear training script - by Andre Lima
#
# This program is based on code from:
#
# tone.py - Single / Dual Tone Generator
# Copyright (C) 2006-2009 Martin S. Ewing, AA6E
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
LA = 440.
SEMI_TONE = 2 ** (1/12.0)
TONE = 2 ** (1/6.0)
AMP = 50.
DSP = '/dev/dsp'
def f_sin(i, a, f1, bl):
aa = a * 32.767
o = 2.0 * math.pi / float(bl)
v = aa * math.sin(f1*i*o)
v *= 2
return v
def do_sound(afout, f1, times):
buflen = int(times * afout.bufsize() / 8)
fmin = float(speed) / float(buflen)
ff1 = round(f1 / fmin)
data = ''
aa = 32767.0 * (AMP / 100.0)
oo = 2.0 * math.pi / float(buflen)
for iy in range(buflen):
vv = f_sin(iy, AMP, ff1, buflen)
val = int(vv)
c1 = chr(val & 0xff)
c2 = chr((val & 0xff00) >> 8)
data = data + c1 + c2
afout.write(data)
while afout.obufcount() > 0:
time.sleep(0.01)
def get_guess(text):
raw_guess = raw_input(text)
try:
return int(raw_guess)
except ValueError:
return raw_guess
if __name__ == '__main__':
speeds = {1: 8000, 2: 11025, 3: 22050, 4: 44100, 5: 96000}
speed = speeds[4]
base = LA * (SEMI_TONE ** 3)
notes = ["do", "do#", "re", "re#", "mi", "fa", "fa#",
"sol", "sol#", "la", "la#", "si"]
pitches = []
pitch = {}
for i, note in enumerate(notes):
pitch[note] = base * (SEMI_TONE ** i)
pitches.append(pitch[note])
afout = ossaudiodev.open(DSP, 'w')
afout.setparameters(ossaudiodev.AFMT_S16_LE, 0, speed)
do_major_scale = [x for x in notes if "#" not in x]
options = [0, 2, 4, 6]
print options
count, good = 0, 0
while True:
d = random.choice(options)
do_sound(afout, pitches[0], 1)
do_sound(afout, pitches[d], 1)
guess = get_guess("Guess: ")
while guess not in options:
if guess == "?":
print "Repeating sound..."
do_sound(afout, pitches[0], 1)
do_sound(afout, pitches[d], 1)
elif guess == "!":
print "Exiting..."
exit(0)
else:
print "(Invalid option: %s)" % str(guess)
guess = get_guess("Guess: ")
print "Actual:", d,
count += 1
if d == guess:
print " (Good!)"
good += 1
else:
print " (Sorry...)"
print "Score: %d/%d (%d%%)." % (good, count, int(float(good)*100/count))
print
afout.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment