CuePoint.swift 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import Foundation
  2. import SwiftData
  3. /// A cue point (marker) on a track — used for marking sections, transitions, etc.
  4. @Model
  5. final class CuePoint: Comparable {
  6. var id: UUID
  7. var name: String
  8. var timestamp: TimeInterval // position in seconds
  9. var endTimestamp: TimeInterval? // optional end for regions
  10. var color: String // hex color for visual display
  11. var type: CuePointType
  12. var notes: String
  13. var track: Track?
  14. /// Whether this is a region (has end point) vs. a point marker.
  15. var isRegion: Bool {
  16. endTimestamp != nil
  17. }
  18. var formattedTimestamp: String {
  19. CuePoint.formatTime(timestamp)
  20. }
  21. init(
  22. name: String = "",
  23. timestamp: TimeInterval,
  24. endTimestamp: TimeInterval? = nil,
  25. color: String = "#FF5722",
  26. type: CuePointType = .marker,
  27. notes: String = ""
  28. ) {
  29. self.id = UUID()
  30. self.name = name
  31. self.timestamp = timestamp
  32. self.endTimestamp = endTimestamp
  33. self.color = color
  34. self.type = type
  35. self.notes = notes
  36. }
  37. static func < (lhs: CuePoint, rhs: CuePoint) -> Bool {
  38. lhs.timestamp < rhs.timestamp
  39. }
  40. static func formatTime(_ time: TimeInterval) -> String {
  41. let minutes = Int(time) / 60
  42. let seconds = Int(time) % 60
  43. let millis = Int((time.truncatingRemainder(dividingBy: 1)) * 1000)
  44. return String(format: "%02d:%02d.%03d", minutes, seconds, millis)
  45. }
  46. }
  47. enum CuePointType: String, Codable, CaseIterable {
  48. case marker = "Marker"
  49. case intro = "Intro"
  50. case outro = "Outro"
  51. case drop = "Drop"
  52. case breakdown = "Breakdown"
  53. case verse = "Verse"
  54. case chorus = "Chorus"
  55. case transition = "Transition"
  56. case loop = "Loop"
  57. case fadeIn = "Fade In"
  58. case fadeOut = "Fade Out"
  59. }