Contains common infrastructural code for apps to communicate among computers, sound synthesizers, and other multimedia devices via OSC.

Related tags

Audio CoreOSC
Overview

“CoreOSC”/

CoreOSC

Build & Test License: MIT

The CoreOSC package contains common infrastructural code for your apps to communicate among computers, sound synthesizers, and other multimedia devices via OSC.

License

CoreOSC is licensed under the GNU Affero General Public License, version 3. If you require a commercial license for an application that you would not like to trigger AGPLv3 obligations (e.g. open sourcing your application), please get in touch.

Architecture

Addresses

An address has a similar syntax to a URL and begins with the character "/", followed by the names of all the containers, in order, along the path from the root of the tree to the method, separated by forward slash characters, followed by the name of the method. All types of addresses found in CoreOSC contain ASCII characters only, as specified in OSC 1.0.

OSC Address Pattern

An address pattern is an address to a potential destination of one ore more methods hosted by an "OSC Server". A number of wildcard characters, such as "*", can be used to allow for a single address pattern to invoke multiple methods.

let addressPattern = try? OSCAddressPattern("/core/osc/*")

Initialization of an OSCAddressPattern will throw if the format is incorrect or invalid characters are found in the given String.

A String can be evaluated to verify whether it is a valid address pattern by using the following:

let valid: Bool = OSCAddressPattern.evaluate("/core/osc/*")    

OSC Address

An address is the path to a method hosted by an "OSC Server". No wildcard characters are allowed as this address signifies the endpoint of an OSCMesage and the full path a message traverses to invoke the method associated with it.

let address = try? OSCAddress("/core/osc/method")

Initialization of an OSCAddress will throw if the format is incorrect or invalid characters are found in the given String.

A String can be evaluated to verify whether it is a valid address by using the following:

let valid: Bool = OSCAddress.evaluate("/core/osc/method")    

Messages

An OSCMessage is a packet formed of an OSCAddressPattern that directs it towards one or more methods hosted by an "OSC Server" and arguments that can be used when invoking the methods. CoreOSC implements all required argument types as specified in OSC 1.1.

Initialization with an OSCAddressPattern:

let addressPattern = try! OSCAddressPattern("/core/osc/*")
let message = OSCMessage(with: addressPattern,
                         arguments: [Int32(1),
                                     Float32(3.142),
                                     "Core OSC",
                                     OSCTimeTag.immediate,
                                     true,
                                     false,
                                     Data([0x01, 0x01]),
                                     OSCArgument.nil,
                                     OSCArgument.impulse])

Initialization with a raw address pattern String:

let message = try? OSCMessage(with: "/core/osc/*",
                              arguments: [Int32(1),
                                          Float32(3.142),
                                          "Core OSC",
                                          OSCTimeTag.immediate,
                                          true,
                                          false,
                                          Data([0x01, 0x01]),
                                          OSCArgument.nil,
                                          OSCArgument.impulse])

Initialization of an OSCMessage will throw if the format is incorrect or invalid characters are found in the given String address pattern.


Bundles

An OSCBundle is a container for messages, but also other bundles and allows for the invokation of multiple messages atomically as well scheduling them to be invoked at some point in the future. For further information regarding the temporal semantics of bundles and their associated OSCTimeTags, please see OSC 1.0.

let message1 = try! OSCMessage(with: "/core/osc/1")
let message2 = try! OSCMessage(with: "/core/osc/2")
let message3 = try! OSCMessage(with: "/core/osc/3")
    
let bundle = OSCBundle([message1, message2, message3], 
                       timetag: .immediate)

Address Spaces

An OSCAddressSpace is a set of methods hosted by an "OSC Server" that can be invoked by one or more OSCMessages. Think of it as a container for blocks of code, that can be dispatched when a message is received, with an address pattern that matches against a methods OSCAddress.

Methods

An OSCMethod is a struct that encapsulates a closure and the OSCAddress needed to invoke it. The idea is that if you wanted to make available control functionality within your application to "OSC Clients" you would begin by creating OSCMethods, adding them to an OSCAddressSpace and when an OSCMessage is received it would be passed to the address space to potentially invoke a method it contains.

For example:

let method = OSCMethod(with try! OSCAddress("object/coords"), invokedAction { [weak self] message, _ in
    guard message.arguments.count == 2,
          let x = message.argument[0] as? Float32, 
          let y = message.argument[1] as? Float32 else { return }
    print("Received /object/coords, x: \(x), y: \(y)"
    self?.object.x = x
    self?.object.y = y
})
    
var addressSpace = OSCAddressSpace(methods: [method])
    
let message = try! OSCMessage("object/coords", arguments: [Float32(3), Float32(5)])
addressSpace.invoke(with: message)
                                                     
print(object.x) // 3
print(object.y) // 5

Extensions

The following objects are not part of either OSC specification but have been developed after observation of implementations of OSC in the wild and aim to provide help and functionality for you to integrate with them.

Annotations

An OSC annotation is a script for writing an OSCMessage in a human readable format allowing you to enable your users to quickly create OSCMessages by typing them out as well as presenting them in logs. There are two available styles of annotation found in CoreOSC. It is strongly recommended that OSCAnnotationStyle.spaces is used, rather than OSCAnnotationStyle.equalsComma as it will allow you to use the valid "=" character in your OSCAddressPatterns.

A String can be evaluated to verify whether it is a valid annotation by using the following:

let annotation = "/core/osc 1 3.142 \"A string with spaces\" aString true false nil impulse"
let valid: Bool = OSCAnnotation.evaluate(annotation, style: .spaces)    

An OSCMessage can be initialized from a valid OSC annotation.

let annotation = "/core/osc 1 3.142 \"a string with spaces\" aString true"
    
let message = OSCAnnotation.message(for: annotation, style: .spaces)

print(message) // CoreOSC.OSCMessage(addressPattern: CoreOSC.OSCAddressPattern(fullPath: "/core/osc", parts: ["core", "osc"], methodName: "osc"), arguments: [1, 3.142, "a string with spaces", "aString", true])

An OSC annotation can be initialized from an OSCMessage.

let message = try! OSCMessage(with: "/core/osc",
                              arguments: [Int32(1),
                                          Float32(3.142),
                                          "Core OSC",
                                          true,
                                          false,
                                          OSCArgument.nil,
                                          OSCArgument.impulse])
// Without argument type tags.
let annotation1 = OSCAnnotation.annotation(for: message,
                                           style: .spaces,
                                           type: false)
                                               
print(annotation1) // "/core/osc 1 3.142 "Core OSC" true false nil impulse"
    
// With argument type tags.
let annotation2 = OSCAnnotation.annotation(for: message,
                                           style: .spaces,
                                           type: true)
                                               
print(annotation2) // "/core/osc 1(i) 3.142(f) "Core OSC"(s) true(T) false(F) nil(N) impulse(I)"

Address Filters

An OSCAddressFilter is kind of the reverse of an OSCAddressSpace. Where an address space allows for an address pattern to invoke multiple pre defined methods. An address filter allows for a single method to be invoked by multiple loosly formatted address patterns by using a "#" wildcard character and omitting parts from the pattern matching. Think of an address filter as a container for blocks of code, that can be dispatched when a message is received, with an address pattern that matches against a filter methods OSCFilterAddress.

Filter Methods

An OSCFilterMethod is a struct that encapsulates a closure and the OSCFilterAddress needed to invoke it. The idea is that if you wanted to make available control functionality within your application to "OSC Clients" without the overhead of establishing an address space containing an OSCAddress and method for each control functionality you would begin by creating OSCFilterMethods, adding them to an OSCAddressFilter and when an OSCMessage is received it would be passed to the address filter to potentially invoke a method it contains.

For example:

let method = OSCFilterMethod(with try! OSCAddress("cue/#/fired"), invokedAction { [weak self] message, _ in
    print("Received: \(message.addressPattern.fullPath)")
    self?.logs.append("Cue \(message.addressPattern.parts[1])")
})
    
var addressFilter = OSCAddressFilter(methods: [method])
    
let message1 = try! OSCMessage(with: "cue/1/fired")
addressFilter.invoke(with: message1)
    
let message2 = try! OSCMessage(with: "cue/2/fired")
addressFilter.invoke(with: message2)
    
let message3 = try OSCMessage(with: "cue/3/fired")
addressFilter.invoke(with: message3)
    
print(logs) // ["Cue 1", "Cue 2", "Cue 3"]

⚠️ - An OSCFilterAddress uses the "#" character, which has been specifically chosen because it is invalid within an OSCAddressPattern. Under no circumstances should you attempt to create an OSCMessage using an OSCFilterAddress as its address pattern.


Refracting

An OSCRefractingAddress can be used to "refract" an OSCAddressPattern to something else. The core idea for this object is to allow an "OSC Server" to act as a router, taking an OSCMessage from one application and routing it to another with modifcations made to the address pattern. Refracting is made possible by using an "#" wildcard character suffixed by a part index number (not 0 indexed). Where a wildcard is used within the refracting address the part will be replaced by the part from the given address pattern. To be succesful at refracting the suffixed index number must be valid with regards to the given address patterns number of parts.

let refractingAddress = try? OSCRefractingAddress("/core/#2/#4")
        
let addressPattern = try? OSCAddressPattern("/core/osc/refracting/test")
        
let refractedAddress: OSCAddressPattern = try? refractingAddress.refract(address: addressPattern)
        
print(refractedAddress!.fullPath) // "/core/osc/test"

A String can be evaluated to verify whether it is a valid refracting address by using the following:

let valid: Bool = OSCRefractingAddress.evaluate("/core/#2/#4")    

⚠️ - An OSCRefractingAddress uses the "#" character, which has been specifically chosen because it is invalid within an OSCAddressPattern. Under no circumstances should you attempt to create an OSCMessage using an OSCRefractingAddress as its address pattern.

To Do

  • Enhance the regexes for all address objects: OSCAddressPattern, OSCAddress, OSCRefractingAddress, OSCFilterAddress.
  • Enhance the evaluate(:String) function for all address objects: OSCAddressPattern, OSCAddress, OSCRefractingAddress, OSCFilterAddress.
  • Develop an API for invoking OSCMessages within OSCBundles and respecting the bundles OSCTimeTag.
  • Research and potentially implement OSCQuery.
  • Explore mapping OSCMethods within the OSCAddressSpace to a tree like data structure.

Authors

Sammy Smallman - Initial Work - SammySmallman

See also the list of contributors who participated in this project.

You might also like...
AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.
AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.

AudioPlayer AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.

Run iOS apps & games on M1 Mac with mouse, keyboard and controller support.
Run iOS apps & games on M1 Mac with mouse, keyboard and controller support.

‎ PlayCover Run iOS apps & games on M1 Mac with mouse, keyboard and controller support. Showcase · Contribute · Discord About the fork & Disclaimer Th

MusicalInstrument - Play musical instrument in just few lines of swift code

MusicalInstrument Play musical instrument in just few lines of swift code. Requi

An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and more.
An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and more.

SpotifyClone An iOS app that visually clones Spotify's app and consumes the official Spotify's Web API to show(and play) songs, podcasts, artists and

AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS, and tvOS.

AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS (including Catalyst), and tvOS. Installation To add AudioKit

MusicKit is a framework and DSL for creating, analyzing, and transforming music in Swift.

MusicKit MusicKit is a framework and DSL for creating, analyzing, and transforming music in Swift. Examples Functional harmony let C5 = Pitch(midi: 72

Voice Memos is an audio recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Swift.
Voice Memos is an audio recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Swift.

VoiceMemos Voice Memos is a voice recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Sw

Extensions and classes in Swift that make it easy to get an iOS device reading and processing MIDI data

MorkAndMIDI A really thin Swift layer on top of CoreMIDI that opens a virtual MIDI destination and port and connects to any MIDI endpoints that appear

An iOS and macOS audio visualization framework built upon Core Audio useful for anyone doing real-time, low-latency audio processing and visualizations.
An iOS and macOS audio visualization framework built upon Core Audio useful for anyone doing real-time, low-latency audio processing and visualizations.

A simple, intuitive audio framework for iOS and OSX. Deprecated EZAudio has recently been deprecated in favor of AudioKit. However, since some people

Comments
  • Trouble extracting message from client using OSCKit on Xcode

    Trouble extracting message from client using OSCKit on Xcode

    Hi,

    Basically I need help creating a handler for this specific address

    I'm having difficulty obtaining a single OSC message with a specific address pattern from a client. The client is called MindMonitor and I'm trying to stream EEG data to a UDP server on Xcode

    The problem is that I want to extract a specific address: "/muse/eeg". The client app is sending data with multiple addresses, but I want to only read a specific one. I can print the entire packet as a bundle, but because the client is sending multiple messages at multiple addresses, it's not always "/muse/eeg".

    EEG data: Screen Shot 2022-04-24 at 5 43 31 PM

    Gyro data: Screen Shot 2022-04-24 at 5 43 43 PM

    When I try to create a message to read from a specific address: let message1 = try! OSCMessage(with: "/muse/eeg") print(message1)

    I get no data and empty arguments:

    Screen Shot 2022-04-24 at 6 22 13 PM

    I'm not really sure how OSC works exactly, but I just want to receive incoming messages with the specific address "/muse/eeg" and ignore all the other messages with other addresses.

    I'm using the OSCKit package in Xcode, but that repo said to direct questions about address patterns and stuff to this one.

    Any help/advice would be really appreciated. I've spent lots of time experimenting with the code and trying to solve this problem

    Thanks!

    opened by allan1224 1
  • Adds OSCArgumentProtocol conformance to CGFloat

    Adds OSCArgumentProtocol conformance to CGFloat

    I'm creating a Float32 by truncating an NSNumber, created from a CGFloat. I've based the rest of this implementation on your Double implementation.

    This implementation is tested in my apps on iOS 14 and macOS 11. Tho I'm not sure how far backwards compatible the implementation is.

    opened by heestand-xyz 1
Owner
Sammy Smallman
Founder of @artifice-industries
Sammy Smallman
A sound fader for AVAudioPlayer written in Swift for iOS, tvOS and macOS.

Cephalopod, a sound fader for AvAudioPlayer written in Swift - iOS, tvOS and macOS This library can help fading sounds in and out with AvAudioPlayer.

Evgenii Neumerzhitckii 109 Dec 16, 2022
Play and share sound inserts from Medo e Delírio em Brasília, a Brazilian podcast.

Play and share sound inserts from Medo e Delírio em Brasília, a Brazilian podcast.

Rafael Schmitt 18 Dec 26, 2022
AudioKit Sample Player (ROM Player) - EXS24, Sound Font, Wave Player

AudioKit ROM / Sample Player Welcome to the official AudioKit example of a sample-based music instrument written in Swift. It can be modified to play

AudioKit 500 Dec 27, 2022
iOS framework for the Quiet Modem (data over sound)

QuietModemKit This is the iOS framework for https://github.com/quiet/quiet With this library, you can send data through sound. Live demo: https://quie

Quiet Modem Project 442 Nov 17, 2022
PitchPerfect - A simple iOS app for the Udacity Nanodegree which explores AVFoundation to record a short sound

PitchPerfect App A simple iOS app for the Udacity Nanodegree which explores AVFo

Mark Han 0 Feb 12, 2022
A charmful decade with many colors patterns, disco music, and other cultural expressions that we refer to as vintage

MontyHallProblem Welcome to the 70s! ?? That is a charmful decade with many colors patterns, disco music, and other cultural expressions that we refer

Diogo Infante 2 Dec 28, 2021
Swift Xcode Project that demonstrates how to set up a microphone input via AudioKit verions 5.

AudioKit Mic Input Swift Xcode Project that demonstrates how to set up a microphone input via AudioKit verions 5. Be sure to plug in headphones in ord

Mark Jeschke 0 Oct 23, 2021
Learn to Code While Building Apps - The Complete iOS Development Bootcamp

Xylophone Our Goal The goal of this tutorial is to dive into a simple iOS recipe - how to play sound and use an Apple library called AVFoundation. The

The App Brewery 83 Jan 6, 2023
HomeHub - Swift app to control my home's smart devices + show spotify current playback

HomeHub iPad app to control my home's smart devices + show spotify current playb

Cooper Bell 2 Oct 22, 2022
Automated Apple Music Lossless Sample Rate Switching for Audio Devices on Macs.

LosslessSwitcher switches your current audio device's sample rate to match the currently playing lossless song on your Apple Music app, automatically.

Vincent Neo 371 Dec 27, 2022