Skip to content

Commit f68ad76

Browse files
committed
Add Lyric Management Features and Update Release Notes
- Introduced a new lyric management system in the Song Structure Builder Tool, allowing users to add, edit, and manage lyrics with version control. - Implemented syllable counting for lyric lines, enhancing the tool's functionality for songwriters. - Updated the Release Notes page to include the latest version (v1_9_4) and ensure users are informed of recent changes. - Added new utility functions for lyric processing, improving code organization and maintainability. - Enhanced UI components for better user interaction and experience in managing song structures and lyrics.
1 parent 8a04bdd commit f68ad76

File tree

7 files changed

+424
-129
lines changed

7 files changed

+424
-129
lines changed

LyricProcessorTool.tsx

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
21
import React, { useState, useCallback, useEffect, useRef } from 'react';
32
import Spinner from './components/Spinner';
43
import type { ToolProps } from './Layout';
54
import { resolveSunoUrlToPotentialSongId } from './services/sunoService';
65
import { fetchSunoClipById } from './services/sunoService';
76
import { fetchRiffusionSongData, extractRiffusionSongId } from './services/riffusionService';
7+
import { countSyllablesInLine } from './utils/lyricUtils';
88

99
// Simplified InputField for this tool
1010
const InputField: React.FC<{
@@ -111,23 +111,6 @@ const InfoIcon: React.FC<{tooltip: string, className?: string}> = ({tooltip, cla
111111
const LinkIcon: React.FC<{ className?: string }> = ({ className = "w-4 h-4" }) => (<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className={className}><path strokeLinecap="round" strokeLinejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" /></svg>);
112112

113113

114-
// Moved outside the component for stability
115-
const countSyllablesForWord = (word: string): number => {
116-
if (!word) return 0;
117-
word = word.toLowerCase().trim();
118-
const cleanWord = word.replace(/^[^a-z']+|[^a-z']+$|(?<=\s)[^a-z']+|[^a-z']+(?=\s)/g, '').replace(/[^a-z']/g, '');
119-
if (cleanWord.length === 0) return 0;
120-
if (['the', 'a', 'i', 'is', 'of', 'to', 'in', 'it', 'on', 'at', 'me', 'my', 'he', 'she', 'we', 'so', 'no', 'go', 'by'].includes(cleanWord)) return 1;
121-
if (cleanWord.length <= 3 && cleanWord.match(/[aeiouy]/)) return 1;
122-
const exceptions: Record<string, number> = { "because": 2, "amazing": 3, "beautiful": 3, "chocolate": 2, "every": 2, "everything": 3, "different": 3, "interesting": 3, "usually": 3, "family": 3, "probably": 3, "finally": 3, "actually": 3, "sometimes": 2, "something": 2, "anything": 3, "especially": 4, "business": 2, "problem": 2, "example": 3, "however": 3, "really": 2, "area": 3, "genuine": 3, "create": 2, "naive": 2, "idea": 3, "evening": 2, "people": 2, "inspire": 2, "desire": 2, "fire": 1, "hour": 1, "choir": 1, "quiet": 2, "science": 2, "video": 3, "audio": 3, "radio": 3, };
123-
if (exceptions[cleanWord]) return exceptions[cleanWord];
124-
let syllableCount = 0; const vowels = "aeiouy"; let lastCharWasVowel = false;
125-
for (let i = 0; i < cleanWord.length; i++) { const char = cleanWord[i]; const isVowel = vowels.includes(char); if (isVowel && !lastCharWasVowel) { syllableCount++; } lastCharWasVowel = isVowel; }
126-
if (cleanWord.endsWith('e') && !cleanWord.endsWith('le') && syllableCount > 1) { const charBeforeE = cleanWord.charAt(cleanWord.length - 2); if (charBeforeE && !vowels.includes(charBeforeE)) { syllableCount--; } }
127-
if (syllableCount === 0 && cleanWord.match(/[aeiouy]/)) { syllableCount = 1; }
128-
return Math.max(0, syllableCount);
129-
};
130-
131114
const structuralKeywordsArray = [ "Verse", "Chorus", "Intro", "Outro", "Bridge", "Pre-Chorus", "Post-Chorus", "Instrumental", "Guitar Solo", "Keyboard Solo", "Drum Solo", "Bass Solo", "Sax Solo", "Trumpet Solo", "Violin Solo", "Cello Solo", "Flute Solo", "Solo", "Hook", "Refrain", "Interlude", "Skit", "Spoken", "Adlib", "Vamp", "Coda", "Pre-Verse", "Post-Verse", "Pre-Bridge", "Post-Bridge", "Breakdown", "Build-up", "Drop", "Section", "Part", "Prelude", "Segway" ];
132115
const structuralMarkerPattern = new RegExp( `^(${structuralKeywordsArray.join('|')})(?:\\s+[A-Za-z0-9#]+)*(?:\\s*x\\d+)?$`, 'i' );
133116

@@ -342,7 +325,7 @@ const LyricProcessorTool: React.FC<ToolProps> = ({ trackLocalEvent }) => {
342325
const words = trimmedLine.split(/\s+/);
343326
const wordCount = words.filter(Boolean).length;
344327
const charCount = trimmedLine.length;
345-
const lineSyllableCount = words.reduce((sum, word) => sum + countSyllablesForWord(word), 0);
328+
const lineSyllableCount = countSyllablesInLine(trimmedLine);
346329
return `${trimmedLine} (${lineSyllableCount} syllables, ${wordCount} words, ${charCount} chars)`;
347330
}
348331
});
@@ -520,7 +503,7 @@ const LyricProcessorTool: React.FC<ToolProps> = ({ trackLocalEvent }) => {
520503
</div>
521504

522505
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-6 border-t border-gray-700">
523-
<button type="button" onClick={handleCountSyllables} disabled={isLoading || !canProcess} className="w-full flex justify-center items-center py-3 px-4 border border-green-600 rounded-md shadow-sm text-sm font-medium text-green-300 bg-transparent hover:bg-green-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 focus:ring-offset-gray-900 disabled:bg-gray-800 disabled:text-gray-500 disabled:border-gray-700 disabled:cursor-not-allowed transition-colors" aria-live="polite"> {isLoading && currentAction === 'syllables' ? ( <><Spinner size="w-5 h-5 mr-2" color="text-green-300" /> COUNTING...</> ) : ( 'COUNT SYLLABLES PER LINE' )} </button>
506+
<button type="button" onClick={handleCountSyllables} disabled={isLoading || !canProcess} className="w-full flex justify-center items-center py-3 px-4 border border-green-600 rounded-md shadow-sm text-sm font-medium text-green-300 bg-transparent hover:bg-green-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 focus:ring-offset-gray-900 disabled:bg-gray-800 disabled:text-gray-500 disabled:border-gray-700 disabled:cursor-not-allowed transition-colors" aria-live="polite"> {isLoading && currentAction === 'syllables' ? ( <><Spinner size="w-5 h-5" color="text-green-300" /> COUNTING...</> ) : ( 'COUNT SYLLABLES PER LINE' )} </button>
524507
<button type="button" onClick={handleCleanAndFormat} disabled={isLoading && (!lyricsInput.trim() && !creatorName.trim() && !songTitle.trim())} className="w-full flex justify-center items-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-black bg-green-500 hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-400 focus:ring-offset-gray-900 disabled:bg-gray-700 disabled:text-gray-400 disabled:border-gray-600 disabled:cursor-not-allowed transition-colors" aria-live="polite"> {isLoading && currentAction === 'clean' ? ( <><Spinner size="w-5 h-5 mr-2" color="text-black" /> CLEANING...</> ) : ( 'CLEAN & FORMAT LYRICS' )} </button>
525508
</div>
526509
</div>

ReleaseNotesPage.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
21
import React, { useEffect } from 'react';
32
import type { ToolProps } from './Layout';
43

54
// Import individual release note components
65
// These are ordered from newest to oldest.
6+
import { ReleaseNote_1_9_4 } from './release-notes/v1_9_4';
77
import { ReleaseNote_1_9_3 } from './release-notes/v1_9_3';
88
import { ReleaseNote_1_9_2 } from './release-notes/v1_9_2';
99
import { ReleaseNote_1_9_1 } from './release-notes/v1_9_1';
@@ -73,6 +73,7 @@ const ReleaseNotesPage: React.FC<ToolProps> = ({ trackLocalEvent }) => {
7373

7474
<main className="text-gray-300 leading-relaxed">
7575
{/* Render all release note components here, newest first */}
76+
<ReleaseNote_1_9_4 />
7677
<ReleaseNote_1_9_3 />
7778
<ReleaseNote_1_9_2 />
7879
<ReleaseNote_1_9_1 />
@@ -132,4 +133,4 @@ const ReleaseNotesPage: React.FC<ToolProps> = ({ trackLocalEvent }) => {
132133
);
133134
};
134135

135-
export default ReleaseNotesPage;
136+
export default ReleaseNotesPage;

0 commit comments

Comments
 (0)