386 lines
13 KiB
Python
386 lines
13 KiB
Python
|
import unittest
|
||
|
import os
|
||
|
import sys
|
||
|
import time
|
||
|
|
||
|
import pygame
|
||
|
import pygame.midi
|
||
|
import pygame.compat
|
||
|
from pygame.locals import *
|
||
|
|
||
|
|
||
|
class MidiInputTest(unittest.TestCase):
|
||
|
|
||
|
def setUp(self):
|
||
|
pygame.midi.init()
|
||
|
in_id = pygame.midi.get_default_input_id()
|
||
|
if in_id != -1:
|
||
|
self.midi_input = pygame.midi.Input(in_id)
|
||
|
else:
|
||
|
self.midi_input = None
|
||
|
|
||
|
def tearDown(self):
|
||
|
if self.midi_input:
|
||
|
self.midi_input.close()
|
||
|
pygame.midi.quit()
|
||
|
|
||
|
def test_Input(self):
|
||
|
"""|tags: interactive|
|
||
|
"""
|
||
|
|
||
|
i = pygame.midi.get_default_input_id()
|
||
|
if self.midi_input:
|
||
|
self.assertEqual(self.midi_input.device_id, i)
|
||
|
|
||
|
# try feeding it an input id.
|
||
|
i = pygame.midi.get_default_output_id()
|
||
|
|
||
|
# can handle some invalid input too.
|
||
|
self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, i)
|
||
|
self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, 9009)
|
||
|
self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, -1)
|
||
|
self.assertRaises(TypeError, pygame.midi.Input, "1234")
|
||
|
self.assertRaises(OverflowError, pygame.midi.Input, pow(2, 99))
|
||
|
|
||
|
def test_poll(self):
|
||
|
|
||
|
if not self.midi_input:
|
||
|
self.skipTest('No midi Input device')
|
||
|
|
||
|
self.assertFalse(self.midi_input.poll())
|
||
|
# TODO fake some incoming data
|
||
|
|
||
|
pygame.midi.quit()
|
||
|
self.assertRaises(RuntimeError, self.midi_input.poll)
|
||
|
# set midi_input to None to avoid error in tearDown
|
||
|
self.midi_input = None
|
||
|
|
||
|
def test_read(self):
|
||
|
|
||
|
if not self.midi_input:
|
||
|
self.skipTest('No midi Input device')
|
||
|
|
||
|
read = self.midi_input.read(5)
|
||
|
self.assertEqual(read, [])
|
||
|
# TODO fake some incoming data
|
||
|
|
||
|
pygame.midi.quit()
|
||
|
self.assertRaises(RuntimeError, self.midi_input.read, 52)
|
||
|
# set midi_input to None to avoid error in tearDown
|
||
|
self.midi_input = None
|
||
|
|
||
|
def test_close(self):
|
||
|
if not self.midi_input:
|
||
|
self.skipTest('No midi Input device')
|
||
|
|
||
|
self.assertIsNotNone(self.midi_input._input)
|
||
|
self.midi_input.close()
|
||
|
self.assertIsNone(self.midi_input._input)
|
||
|
|
||
|
|
||
|
class MidiOutputTest(unittest.TestCase):
|
||
|
|
||
|
def setUp(self):
|
||
|
pygame.midi.init()
|
||
|
m_out_id = pygame.midi.get_default_output_id()
|
||
|
if m_out_id != -1:
|
||
|
self.midi_output = pygame.midi.Output(m_out_id)
|
||
|
else:
|
||
|
self.midi_output = None
|
||
|
|
||
|
def tearDown(self):
|
||
|
if self.midi_output:
|
||
|
self.midi_output.close()
|
||
|
pygame.midi.quit()
|
||
|
|
||
|
def test_Output(self):
|
||
|
"""|tags: interactive|
|
||
|
"""
|
||
|
i = pygame.midi.get_default_output_id()
|
||
|
if self.midi_output:
|
||
|
self.assertEqual(self.midi_output.device_id, i)
|
||
|
|
||
|
# try feeding it an input id.
|
||
|
i = pygame.midi.get_default_input_id()
|
||
|
|
||
|
# can handle some invalid input too.
|
||
|
self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, i)
|
||
|
self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, 9009)
|
||
|
self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, -1)
|
||
|
self.assertRaises(TypeError, pygame.midi.Output,"1234")
|
||
|
self.assertRaises(OverflowError, pygame.midi.Output, pow(2,99))
|
||
|
|
||
|
def test_note_off(self):
|
||
|
"""|tags: interactive|
|
||
|
"""
|
||
|
|
||
|
if self.midi_output:
|
||
|
out = self.midi_output
|
||
|
out.note_on(5, 30, 0)
|
||
|
out.note_off(5, 30, 0)
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.note_off(5, 30, 25)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.note_off(5, 30, -1)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
|
||
|
def test_note_on(self):
|
||
|
"""|tags: interactive|
|
||
|
"""
|
||
|
|
||
|
if self.midi_output:
|
||
|
out = self.midi_output
|
||
|
out.note_on(5, 30, 0)
|
||
|
out.note_on(5, 42, 10)
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.note_on(5, 30, 25)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.note_on(5, 30, -1)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
|
||
|
def test_set_instrument(self):
|
||
|
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
out = self.midi_output
|
||
|
out.set_instrument(5)
|
||
|
out.set_instrument(42, channel=2)
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.set_instrument(-6)
|
||
|
self.assertEqual(str(cm.exception), "Undefined instrument id: -6")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.set_instrument(156)
|
||
|
self.assertEqual(str(cm.exception), "Undefined instrument id: 156")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.set_instrument(5, -1)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.set_instrument(5, 16)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
|
||
|
def test_write(self):
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
|
||
|
out = self.midi_output
|
||
|
out.write([[[0xc0, 0, 0], 20000]])
|
||
|
# is equivalent to
|
||
|
out.write([[[0xc0], 20000]])
|
||
|
# example from the docstring :
|
||
|
# 1. choose program change 1 at time 20000 and
|
||
|
# 2. send note 65 with velocity 100 500 ms later
|
||
|
out.write([
|
||
|
[[0xc0, 0, 0], 20000],
|
||
|
[[0x90, 60, 100], 20500]
|
||
|
])
|
||
|
|
||
|
out.write([])
|
||
|
verrry_long = [[[0x90, 60, i % 100], 20000 + 100 * i] for i in range(1024)]
|
||
|
out.write(verrry_long)
|
||
|
|
||
|
too_long = [[[0x90, 60, i % 100], 20000 + 100 * i] for i in range(1025)]
|
||
|
self.assertRaises(IndexError, out.write, too_long)
|
||
|
# test wrong data
|
||
|
with self.assertRaises(TypeError) as cm:
|
||
|
out.write('Non sens ?')
|
||
|
error_msg = "unsupported operand type(s) for &: 'str' and 'int'"
|
||
|
self.assertEqual(str(cm.exception), error_msg)
|
||
|
|
||
|
with self.assertRaises(TypeError) as cm:
|
||
|
out.write(["Hey what's that?"])
|
||
|
self.assertEqual(str(cm.exception), error_msg)
|
||
|
|
||
|
def test_write_short(self):
|
||
|
"""|tags: interactive|
|
||
|
"""
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
|
||
|
out = self.midi_output
|
||
|
# program change
|
||
|
out.write_short(0xc0)
|
||
|
# put a note on, then off.
|
||
|
out.write_short(0x90, 65, 100)
|
||
|
out.write_short(0x80, 65, 100)
|
||
|
out.write_short(0x90)
|
||
|
|
||
|
def test_write_sys_ex(self):
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
|
||
|
out = self.midi_output
|
||
|
out.write_sys_ex(pygame.midi.time(),
|
||
|
[0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])
|
||
|
|
||
|
def test_pitch_bend(self):
|
||
|
# FIXME : pitch_bend in the code, but not in documentation
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
|
||
|
out = self.midi_output
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.pitch_bend(5, channel=-1)
|
||
|
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.pitch_bend(5, channel=16)
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.pitch_bend(-10001, 1)
|
||
|
self.assertEqual(str(cm.exception), "Pitch bend value must be between "
|
||
|
"-8192 and +8191, not -10001.")
|
||
|
with self.assertRaises(ValueError) as cm:
|
||
|
out.pitch_bend(10665, 2)
|
||
|
|
||
|
def test_close(self):
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
self.assertIsNotNone(self.midi_output._output)
|
||
|
self.midi_output.close()
|
||
|
self.assertIsNone(self.midi_output._output)
|
||
|
|
||
|
def test_abort(self):
|
||
|
if not self.midi_output:
|
||
|
self.skipTest('No midi device')
|
||
|
self.assertEqual(self.midi_output._aborted, 0)
|
||
|
self.midi_output.abort()
|
||
|
self.assertEqual(self.midi_output._aborted, 1)
|
||
|
|
||
|
|
||
|
class MidiModuleTest(unittest.TestCase):
|
||
|
|
||
|
def setUp(self):
|
||
|
pygame.midi.init()
|
||
|
|
||
|
def tearDown(self):
|
||
|
pygame.midi.quit()
|
||
|
|
||
|
def test_MidiException(self):
|
||
|
|
||
|
def raiseit():
|
||
|
raise pygame.midi.MidiException('Hello Midi param')
|
||
|
|
||
|
with self.assertRaises(pygame.midi.MidiException) as cm:
|
||
|
raiseit()
|
||
|
self.assertEqual(cm.exception.parameter, 'Hello Midi param')
|
||
|
|
||
|
def test_get_count(self):
|
||
|
c = pygame.midi.get_count()
|
||
|
self.assertIsInstance(c, int)
|
||
|
self.assertTrue(c >= 0)
|
||
|
|
||
|
def test_get_default_input_id(self):
|
||
|
|
||
|
midin_id = pygame.midi.get_default_input_id()
|
||
|
# if there is a not None return make sure it is an int.
|
||
|
self.assertIsInstance(midin_id, int)
|
||
|
self.assertTrue(midin_id >= -1)
|
||
|
pygame.midi.quit()
|
||
|
self.assertRaises(RuntimeError, pygame.midi.get_default_output_id)
|
||
|
|
||
|
def test_get_default_output_id(self):
|
||
|
|
||
|
c = pygame.midi.get_default_output_id()
|
||
|
self.assertIsInstance(c, int)
|
||
|
self.assertTrue(c >= -1)
|
||
|
pygame.midi.quit()
|
||
|
self.assertRaises(RuntimeError, pygame.midi.get_default_output_id)
|
||
|
|
||
|
def test_get_device_info(self):
|
||
|
|
||
|
an_id = pygame.midi.get_default_output_id()
|
||
|
if an_id != -1:
|
||
|
interf, name, input, output, opened = pygame.midi.get_device_info(an_id)
|
||
|
self.assertEqual(output, 1)
|
||
|
self.assertEqual(input, 0)
|
||
|
self.assertEqual(opened, 0)
|
||
|
|
||
|
an_in_id = pygame.midi.get_default_input_id()
|
||
|
if an_in_id != -1:
|
||
|
r = pygame.midi.get_device_info(an_in_id)
|
||
|
# if r is None, it means that the id is out of range.
|
||
|
interf, name, input, output, opened = r
|
||
|
|
||
|
self.assertEqual(output, 0)
|
||
|
self.assertEqual(input, 1)
|
||
|
self.assertEqual(opened, 0)
|
||
|
out_of_range = pygame.midi.get_count()
|
||
|
for num in range(out_of_range):
|
||
|
self.assertIsNotNone(pygame.midi.get_device_info(num))
|
||
|
info = pygame.midi.get_device_info(out_of_range)
|
||
|
self.assertIsNone(info)
|
||
|
|
||
|
def test_init(self):
|
||
|
|
||
|
pygame.midi.quit()
|
||
|
self.assertRaises(RuntimeError, pygame.midi.get_count)
|
||
|
# initialising many times should be fine.
|
||
|
pygame.midi.init()
|
||
|
pygame.midi.init()
|
||
|
pygame.midi.init()
|
||
|
pygame.midi.init()
|
||
|
|
||
|
self.assertTrue(pygame.midi.get_init())
|
||
|
|
||
|
def test_midis2events(self):
|
||
|
|
||
|
midi_data = ([[0xc0, 0, 1, 2], 20000],
|
||
|
[[0x90, 60, 100, 'blablabla'], 20000]
|
||
|
)
|
||
|
events = pygame.midi.midis2events(midi_data, 2)
|
||
|
self.assertEqual(len(events), 2)
|
||
|
|
||
|
for eve in events:
|
||
|
# pygame.event.Event is a function, but ...
|
||
|
self.assertEqual(eve.__class__.__name__, 'Event')
|
||
|
self.assertEqual(eve.vice_id, 2)
|
||
|
# FIXME I don't know what we want for the Event.timestamp
|
||
|
# For now it accepts it accepts int as is:
|
||
|
self.assertIsInstance(eve.timestamp, int)
|
||
|
self.assertEqual(eve.timestamp, 20000)
|
||
|
self.assertEqual(events[1].data3, 'blablabla')
|
||
|
|
||
|
def test_quit(self):
|
||
|
|
||
|
# It is safe to call this more than once.
|
||
|
pygame.midi.quit()
|
||
|
pygame.midi.init()
|
||
|
pygame.midi.quit()
|
||
|
pygame.midi.quit()
|
||
|
pygame.midi.init()
|
||
|
pygame.midi.init()
|
||
|
pygame.midi.quit()
|
||
|
|
||
|
self.assertFalse(pygame.midi.get_init())
|
||
|
|
||
|
def test_get_init(self):
|
||
|
# Already initialized as pygame.midi.init() was called in setUp().
|
||
|
self.assertTrue(pygame.midi.get_init())
|
||
|
|
||
|
def test_time(self):
|
||
|
|
||
|
mtime = pygame.midi.time()
|
||
|
self.assertIsInstance(mtime, int)
|
||
|
# should be close to 2-3... since the timer is just init'd.
|
||
|
self.assertTrue(0 <= mtime < 100)
|
||
|
|
||
|
|
||
|
def test_conversions(self):
|
||
|
""" of frequencies to midi note numbers and ansi note names.
|
||
|
"""
|
||
|
from pygame.midi import (
|
||
|
frequency_to_midi, midi_to_frequency, midi_to_ansi_note
|
||
|
)
|
||
|
self.assertEqual(frequency_to_midi(27.5), 21)
|
||
|
self.assertEqual(frequency_to_midi(36.7), 26)
|
||
|
self.assertEqual(frequency_to_midi(4186.0), 108)
|
||
|
self.assertEqual(midi_to_frequency(21), 27.5)
|
||
|
self.assertEqual(midi_to_frequency(26), 36.7)
|
||
|
self.assertEqual(midi_to_frequency(108), 4186.0)
|
||
|
self.assertEqual(midi_to_ansi_note(21), 'A0')
|
||
|
self.assertEqual(midi_to_ansi_note(102), 'F#7')
|
||
|
self.assertEqual(midi_to_ansi_note(108), 'C8')
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
unittest.main()
|