Model language and pronunciation settings
This commit is contained in:
@@ -109,6 +109,51 @@ public extension SongProject {
|
||||
genres.removeAll { $0.id == id }
|
||||
}
|
||||
|
||||
var languageIDs: Set<String> {
|
||||
Set(languages.map(\.id))
|
||||
}
|
||||
|
||||
var dialectIDs: Set<String> {
|
||||
Set(dialects.map(\.id))
|
||||
}
|
||||
|
||||
func language(for languageID: String) -> LanguageSelection? {
|
||||
languages.first { $0.id == languageID }
|
||||
}
|
||||
|
||||
func dialect(for dialectID: String) -> DialectSelection? {
|
||||
dialects.first { $0.id == dialectID }
|
||||
}
|
||||
|
||||
func dialects(forLanguageID languageID: String) -> [DialectSelection] {
|
||||
dialects.filter { $0.languageID == languageID }
|
||||
}
|
||||
|
||||
mutating func upsertLanguage(_ language: LanguageSelection) {
|
||||
if let index = languages.firstIndex(where: { $0.id == language.id }) {
|
||||
languages[index] = language
|
||||
} else {
|
||||
languages.append(language)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func removeLanguage(id languageID: String) {
|
||||
languages.removeAll { $0.id == languageID }
|
||||
dialects.removeAll { $0.languageID == languageID }
|
||||
}
|
||||
|
||||
mutating func upsertDialect(_ dialect: DialectSelection) {
|
||||
if let index = dialects.firstIndex(where: { $0.id == dialect.id }) {
|
||||
dialects[index] = dialect
|
||||
} else {
|
||||
dialects.append(dialect)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func removeDialect(id dialectID: String) {
|
||||
dialects.removeAll { $0.id == dialectID }
|
||||
}
|
||||
|
||||
var selectedInstrumentTracks: [InstrumentTrack] {
|
||||
instruments.filter(\.selected)
|
||||
}
|
||||
@@ -299,16 +344,39 @@ public struct DialectSelection: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
public struct ArabicPronunciationSettings: Codable, Equatable, Sendable {
|
||||
public var isEnabled: Bool
|
||||
public var diacritizationPolicy: ArabicDiacritizationPolicy
|
||||
public var tanweenPolicy: ArabicTanweenPolicy
|
||||
public var userNotes: String?
|
||||
public var preservedSpellings: [String]
|
||||
|
||||
public init(isEnabled: Bool = false, userNotes: String? = nil, preservedSpellings: [String] = []) {
|
||||
public init(
|
||||
isEnabled: Bool = false,
|
||||
diacritizationPolicy: ArabicDiacritizationPolicy = .unspecified,
|
||||
tanweenPolicy: ArabicTanweenPolicy = .unspecified,
|
||||
userNotes: String? = nil,
|
||||
preservedSpellings: [String] = []
|
||||
) {
|
||||
self.isEnabled = isEnabled
|
||||
self.diacritizationPolicy = diacritizationPolicy
|
||||
self.tanweenPolicy = tanweenPolicy
|
||||
self.userNotes = userNotes
|
||||
self.preservedSpellings = preservedSpellings
|
||||
}
|
||||
}
|
||||
|
||||
public enum ArabicDiacritizationPolicy: String, Codable, Equatable, Sendable {
|
||||
case unspecified
|
||||
case pronunciationTargeted
|
||||
case fullTashkeel
|
||||
}
|
||||
|
||||
public enum ArabicTanweenPolicy: String, Codable, Equatable, Sendable {
|
||||
case unspecified
|
||||
case preserveUserInput
|
||||
case addWhenPronunciationRequires
|
||||
case removeWhenUnwanted
|
||||
}
|
||||
|
||||
public struct GenreStyle: Codable, Equatable, Identifiable, Sendable {
|
||||
public let id: String
|
||||
public var name: String
|
||||
|
||||
@@ -235,4 +235,48 @@ final class SongProjectModelTests: XCTestCase {
|
||||
|
||||
XCTAssertNil(project.vocalist(for: "harmony"))
|
||||
}
|
||||
|
||||
func testLanguagesDialectsAndArabicPronunciationSettingsAreModeled() {
|
||||
var project = SongProject(
|
||||
id: "project-7",
|
||||
title: "Multilingual Song",
|
||||
idea: "Arabic and English hook"
|
||||
)
|
||||
let arabic = LanguageSelection(id: "arabic", name: "Arabic")
|
||||
let english = LanguageSelection(id: "english", name: "English")
|
||||
let levantine = DialectSelection(id: "levantine", name: "Levantine", languageID: arabic.id)
|
||||
let gulf = DialectSelection(id: "gulf", name: "Gulf", languageID: arabic.id)
|
||||
|
||||
project.upsertLanguage(arabic)
|
||||
project.upsertLanguage(english)
|
||||
project.upsertLanguage(LanguageSelection(id: "english", name: "English"))
|
||||
project.upsertDialect(levantine)
|
||||
project.upsertDialect(gulf)
|
||||
project.arabicPronunciationSettings = ArabicPronunciationSettings(
|
||||
isEnabled: true,
|
||||
diacritizationPolicy: .pronunciationTargeted,
|
||||
tanweenPolicy: .preserveUserInput,
|
||||
userNotes: "Preserve dialect phrasing",
|
||||
preservedSpellings: ["ya habibi"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(project.languageIDs, ["arabic", "english"])
|
||||
XCTAssertEqual(project.dialectIDs, ["levantine", "gulf"])
|
||||
XCTAssertEqual(project.language(for: arabic.id), arabic)
|
||||
XCTAssertEqual(project.dialects(forLanguageID: arabic.id), [levantine, gulf])
|
||||
XCTAssertTrue(project.arabicPronunciationSettings.isEnabled)
|
||||
XCTAssertEqual(project.arabicPronunciationSettings.diacritizationPolicy, .pronunciationTargeted)
|
||||
XCTAssertEqual(project.arabicPronunciationSettings.tanweenPolicy, .preserveUserInput)
|
||||
|
||||
project.removeDialect(id: gulf.id)
|
||||
|
||||
XCTAssertNil(project.dialect(for: gulf.id))
|
||||
XCTAssertEqual(project.dialects(forLanguageID: arabic.id), [levantine])
|
||||
|
||||
project.removeLanguage(id: arabic.id)
|
||||
|
||||
XCTAssertNil(project.language(for: arabic.id))
|
||||
XCTAssertEqual(project.dialects(forLanguageID: arabic.id), [])
|
||||
XCTAssertEqual(project.languageIDs, ["english"])
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ requirement is missing and blocks implementation, record it in
|
||||
- [x] Model song sections with order and optional timestamps.
|
||||
- [x] Model instruments, variants, roles and placements.
|
||||
- [x] Model multiple vocalists and section assignments.
|
||||
- [ ] Model language/dialect and Arabic pronunciation settings.
|
||||
- [x] Model language/dialect and Arabic pronunciation settings.
|
||||
- [ ] Model BPM, key, scale and maqam with Manual/Auto state.
|
||||
- [ ] Model emotional arc and production directions.
|
||||
- [ ] Add serialization tests.
|
||||
|
||||
Reference in New Issue
Block a user