Finished
11class Scale:
22 def __init__(self, tonic):
3 pass
3 # Edge Case: Normalize tonic to handle case insensitivity
4 # Preserve the original case to distinguish between major (uppercase) and minor (lowercase) keys
5 self.tonic = tonic
6
7 # Edge Case: Handle special case for flat symbol in tonic
8 if len(self.tonic) > 1 and self.tonic[1] == 'b':
9 self.tonic = self.tonic[0].upper() + 'b'
10
11 # Define the chromatic scales with sharps and flats (using ASCII symbols)
12 self.sharp_chromatic = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']
13 self.flat_chromatic = ['A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab']
14
15 # Keys that use flats (according to specification table)
16 # Flat: F, B♭, E♭, A♭, D♭, G♭ and d, g, c, f, b♭, e♭
17 self.flat_keys = {'F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'd', 'g', 'c', 'f', 'bb', 'eb'}
18
19 # Determine whether to use flats or sharps
20 # Edge Case: C and a follow sharps convention for ascending scale
21 if self.tonic in self.flat_keys:
22 self.chromatic_scale = self.flat_chromatic
23 else:
24 self.chromatic_scale = self.sharp_chromatic
25
26 # Edge Case: Handle enharmonic equivalents for tonics like 'Bb' or 'A#'
27 # Find the tonic in the selected scale
28 # Use uppercase version for lookup since scales contain uppercase notes
29 # For single letters, just uppercase them. For multi-character, uppercase the first letter.
30 lookup_tonic = self.tonic.upper() if len(self.tonic) == 1 else self.tonic[0].upper() + self.tonic[1:]
31 try:
32 self.tonic_index = self.chromatic_scale.index(lookup_tonic)
33 except ValueError:
34 # If not found, try to find enharmonic equivalent
35 # This handles cases like 'A#' when using flats or 'Bb' when using sharps
36 if self.chromatic_scale is self.sharp_chromatic:
37 enharmonic_map = {'Bb': 'A#', 'Db': 'C#', 'Eb': 'D#', 'Gb': 'F#', 'Ab': 'G#'}
38 if self.tonic in enharmonic_map:
39 self.tonic = enharmonic_map[self.tonic]
40 else: # flat_chromatic
41 enharmonic_map = {'A#': 'Bb', 'C#': 'Db', 'D#': 'Eb', 'F#': 'Gb', 'G#': 'Ab'}
42 if self.tonic in enharmonic_map:
43 self.tonic = enharmonic_map[self.tonic]
44
45 try:
46 self.tonic_index = self.chromatic_scale.index(lookup_tonic)
47 except ValueError:
48 # Edge Case: Invalid tonic note
49 raise ValueError(f"Invalid tonic: {tonic}")
450
551 def chromatic(self):
6 pass
7
52 # Return the chromatic scale starting with the tonic
53 # All notes should be uppercase except for "b" in flats
54 scale = [self.chromatic_scale[(self.tonic_index + i) % 12] for i in range(12)]
55 return [note.upper() if len(note) == 1 else note[0].upper() + note[1:] for note in scale]
56
857 def interval(self, intervals):
9 pass
58 # Edge Case: Empty interval pattern
59 if not intervals:
60 return [self.tonic.upper() if len(self.tonic) == 1 else self.tonic[0].upper() + self.tonic[1:]]
61
62 # Define interval steps
63 interval_steps = {'m': 1, 'M': 2, 'A': 3}
64
65 # Start with properly formatted tonic
66 first_note = self.tonic.upper() if len(self.tonic) == 1 else self.tonic[0].upper() + self.tonic[1:]
67 result = [first_note]
68 current_index = self.tonic_index
69
70 # Edge Case: Invalid interval characters
71 for interval in intervals:
72 if interval not in interval_steps:
73 raise ValueError(f"Invalid interval: {interval}")
74
75 step = interval_steps[interval]
76 current_index = (current_index + step) % 12
77 note = self.chromatic_scale[current_index]
78 # Format note: uppercase except for "b" in flats
79 formatted_note = note.upper() if len(note) == 1 else note[0].upper() + note[1:]
80 result.append(formatted_note)
81
82 return result
83# Handled Edge Cases: Invalid tonic notes, Empty interval patterns, Case sensitivity, Enharmonic equivalents, Invalid interval characters
Test NameStatus
test_chromatic_scale_with_flats
Pass
test_chromatic_scale_with_sharps
Pass
test_dorian_mode
Pass
test_enigmatic
Pass
test_harmonic_minor
Pass
test_hexatonic
Pass
test_locrian_mode
Pass
test_lydian_mode
Pass
test_major_scale_with_flats
Pass
test_major_scale_with_sharps
Pass
test_minor_scale_with_flats
Pass
test_minor_scale_with_sharps
Pass
test_mixolydian_mode
Pass
test_octatonic
Pass
test_pentatonic
Pass
test_phrygian_mode
Pass
test_simple_major_scale
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.