func (s *Stream) Read(max int) (events []Event, err error) {
	if max > maxEventBufferSize {
		return nil, ErrMaxBuffer
	}
	if max < minEventBufferSize {
		return nil, ErrMinBuffer
	}
	buffer := make([]C.PmEvent, max)
	numEvents := C.Pm_Read(unsafe.Pointer(s.pmStream), &buffer[0], C.int32_t(max))
	if numEvents < 0 {
		return nil, convertToError(C.PmError(numEvents))
	}
	events = make([]Event, numEvents)
	for i := 0; i < int(numEvents); i++ {
		events[i] = Event{
			Timestamp: Timestamp(buffer[i].timestamp),
			Status:    int64(buffer[i].message) & 0xFF,
			Data1:     (int64(buffer[i].message) >> 8) & 0xFF,
			Data2:     (int64(buffer[i].message) >> 16) & 0xFF,
		}
	}
	return
}
Reads from the input stream, the max number events to be read are
determined by max.
package portmidi
import "C"
import (
	"encoding/hex"
	"errors"
	"strings"
	"time"
	"unsafe"
)
const (
	minEventBufferSize = 1
	maxEventBufferSize = 1024
)
var (
	ErrMaxBuffer         = errors.New("portmidi: max event buffer size is 1024")
	ErrMinBuffer         = errors.New("portmidi: min event buffer size is 1")
	ErrInputUnavailable  = errors.New("portmidi: input is unavailable")
	ErrOutputUnavailable = errors.New("portmidi: output is unavailable")
)
type Channel int
type Event struct {
	Timestamp Timestamp
	Status    int64
	Data1     int64
	Data2     int64
}
type Stream struct {
	deviceID DeviceID
	pmStream *C.PmStream
}
func NewInputStream(id DeviceID, bufferSize int64) (stream *Stream, err error) {
	var str *C.PmStream
	errCode := C.Pm_OpenInput(
		(*unsafe.Pointer)(unsafe.Pointer(&str)),
		C.PmDeviceID(id), nil, C.int32_t(bufferSize), nil, nil)
	if errCode != 0 {
		return nil, convertToError(errCode)
	}
	if info := Info(id); !info.IsInputAvailable {
		return nil, ErrInputUnavailable
	}
	return &Stream{deviceID: id, pmStream: str}, nil
}
func NewOutputStream(id DeviceID, bufferSize int64, latency int64) (stream *Stream, err error) {
	var str *C.PmStream
	errCode := C.Pm_OpenOutput(
		(*unsafe.Pointer)(unsafe.Pointer(&str)),
		C.PmDeviceID(id), nil, C.int32_t(bufferSize), nil, nil, C.int32_t(latency))
	if errCode != 0 {
		return nil, convertToError(errCode)
	}
	if info := Info(id); !info.IsOutputAvailable {
		return nil, ErrOutputUnavailable
	}
	return &Stream{deviceID: id, pmStream: str}, nil
}
func (s *Stream) Close() error {
	if s.pmStream == nil {
		return nil
	}
	return convertToError(C.Pm_Close(unsafe.Pointer(s.pmStream)))
}
func (s *Stream) Abort() error {
	if s.pmStream == nil {
		return nil
	}
	return convertToError(C.Pm_Abort(unsafe.Pointer(s.pmStream)))
}
func (s *Stream) Write(events []Event) error {
	size := len(events)
	if size > maxEventBufferSize {
		return ErrMaxBuffer
	}
	buffer := make([]C.PmEvent, size)
	for i, evt := range events {
		var event C.PmEvent
		event.timestamp = C.PmTimestamp(evt.Timestamp)
		event.message = C.PmMessage((((evt.Data2 << 16) & 0xFF0000) | ((evt.Data1 << 8) & 0xFF00) | (evt.Status & 0xFF)))
		buffer[i] = event
	}
	return convertToError(C.Pm_Write(unsafe.Pointer(s.pmStream), &buffer[0], C.int32_t(size)))
}
func (s *Stream) WriteShort(status int64, data1 int64, data2 int64) error {
	evt := Event{
		Timestamp: Timestamp(C.Pt_Time()),
		Status:    status,
		Data1:     data1,
		Data2:     data2,
	}
	return s.Write([]Event{evt})
}
func (s *Stream) WriteShorts(status int64, data1s []int64, data2s []int64) error {
	evts := make([]Event, len(data1s))
	timestamp := Timestamp(C.Pt_Time() + 1000)
	for i := range data1s {
		evts[i] = Event{
			Timestamp: timestamp,
			Status:    status,
			Data1:     data1s[i],
			Data2:     data2s[i],
		}
	}
	return s.Write(evts)
}
func (s *Stream) WriteSysExBytes(when Timestamp, msg []byte) error {
	return convertToError(C.Pm_WriteSysEx(unsafe.Pointer(s.pmStream), C.PmTimestamp(when), (*C.uchar)(unsafe.Pointer(&msg[0]))))
}
func (s *Stream) WriteSysEx(when Timestamp, msg string) error {
	buf, err := hex.DecodeString(strings.Replace(msg, " ", "", -1))
	if err != nil {
		return err
	}
	return s.WriteSysExBytes(when, buf)
}
func (s *Stream) SetChannelMask(mask int) error {
	return convertToError(C.Pm_SetChannelMask(unsafe.Pointer(s.pmStream), C.int(mask)))
}