@prefix s9:   <https://spatial9.ai/ontology/spatial-audio#> .
@prefix owl:  <http://www.w3.org/2002/07/owl#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .
@prefix sh:   <http://www.w3.org/ns/shacl#> .
@prefix mo:   <http://purl.org/ontology/mo/> .
@prefix dct:  <http://purl.org/dc/terms/> .

# Spatial9 Spatial and Immersive Audio Ontology, version 0.1 (MIT licence).
# A small, practical vocabulary for describing immersive mixes. Aligned with the
# Music Ontology, ITU-R BS.2076 (ADM) and the IAMF Audio Element / Mix Presentation model.

<https://spatial9.ai/ontology/spatial-audio> a owl:Ontology ;
    dct:title "Spatial9 Spatial and Immersive Audio Ontology"@en ;
    dct:creator "Spatial9 Engineering Team" ;
    owl:versionInfo "0.1" ;
    rdfs:seeAlso <https://spatial9.ai/blog/ontology-spatial-immersive-audio-spatial9> .

# ---------- Content ----------
s9:Recording   a owl:Class ; rdfs:subClassOf mo:Signal ; rdfs:label "Recording"@en .
s9:Stem        a owl:Class ; rdfs:label "Stem"@en ;
    rdfs:comment "One separated or delivered part of a recording, such as vocals or drums."@en .
s9:Instrument  a owl:Class ; rdfs:subClassOf mo:Instrument ; rdfs:label "Instrument"@en .

# ---------- Structure ----------
s9:Mix              a owl:Class ; rdfs:label "Mix"@en .
s9:MixPresentation  a owl:Class ; rdfs:label "Mix Presentation"@en ;
    rdfs:comment "What a player renders. Mirrors the IAMF Mix Presentation and the ADM audioProgramme."@en .
s9:AudioElement     a owl:Class ; rdfs:label "Audio Element"@en .
s9:ChannelBed       a owl:Class ; rdfs:subClassOf s9:AudioElement ; rdfs:label "Channel Bed"@en .
s9:AudioObject      a owl:Class ; rdfs:subClassOf s9:AudioElement ; rdfs:label "Audio Object"@en .
s9:AmbisonicScene   a owl:Class ; rdfs:subClassOf s9:AudioElement ; rdfs:label "Ambisonic Scene"@en .
[] a owl:AllDisjointClasses ; owl:members ( s9:ChannelBed s9:AudioObject s9:AmbisonicScene ) .

# ---------- Playback and perception ----------
s9:Renderer  a owl:Class ; rdfs:label "Renderer"@en .
s9:Format    a owl:Class ; rdfs:label "Format"@en .
s9:Listener  a owl:Class ; rdfs:label "Listener"@en .
s9:Room      a owl:Class ; rdfs:label "Room"@en ; rdfs:comment "A real or virtual acoustic space; may be an acoustic digital twin."@en .
s9:HRTF      a owl:Class ; rdfs:label "HRTF"@en ; rdfs:comment "Head-related transfer function, usually stored as an AES69 SOFA file."@en .
s9:Position  a owl:Class ; rdfs:label "Position"@en .

s9:IAMF       a s9:Format ; rdfs:label "Eclipsa Audio (IAMF)"@en .
s9:ADM_BWF    a s9:Format ; rdfs:label "ADM BWF"@en .
s9:DolbyAtmos a s9:Format ; rdfs:label "Dolby Atmos"@en .
s9:Binaural   a s9:Format ; rdfs:label "Binaural stereo"@en .

# ---------- Object properties ----------
s9:hasMix        a owl:ObjectProperty ; rdfs:domain s9:Recording ; rdfs:range s9:Mix .
s9:separatedInto a owl:ObjectProperty ; rdfs:domain s9:Recording ; rdfs:range s9:Stem .
s9:plays         a owl:ObjectProperty ; rdfs:domain s9:Stem ; rdfs:range s9:Instrument .
s9:presents      a owl:ObjectProperty ; rdfs:domain s9:Mix ; rdfs:range s9:MixPresentation .
s9:hasElement    a owl:ObjectProperty ; rdfs:domain s9:MixPresentation ; rdfs:range s9:AudioElement .
s9:carries       a owl:ObjectProperty ; rdfs:domain s9:AudioElement ; rdfs:range s9:Stem .
s9:hasPosition   a owl:ObjectProperty , owl:FunctionalProperty ; rdfs:domain s9:AudioObject ; rdfs:range s9:Position .
s9:renderedBy    a owl:ObjectProperty ; rdfs:domain s9:MixPresentation ; rdfs:range s9:Renderer .
s9:encodes       a owl:ObjectProperty ; rdfs:domain s9:Renderer ; rdfs:range s9:Format .
s9:renderedFor   a owl:ObjectProperty ; rdfs:domain s9:Renderer ; rdfs:range s9:Listener .
s9:usesHRTF      a owl:ObjectProperty ; rdfs:domain s9:Renderer ; rdfs:range s9:HRTF .
s9:inRoom        a owl:ObjectProperty ; rdfs:domain s9:Listener ; rdfs:range s9:Room .

# ---------- Data properties ----------
s9:azimuth    a owl:DatatypeProperty ; rdfs:domain s9:Position ; rdfs:range xsd:decimal ; rdfs:comment "Degrees, -180 to 180, 0 is straight ahead, positive is to the left (ADM convention)."@en .
s9:elevation  a owl:DatatypeProperty ; rdfs:domain s9:Position ; rdfs:range xsd:decimal ; rdfs:comment "Degrees, -90 to 90."@en .
s9:distance   a owl:DatatypeProperty ; rdfs:domain s9:Position ; rdfs:range xsd:decimal ; rdfs:comment "Normalised 0 to 1."@en .
s9:width      a owl:DatatypeProperty ; rdfs:domain s9:AudioObject ; rdfs:range xsd:decimal .
s9:gainDb     a owl:DatatypeProperty ; rdfs:domain s9:AudioElement ; rdfs:range xsd:decimal .
s9:layout     a owl:DatatypeProperty ; rdfs:domain s9:ChannelBed ; rdfs:range xsd:string ; rdfs:comment "For example 7.1.2 or 5.1."@en .
s9:hoaOrder   a owl:DatatypeProperty ; rdfs:domain s9:AmbisonicScene ; rdfs:range xsd:integer .

# ---------- Shapes (rules a mix must satisfy) ----------
s9:AudioObjectShape a sh:NodeShape ;
    sh:targetClass s9:AudioObject ;
    sh:property [ sh:path s9:hasPosition ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:message "Every audio object needs exactly one position."@en ] ;
    sh:property [ sh:path s9:width ; sh:minInclusive 0 ; sh:maxInclusive 1 ] .

s9:PositionShape a sh:NodeShape ;
    sh:targetClass s9:Position ;
    sh:property [ sh:path s9:azimuth ; sh:minCount 1 ; sh:minInclusive -180 ; sh:maxInclusive 180 ] ;
    sh:property [ sh:path s9:elevation ; sh:minCount 1 ; sh:minInclusive -90 ; sh:maxInclusive 90 ] .
