Música codificada

L’exercici que ve a continuació, usa una codificació semblant al MIDI per representar partitures de música. La codificació que presentem seguirà els següents convenis:

La nota musical es representa per un enter de 0 fins 127. El silenci (cap nota) vindrà donat per l’enter 128. A la taula següent teniu una relació del nom de la nota (C, C#, D, D#, E, F, F#, G, G#, A, A#, B) i la seva correspondència amb l’enter que la representa i la octava on està.

Nota/Octava

-1

0

1

2

3

4

5

6

7

8

9

C

0

12

24

36

48

60

72

84

96

108

120

C# / Db

1

13

25

37

49

61

73

85

97

109

121

D

2

14

26

38

50

62

74

86

98

110

122

D# / Eb

3

15

27

39

51

63

75

87

99

111

123

E

4

16

28

40

52

64

76

88

100

112

124

F

5

17

29

41

53

65

77

89

101

113

125

F# / Gb

6

18

30

42

54

66

78

90

102

114

126

G

7

19

31

43

55

67

79

91

103

115

127

G# / Ab

8

20

32

44

56

68

80

92

104

116

A

9

21

33

45

57

69

81

93

105

117

A# / Bb

10

22

34

46

58

70

82

94

106

118

B

11

23

35

47

59

71

83

95

107

119

Suposem que disposem d’una llista d”strings que conté els noms de les notes, com notes en l’exemple següent:

>>> notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'Fa#', 'G',
... 'G#', 'A', 'A#', 'B']

Aleshores, donada una nota (un nombre natural), es pot calcular el seu nom indexant la llista (notes en l’exemple anterior) amb el residu de la divisió entera per 12. Per exemple, el nom de la nota 40 és mi (E) perquè 40 % 12 == 4 i notes[4] == 'E'. La octava de la nota 40 és (40 / 12) - 1 == 2.

Alternativament, si la taula conté:

>>> notes = ['do', 'do#', 're', 're#', 'mi', 'fa', 'fa#', 'sol',
... 'sol#', 'la', 'la#', 'si']

notes[4]==”mi” en l’exemple anterior.

La durada d’una nota es codifica per un enter d’acord amb la taula que trobareu a continuació:

rodona

blanca

negra

corxera

semicorxera

fusa

semifusa

garrapatea

semigarrapatea

256

128

64

32

16

8

4

2

1

On podem veure que la mínima unitat de temps és la semigarrapatea.

A partir d’aquí, proposem que resolguis el següent enunciat:

Decodificador

  1. En el fitxer notes.py, dissenyeu les classes Notes i NotesUK que permetran convertir un iterador de tuples de codis de notes i temps a un iterador de tuples de noms de notes i de temps. La diferència entre les dues classes rau amb el nom que li donen les notes.

    Per exemple,

    >>> import notes
    >>> part= [(48,256),(50,128),(52,64),(53,32),(55,16),(57,8),(59,4),(60,2),(62,1)]
    >>> for nota in notes.Notes(iter(part)):
    ...     print(nota, end='-')
    ... 
    ('do4', 'r')-('re4', 'b')-('mi4', 'n')-('fa4', 'c')-('sol4', 'sc')-('la4', 'f')-('si4', 'sf')-('do5', 'g')-('re5', 'sg')-
    >>> for nota in notes.NotesUK(iter(part)):
    ...     print(nota, end='-')
    ... 
    ('c4', 'r')-('d4', 'b')-('e4', 'n')-('f4', 'c')-('g4', 'sc')-('a4', 'f')-('b4', 'sf')-('c5', 'g')-('d5', 'sg')-
    >>> partMiM= [ (n + 25, t ) for n, t in part ]
    >>> for nota in notes.Notes(iter(partMiM)):
    ...     print(nota, end='-')
    ... 
    ('do6#', 'r')-('re6#', 'b')-('fa6', 'n')-('fa6#', 'c')-('sol6#', 'sc')-('la6#', 'f')-('do7', 'sf')-('do7#', 'g')-('re7#', 'sg')-
    
    
    class notes.Notes(codi)

    A partir de l’iterador codi genera un objecte iterable de tuples amb el nom llatí de la nota i nom de temps que representen els dos valors de les tuples de l’iterador codi.

    Atributs de classe:

    notes
    notes = ['do', 'do#', 're', 're#', 'mi', 'fa', 'fa#',
             'sol', 'sol#', 'la', 'la#', 'si']
    
    durades
    durades = {256: 'r', 128: 'b', 64: 'n', 32: 'c', 16: 'sc',
                 8: 'f', 4: 'sf', 2: 'g', 1: 'sg'}
    
    class notes.NotesUK(codi)

    A partir de l’iterador codi genera un objecte iterable de tuples amb el nom anglosaxó de la nota i nom de temps que representen els dos valors de les tuples de l’iterador codi.

    Atributs de classe:

    notes
    notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#',
             'G', 'G#', 'A', 'A#', 'B']
    
    durades

    de valor idèntic al de la classe Notes.

  2. Ens cal definir dos mètodes per la classe: __init__ on guardarem com a atribut el paràmetre codi, i el mètode __iter__ on escriurem un generador que faci l’iterador demanat.

    La classe NotesUK es dissenya heretant Notes.