Code Monkey home page Code Monkey logo

portmidi-haskell's Introduction

This is a Haskell module for PortMidi audio library, which supports
real-time MIDI input and output.

=========
ChangeLog
=========

Please see CHANGELOG.md.

============
Installation
============

The usual cabal installation steps apply, either:

       runhaskell Setup.hs configure
       runhaskell Setup.hs build
       runhaskell Setup.hs install

or simply:

       cabal install

This will install a PortMidi package that contains a Sound.PortMidi module.

==============================
Bug reports / Feature requests
==============================

Bug reports and feature requests can be created here:
https://github.com/PortMidi/PortMidi/issues.

portmidi-haskell's People

Contributors

ninegua avatar oliviersohn avatar mzero avatar onixie avatar austinvhuang avatar

Stargazers

smoge avatar  avatar  avatar STYLIANOS IORDANIS avatar Scott Olsen avatar  avatar Tristan de Cacqueray avatar Alexander Bondarenko avatar Adrian Sieber avatar Eben Till avatar Alvaro Fernando García avatar  avatar  avatar

Watchers

Alexander Bondarenko avatar  avatar James Cloos avatar  avatar  avatar

portmidi-haskell's Issues

Please add some example of use

There is not much documentation on hackage or in the code, it would be nice to have some example of usage like for this analogue in go.

The only example I found was this old thread in the mailing list, which I tweaked to get to type-check. However, I cannot get output on my midi keyboard. What am I missing?

`openInput` return value is unstable

In the first screenshot, we see that opening an device won't work unless the call to openInput is prefaced by a call to getDeviceInfo. Very strange indeed...

screen shot 2018-07-28 at 11 42 08 am

In this second one, we see that calling isLeft on a device will cause it to switch! (but only the first time. It settles into an equilibrium of error.)
screen shot 2018-07-28 at 11 41 17 am

Also, I'd like to politely point out that the Left value in an Either should be the erroneous value, and the Right should be the valid one. That is, if one hopes to use Either as a monad.

Thank you,
Ben

Timestamp precision

The Timestamp (type Timestamp = CULong) precision is currently milliseconds, which is enough to introduce midi-jitter of up-to one millisecond. I guess that in some applications, it could be audible, and some platforms (OSX for example) provide nanosecond precision for MIDI timestamps, so we could rewrite portmidi to take advantage of the full resolution, where it is available.

I'd like to propose a PR where the full precision is kept.
(After looking at it a bit more, it looks like it's a big task... and we would need some unit tests to make sure nothing is broken.)

Since it's a breaking change, to avoid undetected bugs when upgrading, I think the type should be changed, I propose newtype NanoTimestamp = CULLong.

What do you think?

Erroneous Incoming System Exclusives

Greetings. First of all, I'd really appreciate any help with this issue. I'm ready to do what I can to help.

I'm deserializing inbound sysex from a vintage Yamaha hardware synthesizer, and PortMidi is not giving me the correct stream of inbound bytes. I know what to expect, given the request I've made to the synth. I also have a utility program, PocketMidi (on Mac) that gives the correct bytes. I am 100% sure of a bug, 60% sure it's in the coremidi integration.

I repeatedly poll PMStream until I get a GotData.
I read the PMEvents.
From each PMEvent, I'm taking the message (::CLong), and extracting the first 4 bytes because I read that there are no more than 4 bytes of actual data in each message.

toBytes :: CLong -> [Word8]
toBytes bit64 = map (fromIntegral . f) [0,8..24] --PM:24 not 56; 4 bytes not 8
  where
    f = \position -> shiftR bit64 position .&. 0xFF

Very simple. BUT what I get back does not look as it should. I took a picture.

portmidierr

Profile gives me the reported bytes sent according to the synth, and the computed number of bytes gotten by taking the length of the packet.

The list within the Profile gives the me timestamped chunks of 4 bytes. Below that, on the command line, I typed what I was expecting.

The second chunk gives me two erroneous trailing zeros, among other issues.
Here's the whole thing typed without timestamps...

Given: F0 43 75 00 00 02 00 00 11 01 20 20 20 6D 6F 6E 6F 20 20 6D 20 38 01 20 64 00 32 02
Got : F0 43 75 00 00 02 11 01 20 20 20 6D 6F 6E 6F 20 38 01 64 00 32 02 00 00

Otherwise, I really like this library. It's fast, and the interface is simple and appropriate.

What do we need to do in order to fix this? It's unlikely that any of you have (or want) my synth, but this problem should be easy to reproduce with any syx-dumping machine.

Reading events (performance optimization)

Today, each call of readEvents dynamically allocates and deallocates a fixed-size pinned array using allocaArray, containing 256 PMEvents.

Considering that readEvents is the only exported function allowing to poll / read messages, if a user needs to receive messages at a low latency (say 1 millisecond) then, every millisecond, this function will be called, and even if there is nothing to read, every call will allocate / dallocate, thereby potentially increasing overall memory fragmentation, and maybe also block for some time.

I think we can improve this situation in 2 ways:

  • provide a binding to Pm_Poll so that we can first check if there is data before calling the readEvents call.
  • provide a readEventsToBuffer that takes an already allocated buffer + its size, and returns an Int saying how many messages were written to it.

What do you think?

Implementation suggestions are welcome, and since I need this in my application I'll probably take a shot at it.

Revisit error reporting

  • By convention, the Left constructor of Either should be used for errors : here, it is used the other way, it's very unsettling :)

  • We can remove the NoError (and GotData ?) constructors of PMError because these non-errors complicate the code at call site. For example, when readEvents succeeds but has read nothing, it should just return an empty list, and not return a non-error.

All these are breaking changes, but they are necessary to make the code at call site more standard / idiomatic. I think I'll propose a PR soon.

Current version?

The version of PortMidi on GitHub is currently 1.5.3, but on Hackage there's a more recent version (1.6.0) uploaded! Which is more up-to-date?

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.