tests: replace copyrighted lyrics with placeholder text #14

Merged
branderson merged 1 commits from synthetic-lyrics into main 2026-10-09 18:15:02 -07:00
9 changed files with 107 additions and 1016 deletions
+36
View File
@@ -0,0 +1,36 @@
#TITLE:Placeholder Chart
#ARTIST:Test Artist
#LANGUAGE:English
#YEAR:2000
#CREATOR:songtrace tests
#GENRE:Test
#COVER:Test Artist - Placeholder Chart [CO].jpg
#MP3:Test Artist - Placeholder Chart.mp3
#VIDEO:Test Artist - Placeholder Chart.mp4
#BPM:217,98
#GAP:4880
#MEDLEYSTARTBEAT:113
#MEDLEYENDBEAT:240
: 0 3 16 ah
: 5 3 20 ah
: 11 3 23 la
: 17 3 16 la
: 22 28 15 ah
: 51 2 16 doo
: 54 31 16 ~
- 95
F 113 3 18 la
F 117 3 21 la
F 121 3 21 la
* 125 3 21 doo
* 129 12 19 ~
- 150
: 155 4 12 Na
R 160 4 0 na
G 165 4 0 na
: 170 6 14 la
- 190
: 194 3 16 La
: 198 3 18 la
* 202 10 20 ah
E
+21
View File
@@ -0,0 +1,21 @@
#TITLE:Café Placeholder
#ARTIST:Tést Artist
#LANGUAGE:English
#GENRE:Test
#YEAR:2000
#MP3:Tést Artist - Café Placeholder.mp3
#CREATOR:songtrace tests
#BPM:256
#GAP:49673
: 0 4 2 Doo
: 6 4 4 doo
: 12 8 5 laé
- 28 30
: 32 4 0 Na
: 38 4 -2 na
* 44 12 -9 ah
- 64
F 70 4 3 La
: 76 6 -5 la
: 84 10 -9 ~
E
-472
View File
@@ -1,472 +0,0 @@
#TITLE:Sanctuary
#ARTIST:Utada Hikaru
#LANGUAGE:English
#YEAR:2009
#CREATOR:Subkei
#GENRE:J-Pop
#COVER:Utada Hikaru - Sanctuary [CO].jpg
#MP3:Utada Hikaru - Sanctuary.mp3
#VIDEO:Utada Hikaru - Sanctuary.mp4
#BPM:217,98
#GAP:4880
#MEDLEYSTARTBEAT:2471
#MEDLEYENDBEAT:2990
: 0 3 16 ah
: 5 3 20 ah
: 11 3 23 ah
: 17 3 16 ah
: 22 28 15 ah
: 51 2 16 ah
: 54 31 16 ~
- 95
F 113 3 18 wonk
F 117 3 21 uoy
F 121 3 21 naht
F 125 3 21 snoit
F 129 3 21 cef
F 133 3 18 fa
F 137 3 18 erom
F 144 2 18 deen
F 147 4 18 I
- 180
: 425 3 16 In
: 429 3 21 you
: 433 2 20 ~
: 436 4 16 ~
: 441 2 18 and
: 445 4 20 I
: 451 4 18 ~
- 459
: 461 3 16 there's
: 465 3 16 a
: 469 5 20 new
: 475 4 23 land
: 481 4 16 ~
: 487 27 15 ~
: 515 4 16 ~
: 521 17 16 ~
: 539 1 18 ~
: 541 3 20 ~
- 547
: 549 1 16 An
: 551 2 18 ~
: 556 3 18 gels
: 560 4 18 in
: 565 7 20 flight
: 573 2 18 ~
- 576
F 578 2 18 wonk
F 581 3 21 uoy
F 585 3 21 naht
F 589 3 21 snoit
F 593 3 21 cef
F 597 3 18 fa
F 601 3 18 erom
F 608 2 18 deen
F 611 3 18 I
- 615
: 617 1 16 My
: 620 1 21 sanc
: 624 2 20 tu
: 628 4 16 a
: 634 8 18 ry
- 646
: 648 3 16 my
: 653 1 21 sanc
: 657 2 20 tu
: 661 3 16 a
: 665 4 16 ry
: 670 2 18 ~
F 674 4 13 yeah
- 680
: 682 2 16 Where
: 686 1 21 fears
: 689 1 20 ~
: 691 5 16 ~
: 697 1 18 and
* 701 4 20 lies
* 707 4 18 ~
- 715
: 717 3 16 melt
: 721 3 16 a
: 725 4 20 way
: 732 4 23 ~
: 737 3 16 ~
: 742 28 15 ~
: 771 3 16 ~
: 775 19 16 ~
: 795 1 18 ~
: 797 3 20 ~
- 804
: 806 1 16 Mu
: 808 2 18 ~
: 812 3 18 sic
: 817 3 18 will
: 822 7 20 tie
: 830 2 18 ~
- 833
F 835 1 18 wonk
F 837 3 21 uoy
F 841 3 21 naht
F 845 3 21 snoit
F 849 3 21 cef
F 853 3 18 fa
F 857 3 18 erom
F 864 2 18 deen
F 867 3 18 I
- 871
: 873 2 16 What's
: 877 1 21 left
: 881 1 20 of
: 884 3 16 me
: 888 1 16 ~
: 890 7 18 ~
- 903
: 905 2 16 What's
: 909 1 21 left
: 913 1 20 of
: 916 3 16 me
: 921 2 16 ~
: 925 3 18 ~
: 933 24 13 now?
- 986
: 1069 3 13 I
: 1074 6 16 watch
: 1082 3 16 you
: 1087 9 18 ~
- 1102
: 1105 3 18 fast
: 1109 3 20 ~
* 1117 2 13 a
* 1122 5 16 sleep
: 1129 3 18 ~
: 1133 15 16 ~
- 1162
: 1189 3 20 All
: 1193 6 21 ~
: 1201 3 18 I
: 1205 6 20 ~
: 1213 5 16 fear
: 1220 20 13 ~
- 1246
: 1249 2 11 means
: 1255 7 13 no
: 1266 5 18 thing
: 1273 41 20 ~
- 1319
: 1321 2 16 In
: 1325 2 21 you
: 1328 2 20 ~
: 1332 3 16 ~
: 1337 2 18 and
: 1341 4 20 I
: 1347 4 18 ~
- 1355
: 1357 3 16 there's
: 1361 3 16 a
* 1365 5 20 new
: 1371 4 23 land
: 1377 4 16 ~
: 1383 27 15 ~
: 1411 4 16 ~
: 1417 17 16 ~
: 1435 1 18 ~
: 1437 3 20 ~
- 1442
: 1444 1 16 An
: 1446 2 18 ~
: 1452 3 18 gels
: 1457 3 18 in
: 1462 6 20 flight
: 1469 2 18 ~
- 1472
F 1474 1 18 wonk
F 1476 3 21 uoy
F 1480 3 21 naht
F 1484 3 21 snoit
F 1488 3 21 cef
F 1492 3 18 fa
F 1496 3 18 erom
F 1503 2 18 deen
F 1506 3 18 I
- 1511
: 1513 1 16 My
: 1516 1 21 sanc
: 1520 2 20 tu
: 1524 4 16 a
: 1530 8 18 ry
- 1541
: 1543 3 16 my
: 1548 1 21 sanc
: 1552 2 20 tu
: 1556 3 16 a
: 1560 4 16 ry
: 1565 2 18 ~
F 1570 3 13 yeah
- 1575
: 1577 2 16 Where
* 1581 1 21 fears
* 1584 1 20 ~
: 1586 5 16 ~
: 1592 1 18 and
: 1596 4 20 lies
: 1602 4 18 ~
- 1611
: 1613 3 16 melt
: 1617 3 16 a
: 1621 4 20 way
: 1628 4 23 ~
: 1633 3 16 ~
: 1638 27 15 ~
: 1666 4 16 ~
: 1672 18 16 ~
: 1691 1 18 ~
: 1693 3 20 ~
- 1699
: 1701 1 16 Mu
: 1703 2 18 ~
: 1707 3 18 sic
: 1712 3 18 will
: 1717 7 20 tie
: 1725 2 18 ~
- 1728
F 1730 2 18 wonk
F 1733 3 21 uoy
F 1737 3 21 naht
F 1741 3 21 snoit
F 1745 3 21 cef
F 1749 3 18 fa
F 1753 3 18 erom
F 1760 2 18 deen
F 1763 3 18 I
- 1767
: 1769 2 16 What's
: 1773 1 21 left
: 1777 1 20 of
: 1780 3 16 me
: 1785 1 16 ~
: 1787 7 18 ~
- 1798
: 1800 2 16 What's
: 1804 1 21 left
* 1808 1 20 of
* 1811 3 16 me
: 1815 1 16 ~
: 1817 7 18 ~
- 1831
F 1834 2 21 snwod
F 1837 2 20 dna
F 1841 3 18 spu
F 1845 3 20 y
F 1849 3 20 nam
F 1853 3 18 os
- 1870
: 1897 3 20 My
* 1901 2 20 heart's
: 1904 1 18 a
: 1906 3 20 bat
: 1910 3 21 tle
: 1914 5 21 ground
- 1926
F 1929 2 16 snoit
F 1932 6 16 om
F 1941 2 18 e
F 1945 2 18 ~
F 1948 2 18 eurt
F 1952 2 18 deen
F 1955 2 16 I
- 1971
F 1987 3 18 wonk
F 1991 3 21 uoy
F 1995 3 21 naht
F 1999 3 21 snoit
F 2003 3 21 cef
F 2007 3 18 fa
F 2011 3 18 erom
F 2018 2 18 deen
F 2021 3 18 I
- 2038
F 2059 2 16 snoit
F 2062 6 16 om
F 2070 3 18 e
F 2075 2 18 ~
F 2078 2 18 eurt
F 2082 2 18 deen
F 2085 2 16 I
- 2116
: 2219 3 13 You
: 2224 6 16 show
: 2232 3 16 me
: 2237 7 18 ~
- 2252
: 2255 3 18 how
: 2259 3 20 ~
: 2267 2 13 to
: 2272 5 16 see
- 2282
* 2284 3 13 That
* 2289 6 16 no
* 2297 3 16 thing
* 2302 5 18 ~
- 2313
: 2316 3 13 is
: 2321 3 16 whole
: 2325 2 15 ~
: 2328 2 13 and
: 2331 1 13 ~
: 2333 2 15 ~
- 2338
: 2340 3 20 no
: 2344 6 21 ~
: 2352 3 18 ~
: 2356 6 20 ~
: 2364 5 16 thing
: 2371 12 13 ~
- 2395
: 2399 2 11 is
: 2403 9 13 bro
: 2416 5 18 ken
: 2423 41 20 ~
- 2470
: 2472 2 16 In
* 2476 2 21 you
* 2479 2 20 ~
* 2483 3 16 ~
: 2488 2 18 and
: 2492 4 20 I
: 2499 3 18 ~
- 2506
: 2508 3 16 There's
: 2512 3 16 a
: 2516 5 20 new
: 2522 4 23 land
: 2528 4 16 ~
: 2534 27 15 ~
: 2562 4 16 ~
: 2568 17 16 ~
: 2586 1 18 ~
: 2588 3 20 ~
- 2593
: 2595 1 16 An
: 2597 2 18 ~
: 2603 3 18 gels
: 2608 3 18 in
: 2613 6 20 flight
: 2620 2 18 ~
- 2623
F 2625 2 18 wonk
F 2628 3 21 uoy
F 2632 3 21 naht
F 2636 3 21 snoit
F 2640 3 21 cef
F 2644 3 18 fa
F 2648 3 18 erom
F 2655 2 18 deen
F 2658 2 18 I
- 2661
: 2663 2 16 My
: 2668 1 21 sanc
: 2672 1 20 tu
: 2675 4 16 a
: 2681 7 18 ry
- 2693
: 2695 3 16 My
: 2700 1 21 sanc
: 2704 2 20 tu
: 2708 3 16 a
: 2712 4 16 ry
: 2717 2 18 ~
F 2721 4 13 yeah
- 2726
: 2728 2 16 Where
: 2732 1 21 fears
: 2735 1 20 ~
: 2737 5 16 ~
: 2743 1 18 and
: 2747 4 20 lies
: 2754 3 18 ~
- 2761
: 2763 3 16 melt
: 2767 3 16 a
: 2771 4 20 way
: 2778 4 23 ~
: 2783 4 16 ~
: 2789 27 15 ~
: 2817 4 16 ~
: 2823 17 16 ~
: 2841 1 18 ~
: 2843 3 20 ~
- 2849
: 2851 1 16 Mu
: 2853 2 18 ~
: 2857 3 18 sic
* 2862 3 18 will
* 2868 7 20 tie
: 2877 2 18 ~
- 2880
F 2882 1 18 wonk
F 2884 3 21 uoy
F 2888 3 21 naht
F 2892 3 21 snoit
F 2896 3 21 cef
F 2900 3 18 fa
F 2904 3 18 erom
F 2911 2 18 deen
F 2914 2 18 I
- 2917
: 2919 2 16 What's
: 2923 1 21 left
: 2927 1 20 of
: 2930 3 16 me
: 2935 1 16 ~
: 2937 7 18 ~
- 2949
: 2951 2 16 What's
: 2955 1 21 left
* 2959 1 20 of
* 2962 3 16 me
* 2967 2 16 ~
: 2971 3 18 ~
: 2979 12 13 now?
- 3005
: 3026 2 11 uh
: 3029 2 13 ~
: 3032 3 16 ~
: 3036 8 15 ~
: 3045 4 18 ~
: 3051 4 16 ~
: 3056 3 15 ~
: 3060 3 13 ~
- 3066
: 3068 1 16 My
: 3070 2 18 ~
: 3074 12 18 fears
- 3096
: 3100 1 16 my
: 3102 2 18 ~
: 3107 3 18 lies
: 3111 2 16 ~
: 3114 1 13 ~
- 3129
* 3164 3 16 melt
* 3169 3 16 a
* 3173 4 20 way
* 3179 4 23 ~
* 3185 3 16 ~
* 3190 27 15 ~
* 3218 3 16 ~
* 3223 19 16 ~
- 3248
: 3250 4 18 ah
: 3256 126 20 ~
- 3392
F 3410 1 18 wonk
F 3412 3 21 uoy
F 3416 3 21 naht
F 3420 3 21 snoit
F 3424 3 21 cef
F 3428 3 18 fa
F 3432 3 18 erom
F 3439 2 18 deen
F 3442 3 18 I
E
-494
View File
@@ -1,494 +0,0 @@
#TITLE:Sweet Child O´Mine
#ARTIST:Guns N' Roses
#LANGUAGE:English
#GENRE:Rock
#YEAR:1987
#MP3:Guns N' Roses - Sweet Child O´Mine.mp3
#COVER:Guns N' Roses - Sweet Child O´Mine.jpg
#VIDEO:Guns N' Roses - Sweet Child O´Mine.webm
#CREATOR:sanicsip
#FIXER:Pacayaka
#BPM:256
#GAP:49673
#VIDEOGAP:0,3
#START:13
#MEDLEYSTARTBEAT:1564
#MEDLEYENDBEAT:2057
: 0 3 8 She's
: 5 2 8 got
: 8 1 8 a
: 13 2 6 smile
: 16 8 8 ~
: 25 1 6 that
: 27 2 5 it
: 32 7 6 seems
: 41 1 8 to
: 45 1 5 me
: 47 5 4 ~
: 53 1 3 ~
- 55
: 57 1 1 re
: 60 7 6 minds
: 69 2 5 me
: 73 1 1 of
: 76 1 1 child
: 79 9 6 ~
: 91 5 6 hood
- 99
: 101 3 6 mem
: 105 4 5 o
: 111 6 3 ries
: 118 1 1 ~
- 120
: 122 3 1 where
: 126 2 4 eve
: 129 5 6 ~
: 135 2 5 ~
: 138 1 1 ry
: 142 2 4 thing
: 145 4 6 ~
: 150 2 5 was
: 154 1 1 as
: 158 2 5 fresh
: 161 4 6 ~
: 166 3 5 as
: 171 1 1 the
: 174 5 6 bright
: 181 5 6 blue
: 190 8 6 sky
: 200 5 5 ~
- 222
: 258 4 8 Now
: 264 4 8 and
: 271 10 8 then
: 283 2 6 when
: 287 2 5 I
: 291 3 6 see
: 295 1 5 her
: 297 1 6 ~
: 299 2 8 ~
: 304 8 5 face
- 313
: 315 3 6 she
: 319 3 8 ~
: 324 3 6 takes
: 330 2 5 me
: 334 1 1 a
: 338 2 3 way
: 341 3 6 ~
: 345 2 5 to
: 349 3 1 that
- 354
: 356 3 6 spe
: 360 3 6 cial
: 364 2 8 ~
: 369 1 6 place
: 371 4 5 ~
: 377 2 5 and
: 381 1 6 if
: 384 2 5 I
: 389 3 6 stare
: 393 2 5 ~
: 398 3 6 too
: 402 2 5 ~
: 405 4 6 long
: 410 1 5 ~
- 415
: 417 1 1 I'd
: 420 1 1 prob
: 423 1 6 a
: 425 2 6 bly
: 429 5 6 break
: 436 5 6 down
: 442 2 6 and
* 445 1 8 ~
: 450 7 6 cry
: 458 8 5 ~
- 483
: 512 3 6 Whoah
: 517 24 8 ~
: 543 3 10 oh
: 548 2 8 ooh
: 551 3 8 whoah
: 555 1 6 ~
: 559 3 6 sweet
: 563 1 5 ~
: 567 2 5 child
: 570 3 6 ~
: 575 1 6 o'
: 578 8 6 mine
: 587 12 5 ~
- 616
: 643 1 6 Whoah
: 645 11 8 ~
: 659 7 6 oh
: 668 7 5 oh
: 677 2 5 oh
: 680 3 6 ~
: 684 3 5 ~
: 689 5 1 sweet
: 697 7 3 love
: 706 2 5 of
: 711 26 1 mine
- 771
: 1041 5 8 She's
: 1048 6 8 got
: 1056 2 6 eyes
: 1059 7 8 ~
: 1068 3 6 of
: 1073 1 5 the
: 1076 3 6 blu
: 1080 3 6 est
: 1084 2 8 ~
: 1089 11 3 skies
: 1102 5 1 as
: 1110 5 6 if
: 1118 7 6 they
- 1128
: 1130 4 6 thought
: 1135 2 5 of
: 1140 2 5 rain
: 1143 4 6 ~
: 1148 4 5 ~
- 1162
* 1171 4 8 I
: 1176 2 5 hate
: 1179 3 6 ~
: 1184 2 6 to
: 1187 3 5 ~
: 1192 2 6 look
: 1196 10 6 in
: 1208 3 6 to
: 1213 6 5 those
: 1221 2 5 eyes
: 1224 7 6 ~
: 1233 4 6 and
- 1239
: 1241 4 6 see
: 1246 1 5 ~
: 1249 3 1 an
: 1253 1 3 ounce
: 1256 5 6 ~
: 1262 1 5 ~
: 1265 2 1 of
: 1269 15 1 pain
- 1294
: 1301 3 6 Her
: 1305 2 6 hair
: 1308 5 8 ~
: 1314 2 8 re
: 1318 6 8 minds
: 1326 4 8 me
: 1331 3 6 of
: 1335 2 5 a
: 1339 6 6 warm
: 1347 2 6 safe
: 1350 3 8 ~
: 1355 6 5 place
- 1362
: 1364 6 1 where
: 1372 3 6 as
: 1376 2 5 ~
: 1380 2 1 a
: 1384 2 5 child
: 1387 7 6 ~
* 1395 3 8 I'd
: 1399 5 6 hide
: 1405 1 5 ~
: 1408 11 1 ~
- 1428
: 1431 1 6 and
: 1433 2 8 ~
: 1437 2 5 pray
: 1440 3 6 ~
: 1445 3 6 for
: 1449 2 5 the
: 1453 7 6 thun
: 1461 6 6 der
- 1471
: 1473 4 6 and
: 1478 2 5 the
: 1482 1 5 rain
: 1484 6 6 ~
- 1491
: 1493 1 5 to
: 1496 8 6 qui
: 1505 2 5 et
: 1509 2 1 ly
: 1514 1 5 pass
: 1516 6 6 ~
* 1526 2 8 me
: 1529 5 6 by
: 1535 1 5 ~
: 1538 10 1 ~
- 1558
: 1566 3 6 Whoah
: 1570 19 8 ~
: 1591 3 10 oh
: 1595 3 8 ooh
: 1600 2 8 whoah
: 1603 1 6 ~
: 1607 4 6 sweet
: 1612 1 5 ~
: 1615 3 5 child
: 1620 2 6 ~
: 1623 1 6 o'
: 1629 7 6 mine
: 1637 11 5 ~
- 1658
: 1675 2 12 Whoah
: 1678 20 13 ~
: 1699 1 12 ~
: 1701 5 13 ~
: 1711 1 8 oh
: 1713 4 10 ~
: 1719 7 8 oh
: 1727 3 8 oh
: 1731 3 10 ~
: 1736 1 8 ~
- 1737
: 1739 3 6 Sweet
: 1743 1 5 ~
: 1748 7 6 love
* 1757 2 8 of
: 1761 4 6 mine
: 1766 1 5 ~
: 1770 16 1 ~
- 1803
* 1829 8 8 Oh
* 1842 4 10 oh
* 1850 4 13 oh
* 1858 2 13 oh
* 1861 5 15 ~
* 1867 1 13 ~
- 1869
: 1871 3 13 Sweet
: 1875 1 10 ~
: 1880 1 10 child
: 1882 3 13 ~
: 1886 1 10 ~
: 1888 2 8 o'
: 1892 2 8 mine
: 1895 5 10 ~
: 1901 2 13 ~
: 1905 2 10 ~
: 1909 9 8 ~
- 1924
: 1926 2 8 Ooh
: 1929 4 10 ~
: 1934 2 8 ~
: 1937 3 5 ~
: 1942 3 8 yeah
: 1951 1 8 yeah
: 1953 5 10 ~
: 1959 2 8 ~
- 1962
: 1964 1 8 Ooh
: 1966 7 10 ~
: 1974 7 8 ~
: 1982 7 6 ~
: 1991 2 5 ooh
: 1994 4 6 ~
: 1999 1 5 ~
- 2002
: 2004 3 1 sweet
: 2010 9 3 love
: 2021 1 5 of
: 2025 1 3 mine
: 2027 1 5 ~
: 2029 2 3 ~
: 2032 25 1 ~
- 2091
: 3176 4 3 Where
: 3181 3 1 do
: 3185 2 -2 we
: 3190 8 -4 go?
- 3204
: 3207 1 1 Where
: 3209 4 3 ~
: 3214 2 1 do
: 3217 2 -2 we
: 3221 6 -4 go
: 3229 8 -6 now?
- 3239
: 3241 3 3 Where
: 3245 3 1 do
: 3249 2 -2 we
: 3253 11 -4 go?
- 3274
: 3282 1 -4 Ooh
: 3284 4 -2 ~
: 3289 3 -4 oh
: 3293 3 -2 ~
: 3297 3 -4 oh
: 3301 1 -6 ~
- 3304
: 3306 2 -2 Where
: 3309 2 -4 do
: 3312 2 -6 we
: 3316 4 -2 go
: 3321 4 -4 ~
: 3326 6 -2 ~?
- 3342
: 3355 5 -4 Oh
: 3362 7 -2 ~
: 3370 2 -2 where
: 3373 2 -2 do
: 3376 2 -2 we
: 3380 3 -4 go
: 3384 1 -6 ~
: 3387 13 -9 now?
- 3410
: 3430 1 -6 Where
: 3433 1 -2 ~
: 3435 2 -2 do
: 3439 2 1 we
: 3443 3 -4 go
: 3447 8 -2 ~?
- 3465
: 3474 7 3 Ooh
: 3483 12 1 oh
: 3497 2 3 where
: 3500 2 1 do
: 3503 2 -2 we
: 3507 6 -4 go
: 3514 13 -6 now?
- 3537
: 3558 1 -4 ay
: 3560 6 -2 ~
: 3567 1 -4 ay
: 3569 5 -2 ~
: 3575 1 -4 ay
: 3577 5 -2 ~
: 3583 1 -4 ay
: 3585 5 -2 ~
: 3591 1 -4 ay
: 3593 6 -2 ~
: 3600 1 -4 ay
: 3602 5 -2 ~
: 3608 2 -4 ay
: 3611 2 -2 ~
- 3614
: 3616 4 10 Oh
: 3623 1 13 where
: 3625 1 15 ~
: 3627 3 13 do
: 3631 3 10 we
: 3635 6 8 go
: 3643 5 6 now?
- 3649
* 3651 2 6 ah
* 3655 2 10 ah
* 3659 2 13 ah
* 3663 2 10 ah
* 3666 1 8 ah
* 3668 2 10 ah
* 3673 2 8 ah
* 3676 2 6 oh
* 3680 2 8 ah
* 3683 1 6 oh
- 3684
: 3686 1 8 where
: 3688 2 10 ~
: 3691 2 8 do
: 3695 2 6 we
: 3699 1 8 go
: 3701 11 10 ~?
- 3719
* 3722 2 13 ah
* 3725 12 15 ~
* 3738 8 13 ~
* 3748 1 10 oh
* 3752 2 15 where
* 3756 2 13 do
* 3760 2 10 we
* 3764 7 8 go
* 3772 10 6 now?
- 3792
: 3816 3 10 Where
: 3821 2 10 do
: 3825 2 13 we
: 3829 1 8 go
: 3831 4 10 ~
: 3837 1 13 ~
: 3841 2 10 ~
: 3845 1 13 ~
: 3849 1 10 ~
: 3851 1 8 ~
: 3853 1 10 ~
: 3855 1 8 ~
: 3857 1 10 ~
: 3859 1 8 ~
: 3861 2 10 ~
: 3865 2 8 ~
: 3868 3 6 ~
: 3872 3 8 ~
: 3876 2 6 ~?
- 3879
: 3881 2 10 where
: 3884 1 8 do
: 3886 1 10 ~
: 3888 2 10 we
: 3892 3 8 go
: 3897 1 6 ~
: 3901 11 3 now?
- 3922
: 3943 1 8 Where
: 3945 2 10 ~
: 3949 2 8 do
: 3953 2 6 we
: 3957 2 10 go
: 3960 2 8 ~
: 3963 10 10 ~?
- 3983
: 3990 8 10 Whoah
: 4000 3 13 ~
: 4004 3 10 ~
: 4008 3 10 where
: 4012 3 13 do
: 4017 2 10 we
: 4021 5 8 go
: 4028 10 6 now?
- 4039
* 4041 3 15 no
* 4046 3 13 no
* 4051 4 10 no
* 4057 3 9 no
* 4062 3 8 no
* 4067 3 6 no
* 4072 9 3 no
- 4087
: 4090 3 8 sweet
: 4094 2 10 ~
: 4101 3 8 child
: 4105 2 6 ~
: 4109 7 3 ~
- 4122
: 4124 3 10 sweet
: 4128 1 8 ~
: 4130 3 10 ~
: 4137 3 10 child
: 4142 2 13 ~
: 4145 4 10 ~
: 4150 2 13 ~
: 4153 4 10 ~
: 4158 1 8 ~
: 4160 2 10 ~
: 4163 2 8 ~
: 4166 3 6 ~
: 4171 2 10 ~
: 4175 2 13 ~
: 4179 3 10 ~
: 4183 4 13 ~
: 4188 4 15 ~
: 4194 2 13 ~
: 4199 1 10 ~
- 4200
: 4202 1 8 o'
: 4204 2 10 ~
: 4208 2 8 mine
: 4211 2 6 ~
: 4214 46 3 ~
: 4262 33 1 ~
: 4297 49 3 ~
E
+17 -17
View File
@@ -7,7 +7,7 @@ from songtrace.lyrics import normalize_lyrics
from songtrace.pipeline import Ctx, PipelineError, SongInput
from songtrace.stages import align
LYRICS = "she's got a smile\nthat it seems to me"
LYRICS = "it's one two three\nfour five six seven eight"
def make_ctx(tmp_path, lyrics=LYRICS, transcript=None):
@@ -15,7 +15,7 @@ def make_ctx(tmp_path, lyrics=LYRICS, transcript=None):
work.mkdir(exist_ok=True)
if transcript is None:
transcript = [{"start": 1.0, "end": 4.0,
"text": "she's got a smile that it seems to me"}]
"text": "it's one two three four five six seven eight"}]
(work / "transcript.json").write_text(json.dumps(transcript))
inp = SongInput(title="T", artist="A", lyrics_text=lyrics)
return Ctx(inp=inp, cfg=Config(whisper_url="u", device="cpu"),
@@ -49,7 +49,7 @@ def check_invariants(rows, lyrics):
def test_alignment_covers_all_words(tmp_path, monkeypatch):
rows = run_align(tmp_path, monkeypatch)
assert [r["word"] for r in rows] == \
["she's", "got", "a", "smile", "that", "it", "seems", "to", "me"]
["it's", "one", "two", "three", "four", "five", "six", "seven", "eight"]
assert rows[0]["line_index"] == 0 and rows[-1]["line_index"] == 1
starts = [r["start"] for r in rows]
assert starts == sorted(starts)
@@ -63,18 +63,18 @@ def test_mismatched_lyrics_fail(tmp_path, monkeypatch):
def test_unalignable_word_interpolated(tmp_path, monkeypatch):
lyrics = "she's got ... smile\nthat it seems to me"
lyrics = "it's one ... three\nfour five six seven eight"
rows = run_align(tmp_path, monkeypatch, lyrics)
dots = next(r for r in rows if r["word"] == "...")
assert dots["score"] == 0.0
prev = next(r for r in rows if r["word"] == "got")
nxt = next(r for r in rows if r["word"] == "smile")
prev = next(r for r in rows if r["word"] == "one")
nxt = next(r for r in rows if r["word"] == "three")
assert prev["end"] <= dots["start"] <= dots["end"] <= nxt["start"] + 1e-6
check_invariants(rows, lyrics)
def test_leading_unalignable_word(tmp_path, monkeypatch):
lyrics = "... got a smile\nthat it seems to me"
lyrics = "... one two three\nfour five six seven eight"
rows = run_align(tmp_path, monkeypatch, lyrics)
assert rows[0]["word"] == "..." and rows[0]["score"] == 0.0
assert rows[0]["start"] >= 0.0
@@ -83,7 +83,7 @@ def test_leading_unalignable_word(tmp_path, monkeypatch):
def test_trailing_unalignable_word(tmp_path, monkeypatch):
lyrics = "she's got a smile\nthat it seems to ..."
lyrics = "it's one two three\nfour five six seven ..."
rows = run_align(tmp_path, monkeypatch, lyrics)
assert rows[-1]["word"] == "..." and rows[-1]["score"] == 0.0
assert rows[-2]["end"] <= rows[-1]["start"]
@@ -91,7 +91,7 @@ def test_trailing_unalignable_word(tmp_path, monkeypatch):
def test_consecutive_unalignable_words(tmp_path, monkeypatch):
lyrics = "she's got ... ... smile\nthat it seems to me"
lyrics = "it's one ... ... three\nfour five six seven eight"
rows = run_align(tmp_path, monkeypatch, lyrics)
dots = [r for r in rows if r["word"] == "..."]
assert len(dots) == 2
@@ -113,8 +113,8 @@ def test_all_words_unalignable_in_section(tmp_path, monkeypatch):
def test_non_chronological_transcript(tmp_path, monkeypatch):
transcript = [{"start": 30.0, "end": 33.0, "text": "that it seems to me"},
{"start": 1.0, "end": 4.0, "text": "she's got a smile"}]
transcript = [{"start": 30.0, "end": 33.0, "text": "four five six seven eight"},
{"start": 1.0, "end": 4.0, "text": "it's one two three"}]
rows = run_align(tmp_path, monkeypatch, transcript=transcript)
check_invariants(rows, LYRICS)
assert len({r["start"] for r in rows}) == len(rows)
@@ -131,8 +131,8 @@ def test_inverted_section_does_not_collapse(tmp_path, monkeypatch):
def test_words_split_across_sections(tmp_path, monkeypatch):
transcript = [{"start": 1.0, "end": 4.0, "text": "she's got a smile"},
{"start": 30.0, "end": 33.0, "text": "that it seems to me"}]
transcript = [{"start": 1.0, "end": 4.0, "text": "it's one two three"},
{"start": 30.0, "end": 33.0, "text": "four five six seven eight"}]
rows = run_align(tmp_path, monkeypatch, transcript=transcript)
check_invariants(rows, LYRICS)
assert rows[3]["end"] <= 5.0
@@ -140,9 +140,9 @@ def test_words_split_across_sections(tmp_path, monkeypatch):
def test_align_drops_lines_never_sung(tmp_path, monkeypatch):
lyrics = "she's got a smile\nthat it seems to me\nbut then it fades away"
lyrics = "it's one two three\nfour five six seven eight\nnine ten eleven twelve"
transcript = [{"start": 1.0, "end": 4.0,
"text": "she's got a smile that it seems to me"}]
"text": "it's one two three four five six seven eight"}]
rows = run_align(tmp_path, monkeypatch, lyrics, transcript)
assert {r["line_index"] for r in rows} == {0, 1}
meta = json.loads((tmp_path / "w" / "align_meta.json").read_text())
@@ -151,9 +151,9 @@ def test_align_drops_lines_never_sung(tmp_path, monkeypatch):
def test_align_flags_missing_span_for_unmatched_singing(tmp_path, monkeypatch):
lyrics = "she's got a smile\nthat it seems to me"
lyrics = "it's one two three\nfour five six seven eight"
transcript = [
{"start": 1.0, "end": 4.0, "text": "she's got a smile that it seems to me"},
{"start": 1.0, "end": 4.0, "text": "it's one two three four five six seven eight"},
{"start": 20.0, "end": 23.0, "text": "completely unrelated ad lib bridge"},
]
run_align(tmp_path, monkeypatch, lyrics, transcript)
+7 -7
View File
@@ -1,22 +1,22 @@
from songtrace.lyrics import normalize_lyrics, alignment_token
RAW = """[Verse 1]
She's got a smile
It's one two three
[Chorus]
Whoa, sweet child o' mine
Take me down to 7 streets
Whoa, la la o' la
Count me up to 7 times
"""
def test_normalize_strips_sections_and_blanks():
ref = normalize_lyrics(RAW)
assert ref.lines == [
["She's", "got", "a", "smile"],
["Whoa,", "sweet", "child", "o'", "mine"],
["Take", "me", "down", "to", "7", "streets"],
["It's", "one", "two", "three"],
["Whoa,", "la", "la", "o'", "la"],
["Count", "me", "up", "to", "7", "times"],
]
assert ref.words[0] == "She's"
assert ref.words[0] == "It's"
assert ref.word_line_index == [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]
+9 -9
View File
@@ -78,7 +78,7 @@ def test_syllabify():
assert syllabify("reminds", "English") == ["re", "minds"]
assert syllabify("a", "English") == ["a"]
assert syllabify("xyzzy", None) == ["xyzzy"]
assert syllabify("She's", "English") == ["She's"]
assert syllabify("It's", "English") == ["It's"]
def test_syllabify_preserves_word_characters():
@@ -96,12 +96,12 @@ def test_syllabify_language_without_pyphen_dict_is_not_mishandled_as_english():
def test_build_notes_basic_line():
times, f0, conf = flat_pitch()
rows = [
{"word": "She's", "start": 1.0, "end": 1.5, "score": 0.9, "line_index": 0},
{"word": "It's", "start": 1.0, "end": 1.5, "score": 0.9, "line_index": 0},
{"word": "got", "start": 1.6, "end": 2.0, "score": 0.9, "line_index": 0},
{"word": "Now", "start": 5.0, "end": 5.5, "score": 0.9, "line_index": 1},
]
notes, breaks, warnings = build_notes(rows, times, f0, conf, "English")
assert notes[0].text == "She's" # line-initial: no leading space
assert notes[0].text == "It's" # line-initial: no leading space
assert notes[1].text == " got" # mid-line: leading space
assert notes[2].text == "Now" # new line: no leading space
assert len(breaks) == 1 and 2.0 <= breaks[0] <= 5.0
@@ -225,8 +225,8 @@ def test_build_notes_short_multisyllable_word_does_not_overlap():
def test_build_notes_never_overlaps_on_dense_input():
rng = np.random.default_rng(11)
times = np.arange(0, 40.0, 0.01)
words = ["She's", "got", "a", "beautiful", "smile", "reminds", "me",
"everything", "I", "lost", "yesterday", "oh"]
words = ["We", "count", "a", "beautiful", "number", "reminds", "us",
"everything", "we", "listed", "yesterday", "oh"]
for _ in range(8):
f0 = 220.0 * 2 ** (rng.integers(0, 12, len(times)) // 3 / 12.0)
conf = np.where(rng.random(len(times)) < 0.9, 0.9, 0.1)
@@ -244,8 +244,8 @@ def test_build_notes_starts_are_non_decreasing():
times = np.arange(0, 12.0, 0.01)
f0 = 220.0 * 2 ** (np.floor(times * 2) % 5 / 12.0) # stepped melody
conf = np.where((times % 3.0) < 2.6, 0.9, 0.1) # unvoiced gaps
words = ["She's", "got", "a", "beautiful", "smile", "that",
"reminds", "me", "of", "everything", "I", "lost"]
words = ["We", "count", "a", "beautiful", "number", "that",
"reminds", "us", "of", "everything", "we", "list"]
rows = []
for i, w in enumerate(words):
dur = 0.8 if i % 3 else 0.07 # every third word sung very fast
@@ -278,7 +278,7 @@ def test_notes_stage_writes_json(tmp_path):
times, f0, conf = flat_pitch()
np.savez(work / "pitch.npz", times=times, f0=f0, conf=conf)
(work / "alignment.json").write_text(json.dumps([
{"word": "She's", "start": 1.0, "end": 1.5, "score": 0.9, "line_index": 0},
{"word": "It's", "start": 1.0, "end": 1.5, "score": 0.9, "line_index": 0},
{"word": "gone", "start": 3.0, "end": 3.5, "score": 0.9, "line_index": 1},
]))
ctx = Ctx(inp=SongInput(title="T", artist="A", lyrics_text="x", language="English"),
@@ -287,7 +287,7 @@ def test_notes_stage_writes_json(tmp_path):
assert stage.outputs(ctx) == [work / "notes_sec.json"]
stage.run(ctx)
data = json.loads((work / "notes_sec.json").read_text())
assert [n["text"] for n in data["notes"]] == ["She's", "gone"]
assert [n["text"] for n in data["notes"]] == ["It's", "gone"]
assert data["breaks"] == [2.25]
assert data["warnings"] == []
assert TimedNote(**data["notes"][0]).pitch == 0
+12 -12
View File
@@ -18,35 +18,35 @@ def test_vocal_sections_keeps_contained_segment():
assert sections == [(0.0, 11.0)]
def test_similarity_high_for_matching_lyrics():
ref = normalize_lyrics("she's got a smile\nthat it seems to me")
segs = [seg(0, 2, "She's got a smile"), seg(2, 4, "that it seems to me")]
ref = normalize_lyrics("it's one two three\nfour five six seven eight")
segs = [seg(0, 2, "It's one two three"), seg(2, 4, "four five six seven eight")]
assert lyrics_similarity(segs, ref) > 0.9
def test_similarity_low_for_wrong_lyrics():
ref = normalize_lyrics("completely different words here entirely")
segs = [seg(0, 2, "she's got a smile that it seems to me")]
segs = [seg(0, 2, "it's one two three four five six seven eight")]
assert lyrics_similarity(segs, ref) < 0.4
def test_classify_lyrics_match_flags_extra_reference_line():
ref = normalize_lyrics("she's got a smile\nthat it seems to me\nbut then it fades")
segs = [seg(1, 4, "she's got a smile that it seems to me")]
ref = normalize_lyrics("it's one two three\nfour five six seven eight\nnine ten eleven")
segs = [seg(1, 4, "it's one two three four five six seven eight")]
dropped, missing = classify_lyrics_match(segs, ref)
assert dropped == [2]
assert missing == []
def test_classify_lyrics_match_flags_unmatched_singing():
ref = normalize_lyrics("she's got a smile\nthat it seems to me")
segs = [seg(1, 4, "she's got a smile that it seems to me"),
ref = normalize_lyrics("it's one two three\nfour five six seven eight")
segs = [seg(1, 4, "it's one two three four five six seven eight"),
seg(20, 23, "completely unrelated ad lib bridge")]
dropped, missing = classify_lyrics_match(segs, ref)
assert dropped == []
assert missing == [(19.0, 24.0)]
def test_classify_lyrics_match_keeps_partially_matched_lines():
ref = normalize_lyrics("she's got a smile\nthat it seems to me")
# line 1 heard with one word garbled ("it" -> "bit"): still a replace/equal
ref = normalize_lyrics("it's one two three\nfour five six seven eight")
# line 1 heard with one word garbled ("five" -> "fife"): still a replace/equal
# match, so the line stays matched rather than dropped
segs = [seg(1, 4, "she's got a smile that bit seems to me")]
segs = [seg(1, 4, "it's one two three four fife six seven eight")]
dropped, _ = classify_lyrics_match(segs, ref)
assert dropped == []
@@ -54,8 +54,8 @@ def test_classify_lyrics_match_scopes_missing_span_to_adlib_not_whole_section():
# matched line and an unmatched ad-lib close enough together that
# vocal_sections would merge them into one section; missing_spans must
# stay tight around the ad-lib so the review marks the right place.
ref = normalize_lyrics("she's got a smile\nthat it seems to me")
segs = [seg(1, 4, "she's got a smile that it seems to me"),
ref = normalize_lyrics("it's one two three\nfour five six seven eight")
segs = [seg(1, 4, "it's one two three four five six seven eight"),
seg(6, 8, "completely unrelated ad lib")]
sections = vocal_sections(segs)
assert sections == [(0.0, 9.0)] # confirms the two segments do merge
+5 -5
View File
@@ -10,8 +10,8 @@ def load(name):
return (FIXTURES / name).read_text(encoding="utf-8", errors="replace")
def test_parse_headers_and_notes():
song = parse_ultrastar(load("sanctuary.txt"))
assert get_header(song, "artist") == "Utada Hikaru"
song = parse_ultrastar(load("chart_crlf.txt"))
assert get_header(song, "artist") == "Test Artist"
assert parse_bpm(get_header(song, "BPM")) == 217.98
first = song.body[0]
assert first == Note(kind=":", beat=0, length=3, pitch=16, text="ah")
@@ -19,16 +19,16 @@ def test_parse_headers_and_notes():
assert any(n.kind == "F" for n in song.body if isinstance(n, Note))
def test_note_text_keeps_leading_space():
song = parse_ultrastar(load("sanctuary.txt"))
song = parse_ultrastar(load("chart_crlf.txt"))
notes = [n for n in song.body if isinstance(n, Note)]
assert notes[1].text == " ah"
def test_negative_pitch():
song = parse_ultrastar(load("sweet_child.txt"))
song = parse_ultrastar(load("chart_latin1.txt"))
assert any(n.pitch == -9 for n in song.body if isinstance(n, Note))
def test_round_trip():
for name in ("sweet_child.txt", "sanctuary.txt"):
for name in ("chart_latin1.txt", "chart_crlf.txt"):
song = parse_ultrastar(load(name))
again = parse_ultrastar(serialize_ultrastar(song))
assert again == song