{"id":16921193,"url":"https://github.com/bdrelling/instrumentkit","last_synced_at":"2025-04-11T11:31:14.110Z","repository":{"id":63905214,"uuid":"525616664","full_name":"bdrelling/InstrumentKit","owner":"bdrelling","description":"Provides type-safe access to localized musical instruments and their tunings.","archived":false,"fork":false,"pushed_at":"2023-11-18T01:53:38.000Z","size":179,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-31T05:51:31.368Z","etag":null,"topics":["instruments","ios","linux","macos","music","swift","tunings","tvos","watchos"],"latest_commit_sha":null,"homepage":"https://instruments.fyi","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bdrelling.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-08-17T02:51:10.000Z","updated_at":"2024-05-17T21:20:02.000Z","dependencies_parsed_at":"2023-11-18T03:29:37.175Z","dependency_job_id":"61b95eca-b890-4804-ab77-937618a878c3","html_url":"https://github.com/bdrelling/InstrumentKit","commit_stats":{"total_commits":68,"total_committers":2,"mean_commits":34.0,"dds":"0.044117647058823484","last_synced_commit":"396fe801f6602b1af92aeaf74d1f16d4733ea661"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdrelling%2FInstrumentKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdrelling%2FInstrumentKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdrelling%2FInstrumentKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bdrelling%2FInstrumentKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bdrelling","download_url":"https://codeload.github.com/bdrelling/InstrumentKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223466481,"owners_count":17149774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["instruments","ios","linux","macos","music","swift","tunings","tvos","watchos"],"created_at":"2024-10-13T19:50:56.747Z","updated_at":"2024-11-07T06:03:46.880Z","avatar_url":"https://github.com/bdrelling.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# InstrumentKit\n\n[![CI Status](https://github.com/bdrelling/InstrumentKit/actions/workflows/tests.yml/badge.svg)](https://github.com/bdrelling/InstrumentKit/actions/workflows/tests.yml)\n[![Latest Release](https://img.shields.io/github/v/tag/bdrelling/InstrumentKit?color=blue\u0026label=)](https://github.com/bdrelling/InstrumentKit/tags)\n[![Swift Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbdrelling%2FInstrumentKit%2Fbadge%3Ftype%3Dswift-versions\u0026label=)](https://swiftpackageindex.com/bdrelling/InstrumentKit)\n[![Platform Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbdrelling%2FInstrumentKit%2Fbadge%3Ftype%3Dplatforms\u0026label=)](https://swiftpackageindex.com/bdrelling/InstrumentKit)\n[![License](https://img.shields.io/github/license/bdrelling/InstrumentKit?label=)](https://github.com/bdrelling/InstrumentKit/blob/main/LICENSE)\n\n**InstrumentKit** provides type-safe access to localized musical instruments and their tunings.\n\n## Table of Contents\n\n- [Work In Progress](#work-in-progress)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Performance](#performance)\n- [Contributing](#contributing)\n- [Credits](#credits)\n- [License](#license)\n\n## Work In Progress\n\n:warning: This package is very much a work in progress. Here are some immediate next steps.\n\n- For the time being, this package is focused on collecting, validating, and localizing data for **string instruments only**. Once string instruments feel accurate and stable and the library is extremely tested, the plan will be to add brass, keyboards, percussions, and more.\n- The library currently leverages an internal dependency for musical notation (`NoteKit`), but should be reaplced by the more accurate and better maintained [`AudioKit/Tonic`](https://github.com/AudioKit/Tonic) as soon as possible. Musical math and theory is difficult, and `InstrumentKit` doesn't want to be in the business of musical math or theory.\n- Provide system for ensuring paritally localized models provide English values by default. Currently, they fall back on the `localizationKey`, meaning `\"Guitar\"` translated to a partial localization without the `\"guitar\"` key will show up as `\"guitar\"`, not `\"Guitar\"`.\n  - This already works for _missing_ localizations, but doesn't work for _partial_ localizations.\n  - This functionality shouldn't be much more work to achieve without increasing performance.\n\n## Installation\n\n### Swift Package Manager\n\n[Swift Package Manager](https://swift.org/package-manager/) is built into the Swift toolchain and is the preferred way of integrating the SDK.\n\nIn addition to being compatible with Apple platforms (iOS, macOS, tvOS, watchOS), the package is also fully compatible with Linux, making it perfect for [Server-side Swift](https://www.swift.org/server/) projects.\n\nFor Swift package projects, simply add the following line to your Package.swift file in the dependencies section, replacing `x.x.x` with the latest version:\n\n```swift\ndependencies: [\n  .package(url: \"https://github.com/bdrelling/InstrumentKit\", .from: \"x.x.x\"),\n]\n```\n\nFor app projects, simply follow the [Apple documentation](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) on adding package dependencies to your app.\n\n## Usage\n\n### Models\n\n```swift\nstruct StringInstrument {\n    let localizationKey: String\n    let name: String\n    let numberOfStrings: Int\n    let numberOfCourses: Int\n    let tunings: [Tuning]\n}\n```\n\n```swift\nstruct Tuning {\n    let localizationKey: String\n    let name: String\n    let notes: [Note]\n}\n```\n\n### Examples\n\nGet a specific string instrument.\n\n```swift\nlet guitar: StringInstrument = .guitar\nlet ukulele: StringInstrument = .ukulele\nlet irishBouzouki: StringInstrument = .irishBouzouki\n```\n\nGet _all_ string instruments.\n\n```swift\nlet instruments: [StringInstrument] = StringInstrument.allCases\nlet instruments: [StringInstrument] = .allCases\n```\n\n\u003e _Collections provide an `.allCases` convenience extension, so you don't have to write out the name of the element each time._\n\nGet a specific tuning for an instrument.\n\n```swift\nlet guitarStandard: Tuning = Tuning.Guitar.standard.rawValue\n```\n\nGet _all_ tunings for an instrument.\n\n```swift\nlet guitarTunings: [Tuning] = StringInstrument.guitar.tunings\nlet guitarTunings: [Tuning] = Tuning.Guitar.allTunings\n```\n\n\u003e _`allTunings` is provided as a convenience for `allCases.map(\\.rawValue)`._\n\n#### Localization\n\nBy default, every `StringInstrument` and `Tuning` will be localized to `Locale.current`. However, you can also localize models on the fly simply by calling `.localized(to:)` with a `Locale`, locale identifier (`String`), or using the `SupportedLanguage` `enum`.\n\nLocalize a model.\n\n```swift\nlet guitarra: StringInstrument = .guitar.localized(to: \"es\")\nlet estandard: Tuning = Tuning.Guitar.standard.localized(to: \"es\")\n```\n\nLocalize a _collection_ of models.\n\n```swift\nlet spanishInstruments: [StringInstrument] = .allCases.localized(to: \"es\")\nlet spanishGuitarTunings: [Tuning] = Tuning.Guitar.allTunings.localized(to: \"es\")\n```\n\n### API\n\nLooking for localized instrument and tuning definitions but don't use Swift? No problem!\n\nAll instruments and tunings in this package are _also_ available by making API requests to [instruments.fyi](https://instruments.fyi). You can fetch all instruments, specific instruments, tunings, and more.\n\nFor more information, see [instruments.fyi](https://github.com/bdrelling/instruments.fyi) or visit [instruments.fyi](https://instruments.fyi).\n\n## Performance\n\n### Localization\n\n`String` localization usage in this module matches standard usage of `Bundle.localizedString(forKey:value:table:)` and `NSLocalizedString`. By initializing these strings through localization tables every time, it ensures that anyone consuming the module will get localization out of the box without any additional work, as they will always localize using `Locale.current`.\n\n### String Initialized Tunings\n\nSeeing the following in `Tuning+Definitions.swift` might make you uncomfortable:\n\n```swift\nenum Guitar: Tuning, CaseIterable {\n    case standard = \"standard: E2 A2 D3 G3 B3 E4\"\n    case dropD = \"drop_d: D2 A2 D3 G3 B3 E4\"\n    case openD = \"open_d: D2 A2 D3 F#3 A3 D4\"\n}\n```\n\nThis approach was not taken lightly. Instruments have dozens of commonly applicable tunings, and there are hundreds of instruments. Maintaining a large data set without an easy-to-parse method of analyzing, comparing, and fact-checking that data becomes extremely difficult over time.\n\n`String` parsing of a `Tuning` takes place in the special `init` at the bottom of `Tuning+Definitions.swift`. By making `Tuning` conform to `ExpressibleByStringLiteral`, it allows us to create `CaseIterable` enums that are easy to validate _and_ provide `Tuning` collection and organization functionality out of the box.\n\nThe logic is simple and very easy to validate: loop through _every `Tuning` in the project_ and if any of our localization keys in any of our supported languages come back with an error of any sort, numerous unit tests in the project will blow up.\n\nAdditionally, these enums are _only initialized once_, meaning that if you keep accessing one of these enums over and over, you can be sure that it won't be re-parsing the `Tuning` definition each time.\n\nIf you have an alternative to propose, feel free to open an issue or pull request. Several approaches were considered before landing on `String`-initialized `Tuning`s, but a fresh set of eyes is always helpful. If you have a performant way of defining this data that is type-safe yet provides the same level of convenience and readability (for maintenance and data accuracy), I'm interested!\n\n## Contributing\n\nDiscussions, issues, and pull requests are more than welcome, for development, corrections, and/or localizations.\n\nIf you're providing corrections and/or localizations, please provide as many additional sources as you can for validation in order to help ensure we can get the corrections integrated as quickly as possible.\n\n## Credits\n\nSpecial thanks to [AudioKit](https://github.com/AudioKit/AudioKit) for all of their expertise and support.\n\n## License\n\nThis project is released under the MIT license. See [LICENSE](/LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbdrelling%2Finstrumentkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbdrelling%2Finstrumentkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbdrelling%2Finstrumentkit/lists"}