{"id":48357059,"url":"https://github.com/pyfar/sofa_conventions","last_synced_at":"2026-04-05T11:33:52.392Z","repository":{"id":105010262,"uuid":"548390577","full_name":"pyfar/sofa_conventions","owner":"pyfar","description":"machine readable implementation of SOFA conventions","archived":false,"fork":false,"pushed_at":"2025-04-12T10:48:44.000Z","size":787,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T11:40:52.439Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"eupl-1.2","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pyfar.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.rst","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-10-09T13:25:21.000Z","updated_at":"2025-02-07T13:34:19.000Z","dependencies_parsed_at":"2024-12-11T16:25:06.511Z","dependency_job_id":"532dc2b9-3b83-46a2-a13e-67d6a238f0cc","html_url":"https://github.com/pyfar/sofa_conventions","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/pyfar/sofa_conventions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyfar%2Fsofa_conventions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyfar%2Fsofa_conventions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyfar%2Fsofa_conventions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyfar%2Fsofa_conventions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyfar","download_url":"https://codeload.github.com/pyfar/sofa_conventions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyfar%2Fsofa_conventions/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31434624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T08:13:15.228Z","status":"ssl_error","status_checked_at":"2026-04-05T08:13:11.839Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-05T11:33:52.251Z","updated_at":"2026-04-05T11:33:52.338Z","avatar_url":"https://github.com/pyfar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SOFA conventions\n\nComplete definition of SOFA conventions according to AES69 are contained in the\nfolders *conventions* and *rules*. The conventions are intended to be used in\napplications that read or write SOFA data. Test data violating the conventions\nare contained in *data*. This data is intended for testing if an application\ncorrectly verifies data against AES69 when reading it.\n\n**Conventions are implemented according to AES69\n(SOFA conventions version 2.1)**\n\nAES69-2022: *AES standard for file exchange - Spatial acoustic data file\nformat*, Audio Engineering Society, Inc., New York, NY, USA.\n\nUpdating the conventions and data requires the sofar package available from\n\u003chttps://github.com/pyfar/sofar\u003e and can be installed via\n\n `pip install sofar`\n\nTo update the conventions from \u003chttps://sofaconventions.org/conventions\u003e:\n\n- check if updates are available with\n  `sofar.update_conventions._check_congruency()`\n- run `sofar.update_conventions()`.\n- update and run `write_verification_rules.py` if a new convention was added or\n  a convention was deprecated completely.\n- update and run `write_upgrade_rules.py` if a convention was deprecated.\n- To update the verification data run `write_verification_data.py`.\n- check if tests pass in `sofar`\n- update HISTORY and VERSION\n- do a tagged commit\n- merge to master branch\n- update *sofa_conventions* submodule in sofar\n\n## 1. Conventions\n\nThis folder contains the official SOFA conventions as json and csv files. SOFA\nconventions are the basis of SOFA files, a data format to store spatially\ndistributed acoustic data. They also contain basic information for verifying\nthe content inside SOFA files. The conventions are tested as part of the sofar\npackage.\n\n## 2. Data\n\nContains SOFA files that each contain exactly one invalid entry. They are\nwritten with\n\n`write_verification_data.py`\n\nand are intended for testing SOFA APIs. See the following section for more\ndetails.\n\n## 3. Rules\n\nContains Verification rules as json files that are needed for a complete\nverification of SOFA files. They are written by running\n\n`write_verification_rules.py`\n\n### Verification of SOFA files\n\nThe following details how SOFA files must be verified to follow the SOFA\nstandard AES69. The verification rules make use of the SOFA conventions\nand the verification rules. The verification requires the following steps:\n\n1. Mandatory variables and attributes must be contained in the file. Such data\n   has the flag \"m\" in the conventions.\n2. All data must have the correct type (double, string, attribute) as denoted\n   the field \"type\" in the conventions.\n3. All variables must have the correct dimensions as denoted by the\n   \"dimemsions\" in the conventions. The dimensions is determined from the\n   variable that lists it with a lower case letter. E.g. if Data_IR shall have\n   the dimension \"mrn\" the and the actual shape of Data_IR is (10, 2, 128),\n   then M=10, R=2, and N=128.\n4. Variable and attribute names may not contain underscores and the keywords\n   'API', 'GLOBAL', and 'PRIVATE'.\n   Note: AES69 uses colons to denote attributes (e.g., 'SourcePosition:Units'\n   denotes the attribute 'Units' belonging to the variable 'SourcePosition')\n   and dots to denote hierarchies (e.g., 'Data.Real' and 'Data.Imag' are\n   variables of the group 'Data'). In addition AES69does not have a keyword to\n   specify global attribute. Some APIs (API_MO and sofar) can not use dots and\n   colons in the names (they use underscores instead) and require the keyword\n   'GLOBAL' to highlight global attributes, e.g., 'GLOBAL_SOFAConventions'.\n   The verification of this rule might thus vary across toolboxes.\n5. Application specific (custom) variables and attributes can not have names\n   that are used by the respective convention.\n6. Some attributes can only have a limited number of entries. Examples for this\n   are names of coordinate systems, units, and room types. For instance the\n   used coordinate system can only be 'cartesian', 'spherical', or\n   'spherical harmonics'. A special case are units, where multiple spellings\n   are allowed (e.g. 'meter' and 'metre') and that can be separated either by\n   commas, commas plus spaces, or spaces (e.g. 'meter, meter, degree' or\n   'meter,meter degree'). All restricted values should be verified insensitive\n   of the case, however, units shall be written in lowercase only.\n7. All verification rules from rules.json must be checked (see below)\n\nThe json files inside this folder contain rules for verifying SOFA files.\nThe rules were manually extracted from the SOFA Standard AES69. Note that\nthe json files are written with `write_verification_rules.py` where additional\ncomments on the rules can be found.\n\n### rules.json\n\nContains all verification rules\n\n- that can not be derived from the SOFA conventions\n- that do not pertain to units and unit strings\n\nNote that the values of units MUST always be given in reference units as\ndetailed for unit_aliases.json (see below)\n\nThe rules are contained in a json file with the following structure\n(explanation below, examples refer to rules.json)\n\n```python\n{\n   key_1: {\n      \"value\": values\n      \"general\": [sub_key_1, sub_key_2, ..., sub_key_N],\n      \"specific\": {\n         value_1: {\n            sub_key_1: values\n            .\n            .\n            .\n            sub_key_N: values\n            \"_dimensions\": {\n               dimension_1: {\n                  \"value\": values,\n                  \"value_str\": value_string\n               },\n               .\n               .\n               .\n               dimensions_N: {...}\n            }\n         }\n         value_2: {...},\n         .\n         .\n         .\n         value_N: {...}\n      }\n   },\n   key_2: {...},\n   .\n   .\n   .\n   key_N: {...}\n}\n```\n\n#### Keys\n\n`key_1`, `key_2`, ... `key_N` are the names of SOFA variables (e.g.,\n'ReceiverPosition') or attributes (e.g., 'GLOBAL_DataType').\n\n#### Values\n\n`values` are either a list of possible values that a variable of attribute must\nhave or null, if the variable or attribute can have any value.\nEXAMPLE: 'GLOBAL_DataType' (`key`) can be [\"FIR\", \"FIR-E\", \"FIRE\" \"TF\", \"TF-E\",\n         \"TFE\", \"SOS\"] (`value`) and an error should be raised if\n         'GLOBAL_DataType' has any other value. If `values` was null,\n         'GLOBAL_DataType' could have any value.\n\n#### Dependencies\n\nA variable or attribute (`key`) can have two different kinds of dependencies.\ngeneral\" and \"specific\". If there are such dependencies, a `key` is\nfollowed by the corresponding fields.\nEXAMPLE: 'GLOBAL_DataType' (`key`) has \"specific\" dependencies and\n         'ListenerPosition_Type' (`key`) has \"general\" dependencies.\n\n##### General Dependencies\n\nGeneral dependencies are simple. They contain a list that contains an arbitrary\nnumber of variables and attributes (`sub_keys`), which must be contained in a\nSOFA object IF `key` is contained.\nEXAMPLE: 'ListenerView_Type' must be contained if 'ListenerView' is contained.\n\n##### Specific Dependencies\n\nSpecific dependencies are more complex. They describe dependencies for a\nvariable or attribute (`sub_key_1`, `sub_key_2`, ..., `sub_key_N`) that only\nhave to be enforced if `key` has a specific value (`value_1`, `value_2`, ...\n, `value_N`). There are three possible dependencies.\n\n1. If the value of `sub_key` is null, it only has to be checked if `sub_key` is\n   contained in the Sofa object\n   EXAMPLE: If 'GLOBAL_DataType' is \"FIR\", 'Data_IR' must be contained\n2. If the value is not null, `sub_key` must have on of the listed values.\n   EXAMPLE: If 'GLOBAL_DataType' is \"FIR\", 'Data_SamplingRate_Units' must be\n            \"hertz\"\n3. If the `sub_key` is \"_dimensions\", the size of on or more SOFA/NetCDF\n   dimensions is restricted to one or more certain values.\n   EXAMPLE: If 'GLOBAL_DataType' is \"SOS\", the dimension 'N' must be an integer\n            multiple of 6 (in this specific case provided as a list of\n            possible values up to 600).\n   For restrictions on the dimensions the rules also provide a verbose error\n   message that can be used for feedback in case the dependency is violated.\n   EXAMPLE: The error message for the case described above is \"an integer\n            multiple of 6 greater 0\"\n\n### unit_aliases.json\n\nContains a list of possible variants of unit names. The structure is as follows\n\n{\n   variant_1_unit_1: reference_unit_1\n   variant_2_unit_1: reference_unit_2\n   .\n   .\n   .\n   variant_N_unit_1: reference_unit_1\n   variant_1_unit_2: reference_unit_2\n   .\n   .\n   .\n   variant_N_unit_N: reference_unit_N\n}\n\nEXAMPLE: The unit \"metre\" (`reference_unit_1`) can also be written \"metres\",\n         \"meter\", and \"meters\" (`variant_1_unit_1`, `variant_2_unit_1`,\n         `variant_3_unit_1`).\n\n### deprecations.json\n\nContains a list of deprecated conventions and the convention that replaces\nthem.\n\n### upgrade.json\n\nContains rules for upgrading deprecated conventions. Upgrading a convention\nrequires the following steps\n\n1. Replace the convention, e.g., switch from *MultiSpeakerBRIR* to\n   *SingleRoomMIMOSRIR*. Note that this dot not change any data. It only\n   changes what data is expected to be stored in a SOFA file.\n2. Update the fields *GLOBAL:SOFAConventions*, *GLOBAL_SOFAConventionsVersion*,\n   *GLOBAL_Version*, and *GLOBAL_DataType* according to the new convention.\n3. Check if any data needs to be renamed and/or reshaped.\n4. Check if any data needs to be removed.\n5. Check if new default data needs to be specified.\n\nSteps 1, 2, and 5 are general steps and do not require specific rules. Steps\n3 and 4 are defined by the json file\n\n```python\n{\n   deprecated_convention_1: {\n      \"from_to\": [[[outdated versions],\n                   [possible upgrades],\n                    upgrade_key],\n                  [a possible second/third/... set in analogy to the above]],\n      upgrade_key_1: {\n         \"move\": {\n            source_key_1: {\n               \"target\": target_key,\n               \"moveaxis: [from, to],\n               \"deprecated_dimensions\": [dimensions_1, ..., dimensions_N]\n            .\n            .\n            .\n            source_key_N: {...}\n            }\n         \"remove\": [target_key_1, ..., target_key_N],\n         \"message\": message to display after upgrading\n         }\n      },\n      upgrade_key_2: {},\n      .\n      .\n      .\n      upgrade_key_N: {}\n   },\n   deprecated_convention_2: {...},\n   .\n   .\n   .\n   deprecated_convention_N: {...}\n}\n```\n\n#### deprecated_convention\n\nThe name of the deprecated convention as a string.\n\n#### from_to\n\nA list with three values\n\n1. The version numbers of the deprecated conventions that can be upgraded.\n2. The conventions and version numbers to which it can be upgraded.\n3. A unique key, that defines where the information for upgrading is given.\n\n#### move\n\nDefines data that must be moved by means of\n\n- the *source_key*, i.e., the name of the data that needs to be moved\n- the *target_key*, i.e., the new name of the data\n- *moveaxis* which defines if any of the dimensions of the data must be\n  reorganized. In this case *from* gives on or more dimension that are moved\n  in the positions defined by *to*. Dimensions start at 0 and the procedure\n  follows that of *numpy.moveaxis*\n- *deprecated_dimensions* lists data dimensions that are not supported by the\n  upgraded convnention.\n\nIn case no data needs to be moved, move simply is empty, i..e, `{}`.\n\n#### remove\n\nA list of data names that must be removed. This is empty if no data needs to\nbe removed, i.e., `[]`.\n\n#### message\n\nA message that should be printed after upgrading. `null` if no message is\nrequired.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyfar%2Fsofa_conventions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpyfar%2Fsofa_conventions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyfar%2Fsofa_conventions/lists"}