-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Experimenting with C-API for patches.
See #3
- Loading branch information
Robin IT
committed
May 30, 2017
1 parent
d3b1e3a
commit f4f56d5
Showing
4 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
fmt: | ||
go fmt ./... | ||
|
||
lib: fmt | ||
go build -buildmode=c-shared -o build/libkatana.so ./capi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package main | ||
|
||
import "C" | ||
|
||
import ( | ||
"fmt" | ||
"unsafe" | ||
|
||
"github.com/katana-dev/lib-katana/patch" | ||
"github.com/katana-dev/lib-katana/sysex" | ||
) | ||
|
||
//Creates an interger reference to a new Patch. | ||
//export new_patch | ||
func new_patch() C.int { | ||
p, _ := patch.New(patch.EncSparse) | ||
n := trackObj(p) | ||
return C.int(n) | ||
} | ||
|
||
/** | ||
* Applies a sysex message to a patch. | ||
* | ||
* @param int Reference number | ||
* @param void* Byte array pointer | ||
* @param int Array length | ||
* @return char* CString message | ||
*/ | ||
//export apply_message_to_patch | ||
func apply_message_to_patch(n C.int, arr unsafe.Pointer, len C.int) *C.char { | ||
b := C.GoBytes(arr, len) | ||
m, err := sysex.Parse(b) | ||
if err != nil { | ||
return C.CString(err.Error()) | ||
} | ||
p := getObj(int32(n)).(patch.Patch) | ||
r := p.ApplyMessage(m) | ||
return C.CString(fmt.Sprintf("Wrote to ref %v > %+v\n", n, r)) | ||
} | ||
|
||
func main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package main | ||
|
||
import ( | ||
"C" | ||
"fmt" | ||
"sync" | ||
) | ||
|
||
//A single reference object. | ||
type ref struct { | ||
obj interface{} | ||
cnt int32 | ||
} | ||
|
||
//A singleton tracker for references. | ||
var t struct { | ||
sync.Mutex | ||
next int32 | ||
nums map[interface{}]int32 | ||
objs map[int32]ref | ||
} | ||
|
||
//Init tracking features. | ||
func initTracker() { | ||
if t.next != 0 { | ||
return | ||
} | ||
|
||
t.Lock() | ||
defer t.Unlock() | ||
t.next = 1 //Start at non-zero. | ||
t.nums = make(map[interface{}]int32) | ||
t.objs = make(map[int32]ref) | ||
} | ||
|
||
//Gets an object without manipulating the counter. | ||
func getObj(n int32) interface{} { | ||
initTracker() | ||
|
||
t.Lock() | ||
r, ok := t.objs[n] | ||
t.Unlock() | ||
if !ok { | ||
panic(fmt.Sprintf("getObj unknown reference number: %d", n)) | ||
} | ||
return r.obj | ||
} | ||
|
||
//Track a given Go object which is outbound. | ||
func trackObj(o interface{}) int32 { | ||
initTracker() | ||
|
||
t.Lock() | ||
defer t.Unlock() | ||
|
||
//Try deduplicate the reference. | ||
n := t.nums[o] | ||
if n != 0 { | ||
r := t.objs[n] | ||
t.objs[n] = ref{r.obj, r.cnt + 1} | ||
} else { | ||
//Push a new reference. | ||
t.next++ | ||
if t.next < 0 { | ||
panic("trackObj reference number overflow") | ||
} | ||
n = t.next | ||
t.nums[o] = n | ||
t.objs[n] = ref{o, 1} | ||
} | ||
|
||
return int32(n) | ||
} | ||
|
||
//Decrements the reference counter for given reference number, eventually deleting on zero. | ||
func releaseRef(n int32) { | ||
initTracker() | ||
|
||
t.Lock() | ||
defer t.Unlock() | ||
|
||
r, ok := t.objs[n] | ||
if !ok { | ||
panic(fmt.Sprintf("releaseRef unknown reference number: %d", n)) | ||
} | ||
|
||
//When this is the last reference, remove the entry from the maps. | ||
if r.cnt <= 1 { | ||
delete(t.objs, n) | ||
delete(t.nums, r.obj) | ||
} else { | ||
//Otherwise decrement. | ||
r := t.objs[n] | ||
t.objs[n] = ref{r.obj, r.cnt - 1} | ||
} | ||
} | ||
|
||
//Releases a reference generated before so it may be garbage collected. | ||
//export release_ref | ||
func release_ref(n C.int) { | ||
releaseRef(int32(n)) | ||
} |