diff --git a/cmd/makeosc/makeosc.go b/cmd/makeosc/makeosc.go index 51730b3..7c956f1 100644 --- a/cmd/makeosc/makeosc.go +++ b/cmd/makeosc/makeosc.go @@ -6,7 +6,7 @@ import ( "os" "strconv" - "github.com/jwetzell/osc-go/pkg/osc" + "github.com/chabad360/go-osc/osc" "github.com/spf13/cobra" ) @@ -31,47 +31,35 @@ func main() { rootCmd.Execute() } -func argToTypedArg(rawArg string, oscType string) osc.OSCArg { +func argToTypedArg(rawArg string, oscType string) any { switch oscType { case "s": - return osc.OSCArg{ - Type: "s", - Value: rawArg, - } + return rawArg case "i": number, err := strconv.ParseInt(rawArg, 10, 32) if err != nil { // ... handle error panic(err) } - return osc.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 osc.OSCArg{ - Type: "f", - Value: float32(number), - } + return float32(number) case "b": data, err := hex.DecodeString(rawArg) if err != nil { // ... handle error panic(err) } - return osc.OSCArg{ - Type: "b", - Value: data, - } + return data default: fmt.Print("unhandled osc type: ") fmt.Printf("%s.\n", oscType) - return osc.OSCArg{} + return rawArg } } @@ -99,7 +87,7 @@ func slipEncode(bytes []byte) []byte { func make(address string, args []string, types []string, slip bool) { - oscArgs := []osc.OSCArg{} + oscMessage := osc.NewMessage(address) for index, arg := range args { oscType := "s" @@ -107,21 +95,20 @@ func make(address string, args []string, types []string, slip bool) { oscType = types[index] } - oscArgs = append(oscArgs, argToTypedArg(arg, oscType)) + oscMessage.Append(argToTypedArg(arg, oscType)) } - oscMessage := osc.OSCMessage{ - Address: address, - Args: oscArgs, - } + oscMessageBuffer, err := oscMessage.MarshalBinary() - oscMessageBuffer := osc.ToBytes(oscMessage) + if err != nil { + panic(err) + } if slip { oscMessageBuffer = slipEncode(oscMessageBuffer) } //TODO write buffer to stdout - os.Stdout.Write(oscMessageBuffer[:]) + os.Stdout.Write(oscMessageBuffer) } diff --git a/cmd/receiveosc/receiveosc.go b/cmd/receiveosc/receiveosc.go index 8455a6f..5c5c923 100644 --- a/cmd/receiveosc/receiveosc.go +++ b/cmd/receiveosc/receiveosc.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - "github.com/jwetzell/osc-go/pkg/osc" + "github.com/chabad360/go-osc/osc" "github.com/spf13/cobra" ) @@ -50,7 +50,7 @@ func listen(netAddress string) { panic(err) } - oscMessage, err := osc.FromBytes(buffer[0:bytesRead]) + oscMessage, err := osc.NewMessageFromData(buffer[0:bytesRead]) if err != nil { panic(err) diff --git a/cmd/sendosc/sendosc.go b/cmd/sendosc/sendosc.go index c83c4ba..d5a64ad 100644 --- a/cmd/sendosc/sendosc.go +++ b/cmd/sendosc/sendosc.go @@ -6,7 +6,7 @@ import ( "net" "strconv" - "github.com/jwetzell/osc-go/pkg/osc" + "github.com/chabad360/go-osc/osc" "github.com/spf13/cobra" ) @@ -39,47 +39,35 @@ func main() { rootCmd.Execute() } -func argToTypedArg(rawArg string, oscType string) osc.OSCArg { +func argToTypedArg(rawArg string, oscType string) any { switch oscType { case "s": - return osc.OSCArg{ - Type: "s", - Value: rawArg, - } + return rawArg case "i": number, err := strconv.ParseInt(rawArg, 10, 32) if err != nil { // ... handle error panic(err) } - return osc.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 osc.OSCArg{ - Type: "f", - Value: float32(number), - } + return float32(number) case "b": data, err := hex.DecodeString(rawArg) if err != nil { // ... handle error panic(err) } - return osc.OSCArg{ - Type: "b", - Value: data, - } + return data default: fmt.Print("unhandled osc type: ") fmt.Printf("%s.\n", oscType) - return osc.OSCArg{} + return rawArg } } @@ -107,7 +95,7 @@ func slipEncode(bytes []byte) []byte { func send(host string, port int32, address string, args []string, types []string, protocol string, slip bool) { - oscArgs := []osc.OSCArg{} + oscMessage := osc.NewMessage(address) for index, arg := range args { oscType := "s" @@ -115,15 +103,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 := osc.OSCMessage{ - Address: address, - Args: oscArgs, - } + oscMessageBuffer, err := oscMessage.MarshalBinary() - oscMessageBuffer := osc.ToBytes(oscMessage) + if err != nil { + panic(err) + } if slip { oscMessageBuffer = slipEncode(oscMessageBuffer) diff --git a/go.mod b/go.mod index 5676d56..e897e63 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ 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/spf13/cobra v1.8.1 +) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 912390a..ebd0d37 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= diff --git a/pkg/osc/osc.go b/pkg/osc/osc.go deleted file mode 100644 index 962d466..0000000 --- a/pkg/osc/osc.go +++ /dev/null @@ -1,262 +0,0 @@ -package osc - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "math" - "strings" -) - -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 { - //TODO(jwetzell): add error handling - 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.Printf("unhandled osc type: %s.\n") - } - } - return argBuffers -} - -func ToBytes(message OSCMessage) []byte { - //TODO(jwetzell): add error handling - 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 readOSCString(bytes []byte) (string, []byte) { - //TODO(jwetzell): add error handling - oscString := "" - stringFinished := false - stringEndIndex := 0 - remainingBytes := []byte{} - - for index, byteIn := range bytes { - if !stringFinished { - if byteIn == 0 { - oscString = string(bytes[0:index]) - stringEndIndex = index + 1 - break - } - } - } - - stringPadding := 4 - (stringEndIndex % 4) - - if stringPadding < 4 { - stringEndIndex = stringEndIndex + stringPadding - } - - remainingBytes = bytes[stringEndIndex:] - - return oscString, remainingBytes -} - -func readOSCInt(bytes []byte) (int32, []byte, error) { - if len(bytes) < 4 { - return 0, bytes, errors.New("int data must be at least 4 bytes large") - } - bits := binary.BigEndian.Uint32(bytes[0:4]) - return int32(bits), bytes[4:], nil -} - -func readOSCFloat(bytes []byte) (float32, []byte, error) { - if len(bytes) < 4 { - return 0, bytes, errors.New("float data must be at least 4 bytes large") - } - bits := binary.BigEndian.Uint32(bytes[0:4]) - return math.Float32frombits(bits), bytes[4:], nil -} - -func readOSCBlob(bytes []byte) ([]byte, []byte, error) { - blobLength, remainingBytes, err := readOSCInt(bytes) - - if err != nil { - return []byte{}, bytes, errors.New("problem reading blob data size") - } - - if len(remainingBytes) < int(blobLength) { - return []byte{}, bytes, errors.New("blob data specified a size larger than the remaining message data") - } - - blobLengthPadding := 4 - (blobLength % 4) - blobEnd := 4 + blobLength - - if blobLengthPadding < 4 { - blobEnd = blobEnd + blobLengthPadding - } - return bytes[4 : 4+blobLength], bytes[blobEnd:], nil -} - -func readOSCArg(bytes []byte, oscType string) (OSCArg, []byte, error) { - var readArgError error - - oscArg := OSCArg{} - oscArg.Type = oscType - - remainingBytes := []byte{} - //TODO(jwetzell): add error handling - switch oscType { - case "s": - argString, bytesLeft := readOSCString(bytes) - oscArg.Value = argString - remainingBytes = bytesLeft - case "i": - argInt, bytesLeft, error := readOSCInt(bytes) - if error != nil { - readArgError = error - } - oscArg.Value = argInt - remainingBytes = bytesLeft - case "f": - argFloat, bytesLeft, error := readOSCFloat(bytes) - if error != nil { - readArgError = error - } - oscArg.Value = argFloat - remainingBytes = bytesLeft - case "b": - argBytes, bytesLeft, error := readOSCBlob(bytes) - if error != nil { - readArgError = error - } - oscArg.Value = argBytes - remainingBytes = bytesLeft - default: - fmt.Printf("unsupported osc type: %s\n", oscType) - readArgError = errors.New("unsupported osc type: " + oscType) - } - return oscArg, remainingBytes, readArgError -} - -func FromBytes(bytes []byte) (OSCMessage, error) { - //TODO(jwetzell): add Message and Bundle support - address, typeAndArgBytes := readOSCString(bytes) - - oscMessage := OSCMessage{ - Address: address, - Args: []OSCArg{}, - } - - typeString, argBytes := readOSCString(typeAndArgBytes) - - for index, oscType := range typeString { - if index == 0 { - if oscType != ',' { - return OSCMessage{}, errors.New("type string is malformed") - } - } else { - oscArg, remainingBytes, error := readOSCArg(argBytes, string(oscType)) - if error != nil { - return oscMessage, error - } - argBytes = remainingBytes - oscMessage.Args = append(oscMessage.Args, oscArg) - } - } - - return oscMessage, nil -}