@@ -23,6 +23,7 @@ global._ = jest.fn(str => str);
2323global . window = {
2424 btoa : jest . fn ( str => Buffer . from ( str , "utf8" ) . toString ( "base64" ) )
2525} ;
26+ global . INVALIDPITCH = "Not a valid pitch name" ;
2627
2728const {
2829 scaleDegreeToPitchMapping,
@@ -97,14 +98,15 @@ const {
9798 numberToPitchSharp,
9899 getNumber,
99100 getNoteFromInterval,
100- numberToPitch,
101- GetNotesForInterval,
102- base64Encode,
103- NOTESFLAT ,
104101 NOTESSHARP ,
105102 MUSICALMODES ,
106103 getStepSizeUp,
107- getStepSizeDown
104+ getStepSizeDown,
105+ INVALIDPITCH ,
106+ numberToPitch,
107+ GetNotesForInterval,
108+ base64Encode,
109+ NOTESFLAT
108110} = require ( "../musicutils" ) ;
109111
110112describe ( "musicutils" , ( ) => {
@@ -2241,39 +2243,6 @@ describe("getPitchInfo", () => {
22412243 } ) ;
22422244} ) ;
22432245
2244- describe ( "_calculate_pitch_number" , ( ) => {
2245- let activity , tur ;
2246-
2247- beforeEach ( ( ) => {
2248- activity = {
2249- errorMsg : jest . fn ( )
2250- } ;
2251-
2252- tur = {
2253- singer : {
2254- lastNotePlayed : null ,
2255- inNoteBlock : { } ,
2256- notePitches : { } ,
2257- noteOctaves : { } ,
2258- keySignature : "C major" ,
2259- movable : false ,
2260- pitchNumberOffset : 0
2261- }
2262- } ;
2263- } ) ;
2264-
2265- it ( "calculates pitch number for a standard note string" , ( ) => {
2266- const val = _calculate_pitch_number ( activity , "C4" , tur ) ;
2267- expect ( typeof val ) . toBe ( "number" ) ;
2268- } ) ;
2269-
2270- it ( "calculates pitch number relative to another note" , ( ) => {
2271- const valC4 = _calculate_pitch_number ( activity , "C4" , tur ) ;
2272- const valC5 = _calculate_pitch_number ( activity , "C5" , tur ) ;
2273- expect ( valC5 ) . toBeGreaterThan ( valC4 ) ;
2274- } ) ;
2275- } ) ;
2276-
22772246describe ( "NOTESFLAT" , ( ) => {
22782247 it ( "should contain 12 chromatic notes" , ( ) => {
22792248 expect ( NOTESFLAT . length ) . toBe ( 12 ) ;
@@ -2404,3 +2373,96 @@ describe("getStepSizeUp", () => {
24042373 expect ( result ) . toBe ( 0 ) ;
24052374 } ) ;
24062375} ) ;
2376+
2377+ describe ( "_calculate_pitch_number" , ( ) => {
2378+ it ( "should return the correct pitch number for common notes" , ( ) => {
2379+ expect ( _calculate_pitch_number ( "C" , 4 ) ) . toBe ( 60 ) ;
2380+ expect ( _calculate_pitch_number ( "A" , 4 ) ) . toBe ( 69 ) ;
2381+ expect ( _calculate_pitch_number ( "C" , 5 ) ) . toBe ( 72 ) ;
2382+ } ) ;
2383+
2384+ it ( "should maintain enharmonic consistency" , ( ) => {
2385+ expect ( _calculate_pitch_number ( "C#" , 4 ) ) . toBe ( 61 ) ;
2386+ expect ( _calculate_pitch_number ( "Db" , 4 ) ) . toBe ( 61 ) ;
2387+ } ) ;
2388+
2389+ it ( "should return INVALIDPITCH for invalid input" , ( ) => {
2390+ expect ( _calculate_pitch_number ( "Invalid" , 4 ) ) . toBe ( "Not a valid pitch name" ) ;
2391+ expect ( _calculate_pitch_number ( null , 4 ) ) . toBe ( "Not a valid pitch name" ) ;
2392+ } ) ;
2393+ } ) ;
2394+
2395+ describe ( "getPitchInfo" , ( ) => {
2396+ it ( "should correctly parse string inputs" , ( ) => {
2397+ const info = getPitchInfo ( "C#5" ) ;
2398+ expect ( info ) . toEqual ( {
2399+ name : "C#" ,
2400+ octave : 5 ,
2401+ pitchNumber : 73
2402+ } ) ;
2403+
2404+ const info10 = getPitchInfo ( "C10" ) ;
2405+ expect ( info10 ) . toEqual ( {
2406+ name : "C" ,
2407+ octave : 10 ,
2408+ pitchNumber : 132
2409+ } ) ;
2410+
2411+ // F𝄪5 (F double-sharp) → same pitch as G5 = (5+1)*12 + 7 = 79
2412+ const infoDoubleSharp = getPitchInfo ( "F\u{1D12A}5" ) ;
2413+ expect ( infoDoubleSharp . pitchNumber ) . toBe ( 79 ) ;
2414+ expect ( infoDoubleSharp . octave ) . toBe ( 5 ) ;
2415+
2416+ // Bb𝄫5 (B double-flat) → same pitch as A5 = (5+1)*12 + 9 = 81
2417+ const infoDoubleFlat = getPitchInfo ( "B\u{1D12B}5" ) ;
2418+ expect ( infoDoubleFlat . pitchNumber ) . toBe ( 81 ) ;
2419+ expect ( infoDoubleFlat . octave ) . toBe ( 5 ) ;
2420+
2421+ // Cx4 (C textual double-sharp) → same pitch as D4 = (4+1)*12 + 2 = 62
2422+ const infoX = getPitchInfo ( "Cx4" ) ;
2423+ expect ( infoX . pitchNumber ) . toBe ( 62 ) ;
2424+ expect ( infoX . octave ) . toBe ( 4 ) ;
2425+ } ) ;
2426+
2427+ it ( "should correctly parse numeric inputs" , ( ) => {
2428+ const info = getPitchInfo ( 60 ) ;
2429+ expect ( info ) . toEqual ( {
2430+ name : "C" ,
2431+ octave : 4 ,
2432+ pitchNumber : 60
2433+ } ) ;
2434+ } ) ;
2435+
2436+ it ( "should handle invalid inputs" , ( ) => {
2437+ const info = getPitchInfo ( "InvalidNote" ) ;
2438+ expect ( info ) . toEqual ( {
2439+ name : null ,
2440+ octave : null ,
2441+ pitchNumber : "Not a valid pitch name"
2442+ } ) ;
2443+ } ) ;
2444+
2445+ it ( "should handle accidental offset accumulation edge cases" , ( ) => {
2446+ // Gb-1: G(7) + flat(-1) = index 6 (G♭). (-1+1)*12 + 6 = 6
2447+ const infoGbNeg1 = getPitchInfo ( "Gb-1" ) ;
2448+ expect ( infoGbNeg1 . pitchNumber ) . toBe ( 6 ) ;
2449+ expect ( infoGbNeg1 . octave ) . toBe ( - 1 ) ;
2450+
2451+ // D𝄫-1 enharmonic of C at oct -1: (-1+1)*12 + 2 + (-2) = 0
2452+ // Note: D𝄫-2 (oct=-2) gives -12; octave must be -1 to reach pitch 0.
2453+ const infoDdblFlatNeg1 = getPitchInfo ( "D\u{1D12B}-1" ) ;
2454+ expect ( infoDdblFlatNeg1 . pitchNumber ) . toBe ( 0 ) ;
2455+ expect ( infoDdblFlatNeg1 . octave ) . toBe ( - 1 ) ;
2456+
2457+ // E##4: E(4) + ##(+2) → index 6 (F#). (4+1)*12 + 4 + 2 = 66
2458+ // Spelled with two ASCII '#' chars; each contributes +1 via ACCIDENTAL_SEMITONE_MAP.
2459+ const infoEDblSharp4 = getPitchInfo ( "E##4" ) ;
2460+ expect ( infoEDblSharp4 . pitchNumber ) . toBe ( 66 ) ;
2461+ expect ( infoEDblSharp4 . octave ) . toBe ( 4 ) ;
2462+
2463+ // Fx10: F(5) + x(+2) → index 7 (G). (10+1)*12 + 5 + 2 = 139
2464+ const infoFx10 = getPitchInfo ( "Fx10" ) ;
2465+ expect ( infoFx10 . pitchNumber ) . toBe ( 139 ) ;
2466+ expect ( infoFx10 . octave ) . toBe ( 10 ) ;
2467+ } ) ;
2468+ } ) ;
0 commit comments