Code Monkey home page Code Monkey logo

portmidi's Introduction

portmidi

Want to output to an MIDI device or listen your MIDI device as an input? This package contains Go bindings for PortMidi. libportmidi (v. 217) is required as a dependency, it's available via apt-get and brew.

apt-get install libportmidi-dev
# or
brew install portmidi

Or, alternatively you can download the source and build it by yourself. See the instructions on PortMidi homepage.

In order to start, go get this repository:

go get github.com/rakyll/portmidi

Usage

Initialize

portmidi.Initialize()

About MIDI Devices

portmidi.CountDevices() // returns the number of MIDI devices
portmidi.Info(deviceID) // returns info about a MIDI device
portmidi.DefaultInputDeviceID() // returns the ID of the system default input
portmidi.DefaultOutputDeviceID() // returns the ID of the system default output

Write to a MIDI Device

out, err := portmidi.NewOutputStream(deviceID, 1024, 0)
if err != nil {
    log.Fatal(err)
}

// note on events to play C major chord
out.WriteShort(0x90, 60, 100)
out.WriteShort(0x90, 64, 100)
out.WriteShort(0x90, 67, 100)

// notes will be sustained for 2 seconds
time.Sleep(2 * time.Second)

// note off events
out.WriteShort(0x80, 60, 100)
out.WriteShort(0x80, 64, 100)
out.WriteShort(0x80, 67, 100)

out.Close()

Read from a MIDI Device

in, err := portmidi.NewInputStream(deviceID, 1024)
if err != nil {
    log.Fatal(err)
}
defer in.Close()

events, err := in.Read(1024)
if err != nil {
    log.Fatal(err)
}

// alternatively you can filter the input to listen
// only a particular set of channels
in.SetChannelMask(portmidi.Channel(1) | portmidi.Channel.(2))
in.Read(1024) // will retrieve events from channel 1 and 2

// or alternatively listen events
ch := in.Listen()
event := <-ch

Cleanup

Cleanup your input and output streams once you're done. Likely to be called on graceful termination.

portmidi.Terminate()

portmidi's People

Contributors

adiknoth avatar ironiridis avatar jmacd avatar kisielk avatar lukegb avatar mattetti avatar mickacka avatar mofeing avatar orivej avatar rakyll avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

portmidi's Issues

Channel filtering doesn't look right ...

I haven't tried it yet but I've just been reading the code

You define:

type Channel int

So using a filter that's Channel(1) | Channel(3) will just get me channel 3...

The C version has a macro called Pm_Channel which is 1 << channel so I think you probably want to change Channel to be a function that returns the same in order to generate a bitmask.

Could not determine kind of name

I have included the
#include <portmidi.h>
#include <porttime.h>
libraries and everything compiles fine, but I get the following errors on runtime.

# github.com/rakyll/portmidi
could not determine kind of name for C.PmDeviceID
could not determine kind of name for C.PmError
could not determine kind of name for C.Pm_CountDevices
could not determine kind of name for C.Pm_GetDefaultInputDeviceID
could not determine kind of name for C.Pm_GetDefaultOutputDeviceID
could not determine kind of name for C.Pm_GetDeviceInfo
could not determine kind of name for C.Pm_Initialize
could not determine kind of name for C.Pm_Terminate
could not determine kind of name for C.Pt_Start
could not determine kind of name for C.Pt_Stop
could not determine kind of name for C.Pt_Time

Does anyone have any idea what this can come from?
Sorry if its a noob question, I'm pretty new to Go and thanks for help!

'portmidi.h' file not found

I am running OS X 10.10.1. I have installed portmidi v217 via homebrew, and I have verified that the header files are linked from /usr/local/Cellar/portmidi/217/include/ to /usr/local/include.

When I run "go get github.com/rakyll/portmidi" or "go install" it errors:

./portmidi.go:20:11: fatal error: 'portmidi.h' file not found
 #include <portmidi.h>
          ^
1 error generated.

I am brand new to Go -- really just want to use it for music. Any idea how to get this working? Thanks.

Segv when reading and writing a storm of events

On Macos 10.14.6 (Mojave)
go 1.14.1
gitlab.com/gomidi/portmididrv v0.6.0
portmidi installed via homebrew - version 217_2

This looks very similar to #36 . I tried setting GODEBUG as described there, but don't see anything in the log. I've been successfully using the library for some prototyping, but now get this seg fault whenever my app processes a quick stream of events (each inbound event triggers a corresponding outbound event and soon after the first in the storm, the app crashes). If I break the cycle (process inbound events, but don't immediately send an outbound event in response - or just send a bunch of outbound events), everything works fine. Could there be some problem with attempting to write at same time the read listener is still processing an inbound event?

Help?

[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x7fff4d85068b]

runtime stack:
runtime.throw(0x151c3e9, 0x2a)
	/usr/local/go/src/runtime/panic.go:1114 +0x72
runtime.sigpanic()
	/usr/local/go/src/runtime/signal_unix.go:679 +0x46a

goroutine 1789 [syscall]:
runtime.cgocall(0x10025e0, 0xc00070ec88, 0xc00031e300)
	/usr/local/go/src/runtime/cgocall.go:133 +0x5b fp=0xc00070ec58 sp=0xc00070ec20 pc=0x100616b
github.com/rakyll/portmidi._Cfunc_Pm_Write(0x68016b0, 0xc00051ccc8, 0x1, 0x0)
	_cgo_gotypes.go:302 +0x4d fp=0xc00070ec88 sp=0xc00070ec58 pc=0x11d8c4d
github.com/rakyll/portmidi.(*Stream).Write.func1(0xc000052140, 0xc00051ccc8, 0x1, 0x1, 0x1, 0xc00070ed00)
	/Users/tynor/go/pkg/mod/github.com/rakyll/[email protected]/stream.go:120 +0x73 fp=0xc00070ecc0 sp=0xc00070ec88 pc=0x11da173
github.com/rakyll/portmidi.(*Stream).Write(0xc000052140, 0xc00070ed30, 0x1, 0x1, 0x100fae8, 0x3)
	/Users/tynor/go/pkg/mod/github.com/rakyll/[email protected]/stream.go:120 +0xc5 fp=0xc00070ed00 sp=0xc00070ecc0 pc=0x11d95c5
github.com/rakyll/portmidi.(*Stream).WriteShort(0xc000052140, 0xbf, 0x73, 0x1c, 0xc00070eda3, 0xc00051ccc3)
	/Users/tynor/go/pkg/mod/github.com/rakyll/[email protected]/stream.go:131 +0x84 fp=0xc00070ed60 sp=0xc00070ed00 pc=0x11d96a4
gitlab.com/gomidi/portmididrv.(*out).Write(0xc0001b49f0, 0xc00051ccc3, 0x3, 0x3, 0x5cb97d0, 0x0, 0xc00011e340)
	/Users/tynor/go/pkg/mod/gitlab.com/gomidi/[email protected]/out.go:43 +0x79 fp=0xc00070ede8 sp=0xc00070ed60 pc=0x11db619

Read(max int) errors on system real time messages

MIDI System Real Time Messages are captured by if event.Status&0xF0 == 0xF0 in stream.Read and return an error because they are not SysEx messages.

There's no data payload for system real time messages so I think there could just be a literal check for messages with a status between 0xF8 and 0xFF.
I'm happy to make that as a PR but I don't want to be presumptuous. I'm pretty new to this repo and to MIDI system messages in general.

How to send output and have the timestamps be honored?

Hi.

Thank you for writing this. I am playing around and have a question. I can send output using WriteShort, and then sleep until sending the next event.

But, what I really have is a []portmidi.Event, which already include timestamp information. It seems like I should be able to just call:

out, err := portmidi.NewOutputStream(output, 1024, 0)
out.Write(events) # events is []portmidi.Event recorded just before this call.

and have it play. But the timing isn't respected, so everything goes very quickly.

I tried setting the latency in the NewOutputStream call to various values (based on the C code, that's the only time that timestamps are actually used), but that doesn't seem to work. (I thought that setting it to portmidi.Time() would offset it correctly from the reads I did just before...)

Do you know how I can pass in a list of Events and just have them played with the timing information honored? It seems silly that I would have to do that in my code :)

Thank you
Dan

Golang MIDI collaboration

Hi Jaana,

I am writing to you, since you worked on MIDI and I wrote a rather complete library in the last weeks that should serve as a toolkit for creating MIDI based applications.

I would like to invite to help out, making it a common standard for MIDI with Go, by providing you insight and expertise.

I spend some effort to have a common API for live and SMF messages/events.
A second major priority was to make lots of mostly independent small packages to allow
small devices to just use what they need.

The other top priority is to make the API stable as in: no breakage.

Anyway I created the github group "gomidi" and already invited you -
would be glad to have you on board.

The core repo is:
https://github.com/gomidi/midi

and there are two simple applications

https://github.com/gomidi/midispy
and
https://github.com/gomidi/smfimage

making use of the core.

Where you could help out:

  • naming, I want to nail down to get the API stable, see https://github.com/gomidi/midi/issues/3
  • ideas for the best abstraction of PitchBend and KeySignature (they are working but
    I am not sure, I covered all use cases and in the best way).
  • obviously testing and more obscure applications I might not have thought of
  • build higher level tools (quantization, what not) on top of it
  • seemless integration with your portmidi lib?

I did not announce the library yet, since I first wanted to get some feedback from developers that delved into the MIDI standard.... ;-)

What do you think?

Looking forward to hear from you.

Cheers,
Benny
(github.com/metakeule)

Why "portmidi.CountDevices()" always return 0?

This is my golang code:

package main

import fmt "fmt" // 本包实现了格式化输入输出
import portmidi "./portmidi"

func main() {
    fmt.Printf("Hello, world;\n")

    var errorid = portmidi.Initialize()
    fmt.Printf("Initialize:%d \n", errorid)

    var deviceIdnum = portmidi.CountDevices() // returns the number of MIDI devices
    fmt.Printf("CountDevices:%d \n", deviceIdnum)

    portmidi.Terminate()
}

"deviceIdnum" is always "0".

I have try c++ code:
#include "portmidi.h"

int _tmain(int argc, _TCHAR* argv[])
{
    PmError error = Pm_Initialize();
    if(error != pmNoError) {
        const char * errorstr = Pm_GetErrorText(error);
        return error;
    }

    int deviceCount = Pm_CountDevices();
    return Pm_Terminate();
}

"deviceCount" is 24.
Where am I wrong?

Thanks for your time.

go signal killed when running example

package main

import (
	"fmt"
	"log"

	"github.com/rakyll/portmidi"
)

func main() {

	in, err := portmidi.NewInputStream(portmidi.DefaultInputDeviceID(), 1024)
	if err != nil {
		log.Fatal(err)
	}

	msg, err := in.Read(1024)
	if err != nil {
		log.Fatal(err)
	}

	for i, b := range msg {
		fmt.Printf("SysEx message byte %d = %02x\n", i, b)
	}
}

ReadSysExBytes panics with array overflow if no event was read

func (s *Stream) ReadSysExBytes(max int) ([]byte, error) {

s.Read() can return success but zero messages (ie. nil, nil). If this happens, the line below causes an array overflow:

	return evt[0].SysEx, nil

Example backtrace:

panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/rakyll/portmidi.(*Stream).ReadSysExBytes(...)
	/home/fraggle/go/src/github.com/rakyll/portmidi/stream.go:238
main.(*getRegisterCommand).queryRegister(0x8205de8, 0x8ce8008, 0x8ce8488, 0x820e378)
	/home/fraggle/sc55ctl/sc55ctl.go:133 +0x2e5
main.(*getRegisterCommand).Execute(0x8205de8, {0x814cbb4, 0x8205c20}, 0x8c962c0, {0x0, 0x0, 0x0})
	/home/fraggle/sc55ctl/sc55ctl.go:182 +0x3e2
github.com/google/subcommands.(*Commander).Execute(0x8c96140, {0x814cbb4, 0x8205c20}, {0x0, 0x0, 0x0})
	/home/fraggle/go/src/github.com/google/subcommands/subcommands.go:209 +0x294
github.com/google/subcommands.Execute(...)
	/home/fraggle/go/src/github.com/google/subcommands/subcommands.go:492
main.main()
	/home/fraggle/sc55ctl/sc55ctl.go:310 +0x71b

How to install libportmidi on OSX?

Can you recommend a guide? I can't seem to figure out how to install it on OSX. I would really like to use this launchpad library to make instruments.

Using ch := in.Listen() seems to lose data

Hi

I seem to have an issue using in.Listen(). It loses key presses. Often I can press just one key, but only see the key down event, not the key up.

Have you seen this behavior?

Thanks
Dan

Duplicate symbol messages on Apple Mac

Golang 1.9
macOS 10.12.6 Sierra

Hello, I ran brew install portmidi and that seemed to go OK. I then ran go get github.com/rakyll/portmidi - again, no cause for alarm.

I then cd'd to the rakyll/portmidi folder and ran go test. I received the following messages:

 carlca  ~/code/go/src/github.com/rakyll/portmidi  master  go test                                   ✓  10:26:17 - 05.09.2017
# testmain
/usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Abort in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Close in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_CountDevices in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_GetDefaultInputDeviceID in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_GetDefaultOutputDeviceID in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_GetDeviceInfo in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_GetErrorText in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Initialize in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_OpenInput in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_OpenOutput in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Poll in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Read in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_SetChannelMask in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Terminate in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_Write in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pm_WriteSysEx in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pt_Start in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pt_Stop in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
duplicate symbol __cgo_d8e63e9abae4_Cfunc_Pt_Time in:
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000000.o
    /var/folders/1d/1rqcnlq51zd4j_vqhp1kv3540000gp/T/go-link-946891097/000002.o
ld: 19 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

FAIL	_/Users/carlca/code/go/src/github.com/rakyll/portmidi [build failed]

Any ideas what the problem could be? Cheers, Carl.

Crash on Pm_Write

i see this fairly regularly on linux (via the launchpad package) but haven't yet figured out how to reproduce

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x2 addr=0x7ff50c021000 pc=0x7ff51ce5ff46]

runtime stack:
runtime.throw(0x631c1f, 0x2a)
        /usr/lib/go/src/runtime/panic.go:566 +0x95
runtime.sigpanic()
        /usr/lib/go/src/runtime/sigpanic_unix.go:12 +0x2cc

goroutine 35 [syscall, locked to thread]:
runtime.cgocall(0x5bd000, 0xc420216c78, 0x0)
        /usr/lib/go/src/runtime/cgocall.go:131 +0x110 fp=0xc420216c30 sp=0xc420216bf0
github.com/scgolang/beats/vendor/github.com/rakyll/portmidi._Cfunc_Pm_Write(0x7ff50c000bf0, 0xc42016e4a0, 0x1, 0x0)
        ??:0 +0x4d fp=0xc420216c78 sp=0xc420216c30
github.com/scgolang/beats/vendor/github.com/rakyll/portmidi.(*Stream).Write(0xc4201fc4d0, 0xc420216cf8, 0x1, 0x1, 0x0, 0x0)
        /home/brian/go/src/github.com/scgolang/beats/vendor/github.com/rakyll/portmidi/stream.go:121 +0x11d fp=0xc420216cc8 sp=0xc420216c78
github.com/scgolang/beats/vendor/github.com/rakyll/portmidi.(*Stream).WriteShort(0xc4201fc4d0, 0x90, 0x54, 0xc, 0x0, 0x0)
        /home/brian/go/src/github.com/scgolang/beats/vendor/github.com/rakyll/portmidi/stream.go:132 +0x9b fp=0xc420216d28 sp=0xc420216cc8

Event struct doesn't expose entire Message slice

Hi, I hacked on a fork of this library to get Go talking to an older synth over Sysex. The changes I made are breaking, but I was interested in contributing if I can. Perhaps there is a non-breaking way of doing this, or a version of this can be included in a future release?

The diff is here: master...murdinc:master

As far as I can tell, only 3 bytes of the Message are available currently, but I needed the entire message.

Current struct:
// Event represents a MIDI event.
type Event struct {
    Timestamp Timestamp
    Status    int64
    Data1     int64
    Data2     int64
}
The changes I made are modeled after the PmEvent Struct in the portmidi docs:
// Event represents a MIDI event.
type Event struct {
    Timestamp Timestamp
    Message   Message
}

// Message represents a 4 byte message
type Message []byte


func (m Message) Status() byte {
    status := m[0]
    return status
}

func (m Message) Data1() byte {
    data1 := m[1]
    return data1
}

func (m Message) Data2() byte {
    data2 := m[2]
    return data2
}

Issue sending midi messages on Mac OS Montery

Running the following sample code:

`

package main

import(
"log"
"time"
"github.com/rakyll/portmidi"
)

func main() {
portmidi.Initialize()

out, err := portmidi.NewOutputStream(1, 1024, 0)
if err != nil {
log.Fatal(err)
}

// note on events to play C major chord
out.WriteShort(0x90, 60, 100)
out.WriteShort(0x90, 64, 100)
out.WriteShort(0x90, 67, 100)

// notes will be sustained for 2 seconds
time.Sleep(2 * time.Second)

// note off events
out.WriteShort(0x80, 60, 100)
out.WriteShort(0x80, 64, 100)
out.WriteShort(0x80, 67, 100)

    out.Close()

}

`

I see a flash on my USB midi when the device opens, and another when it closes, but no note events are sent when it writes them. Also not seeing any kind of error.

If I use the Mac OS midi tester, then I can see note events been sent to my usb midi fine so I don't think it's a device issue.

Is there any debugging I can turn on or way of investigating further?

Listen() has no stop mechanism.

I ran into a problem where calling Stream.Close() causes a crash in my app.
The call was fine when the app was closing down. i.e. when other go routines being killed.
The reason, Stream.Listen() spawns a go routine with no exit feature, so it will keep polling the Stream even if it has been Closed. This of course results in a memory access violation.
I assume the reason testing hasn't picked this up before is because Steam.Close() is usually only called on exit.

I am using the following in my project to allow a stream to stop listening.
It's a slight API change adding a stop signal to Stream.Listen().
Though it might be a good idea to use the context package...

func (s *portmidi.Stream) Listen(stop <-chan int) <-chan portmidi.Event {
	const pollingInterval = 10 * time.Millisecond
	timer := time.NewTimer(pollingInterval)
	ch := make(chan portmidi.Event)
	go func(s *portmidi.Stream, ch chan portmidi.Event) {
		for {
			select {
			case <-timer.C:
				events, err := s.Read(1024)
				if err != nil {
					timer.Reset(pollingInterval)
					continue
				}
				for i := range events {
					ch <- events[i]
				}
				timer.Reset(pollingInterval)
			case <-stop:
				timer.Stop()
				return
			}
		}
	}(s, ch)
	return ch
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.