Compare commits

..

19 Commits

Author SHA1 Message Date
jwetzell 8ecda737e4 one more try 2024-10-21 15:19:22 -05:00
jwetzell 24dabc86dd try something else 2024-10-21 15:15:40 -05:00
jwetzell 3790e83b9c fix binary name and workflow dependency 2024-10-21 15:00:07 -05:00
jwetzell d60515863e rework sendosc release workflow 2024-10-21 14:48:43 -05:00
jwetzell defe4e1a3d Create LICENSE 2024-10-21 14:37:10 -05:00
jwetzell 9990c08f70 Merge pull request #1 from jwetzell/add-more-osc-types
Add more osc types
2024-10-21 14:35:32 -05:00
jwetzell 5f4ab5bbb8 add OSC nil type 2024-10-21 14:31:13 -05:00
jwetzell 1de7be013e add osc true and false types 2024-10-21 14:30:44 -05:00
jwetzell 5dc08cd907 add osc double type 2024-10-21 14:29:27 -05:00
jwetzell e8f0fb7d14 add osc int64 type 2024-10-21 14:28:48 -05:00
jwetzell 95a076717f try upstream osc lib as well 2024-09-30 18:33:06 -05:00
jwetzell 1fa6f5fbcc Create README.md 2024-09-30 12:41:48 -05:00
jwetzell 32212ce256 switch to an OSC library 2024-09-30 12:34:18 -05:00
jwetzell d19f0cd1ff add script to send osc bytes to stdout 2024-09-29 23:15:02 -05:00
jwetzell 2bba8da489 todo comments 2024-09-29 18:27:32 -05:00
jwetzell 9b17a6c662 add basic script for receiving osc 2024-09-29 18:27:24 -05:00
jwetzell 46fcdfd944 add parsing of OSC Messages only 2024-09-29 18:20:23 -05:00
jwetzell 21b61db4c9 rename ToBuffer to ToBytes 2024-09-29 15:56:51 -05:00
jwetzell a2a211dfe3 restructure to more generic go module 2024-09-29 15:50:25 -05:00
8 changed files with 264 additions and 149 deletions
@@ -1,16 +1,32 @@
name: "release go binaries for multiple os/arch"
on:
release:
types: [created]
push:
tags:
- 'sendosc/*'
permissions:
contents: write
packages: write
jobs:
create-release:
name: Create sendosc release
runs-on: ubuntu-latest
steps:
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
release-multi:
name: Release Go Binary
name: create binaries and upload
needs: create-release
runs-on: ubuntu-latest
strategy:
matrix:
@@ -29,3 +45,5 @@ jobs:
goversion: "1.23.1"
project_path: "./cmd/sendosc"
binary_name: "sendosc"
asset_name: sendosc-${{ matrix.goos }}-${{ matrix.goarch }}
release_name: ${{github.ref_name}}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Joel Wetzell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+5
View File
@@ -0,0 +1,5 @@
A collection of command line OSC utilities written in Go. Mainly an exercise in learning Go.
# `sendosc`
# `makeosc`
# `receiveosc`
+114
View File
@@ -0,0 +1,114 @@
package main
import (
"encoding/hex"
"fmt"
"os"
"strconv"
"github.com/hypebeast/go-osc/osc"
"github.com/spf13/cobra"
)
func main() {
var Address string
var Args []string
var Types []string
var Slip bool
var rootCmd = &cobra.Command{
Use: "sendosc",
Run: func(cmd *cobra.Command, args []string) {
make(Address, Args, Types, Slip)
},
}
rootCmd.Flags().StringVar(&Address, "address", "", "OSC address")
rootCmd.Flags().StringArrayVar(&Args, "arg", []string{}, "OSC args")
rootCmd.Flags().StringArrayVar(&Types, "type", []string{}, "OSC types")
rootCmd.Flags().BoolVar(&Slip, "slip", false, "whether to slip encode the OSC Message bytes")
rootCmd.MarkFlagRequired("address")
rootCmd.Execute()
}
func argToTypedArg(rawArg string, oscType string) any {
switch oscType {
case "s":
return rawArg
case "i":
number, err := strconv.ParseInt(rawArg, 10, 32)
if err != nil {
// ... handle error
panic(err)
}
return int32(number)
case "f":
number, err := strconv.ParseFloat(rawArg, 32)
if err != nil {
// ... handle error
panic(err)
}
return float32(number)
case "b":
data, err := hex.DecodeString(rawArg)
if err != nil {
// ... handle error
panic(err)
}
return data
default:
fmt.Print("unhandled osc type: ")
fmt.Printf("%s.\n", oscType)
return rawArg
}
}
func slipEncode(bytes []byte) []byte {
END := byte(0xc0)
ESC := byte(0xdb)
ESC_END := byte(0xdc)
ESC_ESC := byte(0xdd)
var encodedBytes = []byte{}
for _, byteToEncode := range bytes {
if byteToEncode == END {
encodedBytes = append(encodedBytes, ESC_END)
} else if byteToEncode == ESC {
encodedBytes = append(encodedBytes, ESC_ESC)
} else {
encodedBytes = append(encodedBytes, byteToEncode)
}
}
encodedBytes = append(encodedBytes, END)
return encodedBytes
}
func make(address string, args []string, types []string, slip bool) {
oscMessage := osc.NewMessage(address)
for index, arg := range args {
oscType := "s"
if len(types) > index {
oscType = types[index]
}
oscMessage.Append(argToTypedArg(arg, oscType))
}
oscMessageBuffer, err := oscMessage.MarshalBinary()
if err != nil {
panic(err)
}
if slip {
oscMessageBuffer = slipEncode(oscMessageBuffer)
}
//TODO write buffer to stdout
os.Stdout.Write(oscMessageBuffer)
}
+60
View File
@@ -0,0 +1,60 @@
package main
import (
"fmt"
"net"
"github.com/chabad360/go-osc/osc"
"github.com/spf13/cobra"
)
func main() {
var Host string
var Port string
var rootCmd = &cobra.Command{
Use: "sendosc",
Run: func(cmd *cobra.Command, args []string) {
netAddress := Host + ":" + Port
listen(netAddress)
},
}
rootCmd.Flags().StringVar(&Host, "host", "127.0.0.1", "host to send OSC message to")
rootCmd.Flags().StringVar(&Port, "port", "8888", "port to send OSC message to")
rootCmd.Execute()
}
func listen(netAddress string) {
s, err := net.ResolveUDPAddr("udp4", netAddress)
if err != nil {
fmt.Println(err)
return
}
connection, err := net.ListenUDP("udp4", s)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("listening on %s (udp)\n", netAddress)
defer connection.Close()
buffer := make([]byte, 1024)
for {
bytesRead, _, err := connection.ReadFromUDP(buffer)
if err != nil {
panic(err)
}
oscMessage, err := osc.NewMessageFromData(buffer[0:bytesRead])
if err != nil {
panic(err)
}
fmt.Println(oscMessage)
}
}
+33 -144
View File
@@ -1,134 +1,16 @@
package main
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"net"
"strconv"
"strings"
"github.com/hypebeast/go-osc/osc"
"github.com/spf13/cobra"
)
type OSCArg struct {
Type string
Value any
}
type OSCMessage struct {
Address string
Args []OSCArg
}
func stringToOSCBytes(rawString string) []byte {
var sb strings.Builder
sb.WriteString(rawString)
sb.WriteString("\u0000")
padLength := 4 - (len(sb.String()) % 4)
if padLength < 4 {
for i := 0; i < padLength; i++ {
sb.WriteString("\u0000")
}
}
return []byte(sb.String())
}
func integerToOSCBytes(number int32) []byte {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, number)
if err != nil {
panic(err)
}
return buf.Bytes()
}
func floatToOSCBytes(number float32) []byte {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, number)
if err != nil {
panic(err)
}
return buf.Bytes()
}
func byteArrayToOSCBytes(bytes []byte) []byte {
oscBytes := []byte{}
bytesSize := len(bytes)
oscBytes = append(oscBytes, integerToOSCBytes(int32(bytesSize))...)
oscBytes = append(oscBytes, bytes...)
padLength := 4 - (bytesSize % 4)
if padLength < 4 {
for i := 0; i < padLength; i++ {
oscBytes = append(oscBytes, 0)
}
}
return oscBytes
}
func argsToBuffer(args []OSCArg) []byte {
var argBuffers = []byte{}
for _, arg := range args {
switch oscType := arg.Type; oscType {
case "s":
if value, ok := arg.Value.(string); ok {
argBuffers = append(argBuffers, stringToOSCBytes(value)...)
} else {
fmt.Println("OSC arg had string type but non-string value.")
}
case "i":
if value, ok := arg.Value.(int32); ok {
argBuffers = append(argBuffers, integerToOSCBytes(value)...)
} else {
fmt.Println("OSC arg had integer type but non-integer value.")
}
case "f":
if value, ok := arg.Value.(float32); ok {
argBuffers = append(argBuffers, floatToOSCBytes(value)...)
} else {
fmt.Println("OSC arg had float type but non-float value.")
}
case "b":
if value, ok := arg.Value.([]byte); ok {
argBuffers = append(argBuffers, byteArrayToOSCBytes(value)...)
} else {
fmt.Println("OSC arg had blob type but non-blob value.")
}
default:
fmt.Print("unhandled osc type: ")
fmt.Printf("%s.\n", oscType)
}
}
return argBuffers
}
func messageToBuffer(message OSCMessage) []byte {
oscBuffer := []byte{}
oscBuffer = append(oscBuffer, stringToOSCBytes(message.Address)...)
var sb strings.Builder
sb.WriteString(",")
for _, arg := range message.Args {
sb.WriteString(arg.Type)
}
oscBuffer = append(oscBuffer, stringToOSCBytes(sb.String())...)
oscBuffer = append(oscBuffer, argsToBuffer(message.Args)...)
return oscBuffer
}
func main() {
var Host string
var Port int32
@@ -157,47 +39,55 @@ func main() {
rootCmd.Execute()
}
func argToTypedArg(rawArg string, oscType string) OSCArg {
func argToTypedArg(rawArg string, oscType string) any {
switch oscType {
case "s":
return OSCArg{
Type: "s",
Value: rawArg,
}
return rawArg
case "i":
number, err := strconv.ParseInt(rawArg, 10, 32)
if err != nil {
// ... handle error
panic(err)
}
return OSCArg{
Type: "i",
Value: int32(number),
}
return int32(number)
case "f":
number, err := strconv.ParseFloat(rawArg, 32)
if err != nil {
// ... handle error
panic(err)
}
return OSCArg{
Type: "f",
Value: float32(number),
}
return float32(number)
case "b":
data, err := hex.DecodeString(rawArg)
if err != nil {
// ... handle error
panic(err)
}
return OSCArg{
Type: "b",
Value: data,
return data
case "h":
number, err := strconv.ParseInt(rawArg, 10, 64)
if err != nil {
// ... handle error
panic(err)
}
return int64(number)
case "d":
number, err := strconv.ParseFloat(rawArg, 64)
if err != nil {
// ... handle error
panic(err)
}
return float64(number)
case "T":
return true
case "F":
return false
case "N":
return nil
default:
fmt.Print("unhandled osc type: ")
fmt.Printf("%s.\n", oscType)
return OSCArg{}
return rawArg
}
}
@@ -225,7 +115,7 @@ func slipEncode(bytes []byte) []byte {
func send(host string, port int32, address string, args []string, types []string, protocol string, slip bool) {
oscArgs := []OSCArg{}
oscMessage := osc.NewMessage(address)
for index, arg := range args {
oscType := "s"
@@ -233,15 +123,14 @@ func send(host string, port int32, address string, args []string, types []string
oscType = types[index]
}
oscArgs = append(oscArgs, argToTypedArg(arg, oscType))
oscMessage.Append(argToTypedArg(arg, oscType))
}
oscMessage := OSCMessage{
Address: address,
Args: oscArgs,
}
oscMessageBuffer, err := oscMessage.MarshalBinary()
oscMessageBuffer := messageToBuffer(oscMessage)
if err != nil {
panic(err)
}
if slip {
oscMessageBuffer = slipEncode(oscMessageBuffer)
+6 -2
View File
@@ -1,8 +1,12 @@
module sendosc
module github.com/jwetzell/osc-go
go 1.23.1
require github.com/spf13/cobra v1.8.1
require (
github.com/chabad360/go-osc v0.0.0-20220502185613-216f362cdf0a
github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5
github.com/spf13/cobra v1.8.1
)
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+4
View File
@@ -1,4 +1,8 @@
github.com/chabad360/go-osc v0.0.0-20220502185613-216f362cdf0a h1:MTor/GgULww+hISVbeiNuC5vyT1mc2xa6/14ib0lvyc=
github.com/chabad360/go-osc v0.0.0-20220502185613-216f362cdf0a/go.mod h1:/aAn5LNn+s7zq33XItIcYLr6aOntVkWckHPAG40yeUc=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5 h1:fqwINudmUrvGCuw+e3tedZ2UJ0hklSw6t8UPomctKyQ=
github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5/go.mod h1:lqMjoCs0y0GoRRujSPZRBaGb4c5ER6TfkFKSClxkMbY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=