PortMidi 0.1.6.1 → 0.2.0.0
raw patch · 12 files changed
+367/−297 lines, 12 filesdep ~basenew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
- Sound.PortMidi: NoError :: PMError
+ Sound.PortMidi: NoError'NoData :: PMSuccess
+ Sound.PortMidi: PMEventCount :: CInt -> PMEventCount
+ Sound.PortMidi: data PMSuccess
+ Sound.PortMidi: getSuccessText :: PMSuccess -> IO String
+ Sound.PortMidi: getText :: Either PMError PMSuccess -> IO String
+ Sound.PortMidi: instance GHC.Classes.Eq Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Classes.Eq Sound.PortMidi.PMSuccess
+ Sound.PortMidi: instance GHC.Classes.Ord Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Enum.Enum Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Enum.Enum Sound.PortMidi.PMSuccess
+ Sound.PortMidi: instance GHC.Num.Num Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Real.Integral Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Real.Real Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Show.Show Sound.PortMidi.PMEventCount
+ Sound.PortMidi: instance GHC.Show.Show Sound.PortMidi.PMSuccess
+ Sound.PortMidi: newtype PMEventCount
+ Sound.PortMidi: poll :: PMStream -> IO (Either PMError PMSuccess)
+ Sound.PortMidi: readEventsToBuffer :: PMStream -> Ptr PMEvent -> CLong -> IO (Either PMError PMEventCount)
- Sound.PortMidi: GotData :: PMError
+ Sound.PortMidi: GotData :: PMSuccess
- Sound.PortMidi: PMEvent :: !CLong -> !Timestamp -> PMEvent
+ Sound.PortMidi: PMEvent :: {-# UNPACK #-} !CLong -> {-# UNPACK #-} !Timestamp -> PMEvent
- Sound.PortMidi: PMMsg :: !CLong -> !CLong -> !CLong -> PMMsg
+ Sound.PortMidi: PMMsg :: {-# UNPACK #-} !CLong -> {-# UNPACK #-} !CLong -> {-# UNPACK #-} !CLong -> PMMsg
- Sound.PortMidi: [data1] :: PMMsg -> !CLong
+ Sound.PortMidi: [data1] :: PMMsg -> {-# UNPACK #-} !CLong
- Sound.PortMidi: [data2] :: PMMsg -> !CLong
+ Sound.PortMidi: [data2] :: PMMsg -> {-# UNPACK #-} !CLong
- Sound.PortMidi: [message] :: PMEvent -> !CLong
+ Sound.PortMidi: [message] :: PMEvent -> {-# UNPACK #-} !CLong
- Sound.PortMidi: [status] :: PMMsg -> !CLong
+ Sound.PortMidi: [status] :: PMMsg -> {-# UNPACK #-} !CLong
- Sound.PortMidi: [timestamp] :: PMEvent -> !Timestamp
+ Sound.PortMidi: [timestamp] :: PMEvent -> {-# UNPACK #-} !Timestamp
- Sound.PortMidi: abort :: PMStream -> IO PMError
+ Sound.PortMidi: abort :: PMStream -> IO (Either PMError PMSuccess)
- Sound.PortMidi: close :: PMStream -> IO PMError
+ Sound.PortMidi: close :: PMStream -> IO (Either PMError PMSuccess)
- Sound.PortMidi: initialize :: IO PMError
+ Sound.PortMidi: initialize :: IO (Either PMError PMSuccess)
- Sound.PortMidi: openInput :: DeviceID -> IO (Either PMStream PMError)
+ Sound.PortMidi: openInput :: DeviceID -> IO (Either PMError PMStream)
- Sound.PortMidi: openOutput :: DeviceID -> Int -> IO (Either PMStream PMError)
+ Sound.PortMidi: openOutput :: DeviceID -> Int -> IO (Either PMError PMStream)
- Sound.PortMidi: readEvents :: PMStream -> IO (Either [PMEvent] PMError)
+ Sound.PortMidi: readEvents :: PMStream -> IO (Either PMError [PMEvent])
- Sound.PortMidi: setChannelMask :: PMStream -> CLong -> IO PMError
+ Sound.PortMidi: setChannelMask :: PMStream -> CLong -> IO (Either PMError PMSuccess)
- Sound.PortMidi: setFilter :: PMStream -> CLong -> IO PMError
+ Sound.PortMidi: setFilter :: PMStream -> CLong -> IO (Either PMError PMSuccess)
- Sound.PortMidi: terminate :: IO PMError
+ Sound.PortMidi: terminate :: IO (Either PMError PMSuccess)
- Sound.PortMidi: writeEvents :: PMStream -> [PMEvent] -> IO PMError
+ Sound.PortMidi: writeEvents :: PMStream -> [PMEvent] -> IO (Either PMError PMSuccess)
- Sound.PortMidi: writeShort :: PMStream -> PMEvent -> IO PMError
+ Sound.PortMidi: writeShort :: PMStream -> PMEvent -> IO (Either PMError PMSuccess)
- Sound.PortMidi: writeSysEx :: PMStream -> Timestamp -> String -> IO PMError
+ Sound.PortMidi: writeSysEx :: PMStream -> Timestamp -> String -> IO (Either PMError PMSuccess)
Files
- CHANGELOG.md +184/−0
- CHANGELOG.txt +0/−156
- LICENSE +7/−16
- PortMidi.cabal +8/−8
- README.txt +9/−12
- Sound/PortMidi.hs +130/−77
- Sound/PortMidi/DeviceInfo.hsc +1/−0
- portmidi/pm_common/pminternal.h +1/−1
- portmidi/pm_common/portmidi.c +1/−1
- portmidi/pm_linux/pmlinuxalsa.c +5/−5
- portmidi/pm_win/pmwinmm.c +18/−18
- portmidi/porttime/ptwinmm.c +3/−3
+ CHANGELOG.md view
@@ -0,0 +1,184 @@+# Changelog++This project adheres to [Haskell PVP](https://pvp.haskell.org/).++The format of this changelog is based on+[Keep a Changelog](http://keepachangelog.com/en/1.0.0/)+++## 0.2.0.0+### Changed+- Error reporting (Breaking change).+ All functions now adhere to the `Either`+ [conventions](http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Either.html):+ real errors are returned in a `Left`,+ successes are returned in a `Right`.+ The non-errors constructors of `PMError`+ (`NoError` and `GotData`) were moved to a new type `PMSuccess`.++### Added+- The `poll` function which binds to+[`Pm_Poll`](http://portmedia.sourceforge.net/portmidi/doxygen/group__grp__io.html#g344e6ba3edb14d560ccb074d66b56590).+- The `readEventsToBuffer` function, to read events in a user-supplied buffer.+- The `PMSuccess` type representing non-errors, with its associated+ functions `getText` and `getSuccessText`.+++## 0.1.6.1++commit 3b92597d84113969371612fb5c590b9f8c77d53c+Author: Paul H. Liu <paul@thev.net>+Date: Wed Jul 6 09:34:40 2016 -0700++ Fix case sensitivity, and bump version to 0.1.6.1 to correct version number++commit 2d5266dd325f2c248a9022679abfcebe9b317a95+Author: Paul H. Liu <paul@thev.net>+Date: Tue Jul 5 21:37:24 2016 -0700++ Move to github, and bump version to 0.1.5.3++commit d7946afcfd7c3204c1ea999ed7fdb9c4e9ff20a7+Author: Paul Liu <paul@thev.net>+Date: Sun Apr 3 00:46:02 2016 -0700++ PMEvent uses CLong as message type to better handle SysEx.++ Ignore-this: 367f146403228813c914a23bfc2a1248+ - This is a breaking change. Use encodeMsg or decodeMsg to work with PMMsg.++ darcs-hash:20160403074602-da8e5-05c03013660b8fc91f843fa22143ec2b7ea5d7b5++commit d5217416a5477f10a36727254425a572d18b7e4a+Author: Paul Liu <paul@thev.net>+Date: Sun Apr 3 00:40:29 2016 -0700++ Use LANGUAGE pragma instead of OPTIONS_GHC++ Ignore-this: c65fb70875497b8e6c46f76ee9105dbe++ darcs-hash:20160403074029-da8e5-378ba491b94131265a94f115bf068971f869ea2b++commit 358452adfcf91c2436752f9b95ebcc5d5124db97+Author: Paul Liu <paul@thev.net>+Date: Sun Apr 3 00:40:09 2016 -0700++ Detect freebsd OS++ Ignore-this: 9f819a332d364679acc2e005488f9375++ darcs-hash:20160403074009-da8e5-16571867d53492c3fb7dc84df8fb8a500a71312a++commit c64496ded49633100864e8e0e192a9333ef8caa5+Author: Paul Liu <paul@thev.net>+Date: Mon Sep 21 22:17:09 2015 -0700++ Add CHANGELOG.txt to package, and bump version to 0.1.5.2++ Ignore-this: 465173236978f9557dbbc574b5d34a8f++ darcs-hash:20150922051709-da8e5-824c6e4c060e3c85ee3831cebde4a88fd3f8582b++commit fda70ecb49f85fd4dccc5daaecbdd9f96fe1651f+Author: Paul Liu <paul@thev.net>+Date: Mon Sep 21 11:29:09 2015 -0700++ Update README and bump version to 0.1.5.1++ Ignore-this: 98500cbf8d27a5068949cb458648500e++ darcs-hash:20150921182909-da8e5-fc100f8c68c20229a726f31ce8fd7051e8c13163++commit 044b0f47f3fc3bc6ade39c2972fb4b40c16c4e05+Author: Paul Liu <paul@thev.net>+Date: Mon Sep 21 11:17:37 2015 -0700++ Bump version to 0.1.5++ Ignore-this: 4fb2ae12ea9145bac0f0459ff3073169++ darcs-hash:20150921181737-da8e5-75d0be5001d877daf0c359687c66408afec0639b++commit a158c93a9d50c8bc56a3be908effd4020f9e7cc0+Author: Mark Lentczner <mark.lentczner@gmail.com>+Date: Mon Sep 21 11:16:04 2015 -0700++ On some systems, Int is not the same size as CInt.++ Ignore-this: 7bd6231264f14d66dd4c0156cc3266ba++ - Added hidden module Sound.PortMidi.DeviceInfo, moving DeviceInfo and peekDeviceInfo there+ - this allowed it to be a hsc2hs module, enabling peekDeviceInfo to use C generated structure offsets and sizes+ - FFI declarations for C calls that take and return PmError and PmDeviceID have been changed to take and return CInt rather than Int+ - Haskell functions interfacing with C calls have had fromIntegral calls added as needed+ - toPMError convenience function added, which replaced many calls to toEnum+ - FFI declaration for Pm_CountDevices added, countDevices became a Haskell function+ - PMError's toEnum function produces a more useful error message when the "impossible" happens++ darcs-hash:20150921181604-63162-de113c7c4da4f42d274b8b6c0641563c8670f606++commit cfae744f937cf4dfafd9e03bce9e0088a5b375f5+Author: Mark Lentczner <mark.lentczner@gmail.com>+Date: Mon Sep 21 11:15:00 2015 -0700++ Add strictness annotation when necessary++ Ignore-this: 9e5792f9ad04c797fcd51b244d7485fa++ darcs-hash:20150921181500-63162-dd522488d7f680cf536655d8cb1a878e489dcc98++commit 4fb6f505b2f495bad6ddd1072ff41b51001d9b44+Author: Paul Liu <paul@thev.net>+Date: Wed May 6 00:33:40 2015 -0700++ Update cabal file, and bump version to 0.1.4++ Ignore-this: 8b1d17f401ebd925a4bc6ff7778b453d++ darcs-hash:20150506073340-da8e5-0cf190250915842e35fc5f3177e576d84fb82026++commit a164e464065c84f3f4e958c53271f930c097f2d3+Author: Paul Liu <paul@thev.net>+Date: Wed May 6 00:33:10 2015 -0700++ Use withCAString for writeSysEx++ Ignore-this: 9499c201b5fb289cda27c090fdbf1541++ darcs-hash:20150506073310-da8e5-ecd2cf32c5f121cc95b97c1e9a495d189b0391cc++commit c3ad563bbce9fbc25c8470865ded7b070d0d030e+Author: Paul Liu <paul@thev.net>+Date: Wed Sep 16 11:06:11 2009 -0700++ remove conflicts in cabal file++ Ignore-this: 3ef1f4b655182e4cc5eb861e8f2427f1++ darcs-hash:20090916180611-da8e5-47cff7e32f38c7d54155784dbf2ddee6f1053faf++commit 6b0963d50576c0572155e421a4e6d02c8c649d8c+Author: Paul Liu <paul@thev.net>+Date: Wed Sep 16 11:01:59 2009 -0700++ fix compilation problem on OS X++ Ignore-this: a87d64d1c1a59bd161edecbde23932e3++ darcs-hash:20090916180159-da8e5-62407ea637a40e789f7e316a6fe181f56bc8fa1f++commit 13c1d569f8566968bd0a214903d11c08a1101a2a+Author: Paul Liu <paul@thev.net>+Date: Thu Jul 30 14:32:59 2009 -0700++ make cabal work for ghc 6.10.* on OS X++ darcs-hash:20090730213259-da8e5-f5a2558120fba824bb05440a8d7e3a2985fab2ed++commit 8b7e2ea3c5ef6cb2b436e136964c2ee5814ffc02+Author: Paul Liu <paul@thev.net>+Date: Thu Sep 4 18:59:02 2008 -0700++ PortMidi-0.1 initial release++ darcs-hash:20080905015902-da8e5-902a16abf5d28adda47ab45f6c0927a1042caf09
− CHANGELOG.txt
@@ -1,156 +0,0 @@-commit 3b92597d84113969371612fb5c590b9f8c77d53c-Author: Paul H. Liu <paul@thev.net>-Date: Wed Jul 6 09:34:40 2016 -0700-- Fix case sensitivity, and bump version to 0.1.6.1 to correct version number--commit 2d5266dd325f2c248a9022679abfcebe9b317a95-Author: Paul H. Liu <paul@thev.net>-Date: Tue Jul 5 21:37:24 2016 -0700-- Move to github, and bump version to 0.1.5.3--commit d7946afcfd7c3204c1ea999ed7fdb9c4e9ff20a7-Author: Paul Liu <paul@thev.net>-Date: Sun Apr 3 00:46:02 2016 -0700-- PMEvent uses CLong as message type to better handle SysEx.- - Ignore-this: 367f146403228813c914a23bfc2a1248- - This is a breaking change. Use encodeMsg or decodeMsg to work with PMMsg.- - darcs-hash:20160403074602-da8e5-05c03013660b8fc91f843fa22143ec2b7ea5d7b5--commit d5217416a5477f10a36727254425a572d18b7e4a-Author: Paul Liu <paul@thev.net>-Date: Sun Apr 3 00:40:29 2016 -0700-- Use LANGUAGE pragma instead of OPTIONS_GHC- - Ignore-this: c65fb70875497b8e6c46f76ee9105dbe- - darcs-hash:20160403074029-da8e5-378ba491b94131265a94f115bf068971f869ea2b--commit 358452adfcf91c2436752f9b95ebcc5d5124db97-Author: Paul Liu <paul@thev.net>-Date: Sun Apr 3 00:40:09 2016 -0700-- Detect freebsd OS- - Ignore-this: 9f819a332d364679acc2e005488f9375- - darcs-hash:20160403074009-da8e5-16571867d53492c3fb7dc84df8fb8a500a71312a--commit c64496ded49633100864e8e0e192a9333ef8caa5-Author: Paul Liu <paul@thev.net>-Date: Mon Sep 21 22:17:09 2015 -0700-- Add CHANGELOG.txt to package, and bump version to 0.1.5.2- - Ignore-this: 465173236978f9557dbbc574b5d34a8f- - darcs-hash:20150922051709-da8e5-824c6e4c060e3c85ee3831cebde4a88fd3f8582b--commit fda70ecb49f85fd4dccc5daaecbdd9f96fe1651f-Author: Paul Liu <paul@thev.net>-Date: Mon Sep 21 11:29:09 2015 -0700-- Update README and bump version to 0.1.5.1- - Ignore-this: 98500cbf8d27a5068949cb458648500e- - darcs-hash:20150921182909-da8e5-fc100f8c68c20229a726f31ce8fd7051e8c13163--commit 044b0f47f3fc3bc6ade39c2972fb4b40c16c4e05-Author: Paul Liu <paul@thev.net>-Date: Mon Sep 21 11:17:37 2015 -0700-- Bump version to 0.1.5- - Ignore-this: 4fb2ae12ea9145bac0f0459ff3073169- - darcs-hash:20150921181737-da8e5-75d0be5001d877daf0c359687c66408afec0639b--commit a158c93a9d50c8bc56a3be908effd4020f9e7cc0-Author: Mark Lentczner <mark.lentczner@gmail.com>-Date: Mon Sep 21 11:16:04 2015 -0700-- On some systems, Int is not the same size as CInt.- - Ignore-this: 7bd6231264f14d66dd4c0156cc3266ba- - - Added hidden module Sound.PortMidi.DeviceInfo, moving DeviceInfo and peekDeviceInfo there- - this allowed it to be a hsc2hs module, enabling peekDeviceInfo to use C generated structure offsets and sizes- - FFI declarations for C calls that take and return PmError and PmDeviceID have been changed to take and return CInt rather than Int- - Haskell functions interfacing with C calls have had fromIntegral calls added as needed- - toPMError convenience function added, which replaced many calls to toEnum- - FFI declaration for Pm_CountDevices added, countDevices became a Haskell function- - PMError's toEnum function produces a more useful error message when the "impossible" happens- - darcs-hash:20150921181604-63162-de113c7c4da4f42d274b8b6c0641563c8670f606--commit cfae744f937cf4dfafd9e03bce9e0088a5b375f5-Author: Mark Lentczner <mark.lentczner@gmail.com>-Date: Mon Sep 21 11:15:00 2015 -0700-- Add strictness annotation when necessary- - Ignore-this: 9e5792f9ad04c797fcd51b244d7485fa- - darcs-hash:20150921181500-63162-dd522488d7f680cf536655d8cb1a878e489dcc98--commit 4fb6f505b2f495bad6ddd1072ff41b51001d9b44-Author: Paul Liu <paul@thev.net>-Date: Wed May 6 00:33:40 2015 -0700-- Update cabal file, and bump version to 0.1.4- - Ignore-this: 8b1d17f401ebd925a4bc6ff7778b453d- - darcs-hash:20150506073340-da8e5-0cf190250915842e35fc5f3177e576d84fb82026--commit a164e464065c84f3f4e958c53271f930c097f2d3-Author: Paul Liu <paul@thev.net>-Date: Wed May 6 00:33:10 2015 -0700-- Use withCAString for writeSysEx- - Ignore-this: 9499c201b5fb289cda27c090fdbf1541- - darcs-hash:20150506073310-da8e5-ecd2cf32c5f121cc95b97c1e9a495d189b0391cc--commit c3ad563bbce9fbc25c8470865ded7b070d0d030e-Author: Paul Liu <paul@thev.net>-Date: Wed Sep 16 11:06:11 2009 -0700-- remove conflicts in cabal file- - Ignore-this: 3ef1f4b655182e4cc5eb861e8f2427f1- - darcs-hash:20090916180611-da8e5-47cff7e32f38c7d54155784dbf2ddee6f1053faf--commit 6b0963d50576c0572155e421a4e6d02c8c649d8c-Author: Paul Liu <paul@thev.net>-Date: Wed Sep 16 11:01:59 2009 -0700-- fix compilation problem on OS X- - Ignore-this: a87d64d1c1a59bd161edecbde23932e3- - darcs-hash:20090916180159-da8e5-62407ea637a40e789f7e316a6fe181f56bc8fa1f--commit 13c1d569f8566968bd0a214903d11c08a1101a2a-Author: Paul Liu <paul@thev.net>-Date: Thu Jul 30 14:32:59 2009 -0700-- make cabal work for ghc 6.10.* on OS X- - darcs-hash:20090730213259-da8e5-f5a2558120fba824bb05440a8d7e3a2985fab2ed--commit 8b7e2ea3c5ef6cb2b436e136964c2ee5814ffc02-Author: Paul Liu <paul@thev.net>-Date: Thu Sep 4 18:59:02 2008 -0700-- PortMidi-0.1 initial release- - darcs-hash:20080905015902-da8e5-902a16abf5d28adda47ab45f6c0927a1042caf09
LICENSE view
@@ -1,21 +1,12 @@-Copyright (c) 2008 Paul H. Liu <paul@thev.net>--This software is provided 'as-is', without any express or implied-warranty. In no event will the authors be held liable for any damages-arising from the use of this software.+Copyright (c) 2008, Paul H. Liu <paul@thev.net>+All rights reserved. -Permission is granted to anyone to use this software for any purpose,-including commercial applications, and to alter it and redistribute it-freely, subject to the following restrictions:+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. The origin of this software must not be misrepresented; you must not- claim that you wrote the original software. If you use this software- in a product, an acknowledgment in the product documentation would- be appreciated but is not required.+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Altered source versions must be plainly marked as such, and must not- be misrepresented as being the original software.+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. This notice may not be removed or altered from any source- distribution.+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PortMidi.cabal view
@@ -1,10 +1,11 @@ name: PortMidi-version: 0.1.6.1+version: 0.2.0.0 Cabal-Version: >= 1.6 build-type: Simple license: BSD3 license-file: LICENSE maintainer: Paul H. Liu <paul@thev.net>+ , Olivier Sohn <olivier.sohn@gmail.com> homepage: http://github.com/ninegua/PortMidi category: Sound stability: experimental@@ -12,7 +13,7 @@ description: A Haskell binding for PortMedia/PortMidi extra-source-files: README.txt- CHANGELOG.txt+ CHANGELOG.md portmidi/pm_common/portmidi.h portmidi/pm_common/pmutil.h portmidi/pm_common/pminternal.h@@ -29,8 +30,8 @@ extensions: CPP, ForeignFunctionInterface if os(linux) || os(freebsd) include-dirs: portmidi/pm_common portmidi/pm_linux portmidi/porttime- cc-options: -DPMALSA - c-sources: + cc-options: -DPMALSA+ c-sources: portmidi/pm_common/pmutil.c portmidi/pm_common/portmidi.c portmidi/pm_linux/pmlinux.c@@ -42,7 +43,7 @@ if os(darwin) include-dirs: portmidi/pm_common portmidi/pm_mac portmidi/porttime cc-options: -msse2- c-sources: + c-sources: portmidi/pm_common/pmutil.c portmidi/pm_common/portmidi.c portmidi/pm_mac/pmmac.c@@ -53,15 +54,14 @@ else if os(mingw32) include-dirs: portmidi/pm_common portmidi/pm_win portmidi/porttime- c-sources: + c-sources: portmidi/pm_common/pmutil.c portmidi/pm_common/portmidi.c portmidi/pm_win/pmwin.c portmidi/pm_win/pmwinmm.c portmidi/porttime/porttime.c portmidi/porttime/ptwinmm.c- extra-libraries: winmm + extra-libraries: winmm source-repository head type: git location: https://github.com/ninegua/PortMidi-
README.txt view
@@ -1,17 +1,17 @@ This is a Haskell module for PortMidi audio library, which supports-real-time MIDI input and output. +real-time MIDI input and output. ========= ChangeLog ========= -Please see CHANGELOG.txt.+Please see CHANGELOG.md. ============ Installation ============ -The usual cabal installation steps apply, either: +The usual cabal installation steps apply, either: runhaskell Setup.hs configure runhaskell Setup.hs build@@ -21,14 +21,11 @@ cabal install -This will install a PortMidi package that contains a Sound.PortMidi module. --===================-Contact Information-===================+This will install a PortMidi package that contains a Sound.PortMidi module. -You may send your bug report and feature request to the package -maintainer: Paul H. Liu <paul@thev.net>.+==============================+Bug reports / Feature requests+============================== ----Last Update: Tue Jul 5 PDT 2016+Bug reports and feature requests can be created here:+https://github.com/ninegua/PortMidi/issues.
Sound/PortMidi.hs view
@@ -2,15 +2,18 @@ Interface to PortMidi -} {-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} -module Sound.PortMidi ( +module Sound.PortMidi ( -- * Data Types PMError(..)+ , PMSuccess(..)+ , PMEventCount(..) , PMStream , DeviceInfo(..) , DeviceID , PMMsg(..)- , PMEvent(..) + , PMEvent(..) -- * Constants , filterActive , filterSysex@@ -33,11 +36,13 @@ , filterSongSelect , filterTune , filterSystemCommon- -- * PortMid functions+ -- * PortMidi functions , initialize , terminate , hasHostError , getErrorText+ , getSuccessText+ , getText , countDevices , getDefaultInputDeviceID , getDefaultOutputDeviceID@@ -49,10 +54,12 @@ , setChannelMask , abort , close+ , poll , readEvents+ , readEventsToBuffer , writeEvents , writeShort- , writeSysEx + , writeSysEx -- * Time function , time --@@ -63,18 +70,28 @@ import Foreign import Foreign.C-import Foreign.Marshal-import Foreign.Storable-import Data.IORef-import Data.Bits-import System.IO.Unsafe import Sound.PortMidi.DeviceInfo -data PMError- = NoError+-- | Represents non-errors of the C enum `PmError`+data PMSuccess+ = NoError'NoData+ -- ^ Returned by 'poll' when there is no data, and returned by other functions+ -- when there is no error. | GotData- | HostError+ -- ^ Only returned by 'poll' when data is available.+ deriving (Eq, Show)++instance Enum PMSuccess where+ fromEnum NoError'NoData = 0+ fromEnum GotData = 1+ toEnum 0 = NoError'NoData+ toEnum 1 = GotData+ toEnum x = error $ "PortMidi: PMSuccess toEnum out of bound " ++ show x++-- | Represents real errors of the C enum `PmError`+data PMError+ = HostError | InvalidDeviceId | InsufficientMemory | BufferTooSmall@@ -86,8 +103,6 @@ deriving (Eq, Show) instance Enum PMError where- fromEnum NoError = 0- fromEnum GotData = 1 fromEnum HostError = -10000 fromEnum InvalidDeviceId = -9999 fromEnum InsufficientMemory = -9998@@ -97,8 +112,6 @@ fromEnum BadData = -9994 fromEnum InternalError = -9993 fromEnum BufferMaxSize = -9992- toEnum 0 = NoError- toEnum 1 = GotData toEnum (-10000) = HostError toEnum (-9999) = InvalidDeviceId toEnum (-9998) = InsufficientMemory@@ -108,22 +121,39 @@ toEnum (-9994) = BadData toEnum (-9993) = InternalError toEnum (-9992) = BufferMaxSize- toEnum x = error $ "PortMidi: toEnum out of bound " ++ show x+ toEnum x = error $ "PortMidi: PMError toEnum out of bound " ++ show x -toPMError :: CInt -> PMError-toPMError = toEnum . fromIntegral+eitherErrorOrSuccess :: CInt -> Either PMError PMSuccess+eitherErrorOrSuccess n+ | isSuccess = Right $ toEnum $ fromIntegral n+ | otherwise = Left $ toEnum $ fromIntegral n+ where+ isSuccess = n == 0 || n == 1 +-- | Represents a count of 'PMEvent's+newtype PMEventCount = PMEventCount CInt+ deriving(Num, Integral, Real, Enum, Show, Eq, Ord)++-- | Interprets a 'CInt', as returned by 'pm_Read'.+eitherErrorOrCount :: CInt -> Either PMError PMEventCount+eitherErrorOrCount n+ | n >= 0 = Right $ fromIntegral n+ | otherwise = Left $ toEnum $ fromIntegral n+ data PortMidiStream type PMStreamPtr = Ptr PortMidiStream type PMStream = ForeignPtr PortMidiStream type DeviceID = Int +(.<.) :: CLong -> Int -> CLong (.<.) = shiftL++(.>.) :: CLong -> Int -> CLong (.>.) = shiftR filterActive, filterSysex, filterClock, filterPlay, filterTick, filterFD, filterUndefined, filterReset, filterRealtime, filterNote, filterChannelAftertouch, filterPolyAftertouch, filterAftertouch, filterProgram, filterControl, filterPitchBend, filterMTC, filterSongPosition, filterSongSelect, filterTune, filterSystemCommon :: CLong -filterActive = 1 .<. 0x0e +filterActive = 1 .<. 0x0e filterSysex = 1 .<. 0x00 filterClock = 1 .<. 0x08 filterPlay = (1 .<. 0x0A) .|. (1 .<. 0x0C) .|. (1 .<. 0x0B)@@ -131,7 +161,7 @@ filterFD = 1 .<. 0x0D filterUndefined = filterFD filterReset = 1 .<. 0x0F-filterRealtime = filterActive .|. filterSysex .|. filterClock .|. filterPlay .|. filterUndefined .|. filterReset .|. filterTick +filterRealtime = filterActive .|. filterSysex .|. filterClock .|. filterPlay .|. filterUndefined .|. filterReset .|. filterTick filterNote = (1 .<. 0x19) .|. (1 .<. 0x18) filterChannelAftertouch = 1 .<. 0x1D filterPolyAftertouch = 1 .<. 0x1A@@ -145,11 +175,11 @@ filterTune = 1 .<. 0x06 filterSystemCommon = filterMTC .|. filterSongPosition .|. filterSongSelect .|. filterTune -data PMMsg +data PMMsg = PMMsg- { status :: !CLong- , data1 :: !CLong- , data2 :: !CLong+ { status :: {-# UNPACK #-} !CLong+ , data1 :: {-# UNPACK #-} !CLong+ , data2 :: {-# UNPACK #-} !CLong } deriving (Eq, Show) encodeMsg :: PMMsg -> CLong@@ -157,12 +187,13 @@ decodeMsg :: CLong -> PMMsg decodeMsg i = PMMsg (i .&. 0xFF) ((i .>. 8) .&. 0xFF) ((i .>. 16) .&. 0xFF) +-- | Time with millisecond precision. type Timestamp = CULong -data PMEvent - = PMEvent - { message :: !CLong- , timestamp :: !Timestamp+data PMEvent+ = PMEvent+ { message :: {-# UNPACK #-} !CLong+ , timestamp :: {-# UNPACK #-} !Timestamp } deriving (Eq, Show) instance Storable PMEvent where@@ -178,12 +209,12 @@ foreign import ccall "portmidi.h Pm_Initialize" pm_Initialize :: IO CInt-initialize :: IO PMError-initialize = pm_Initialize >>= return . toPMError+initialize :: IO (Either PMError PMSuccess)+initialize = pm_Initialize >>= return . eitherErrorOrSuccess foreign import ccall "portmidi.h Pm_Terminate" pm_Terminate :: IO CInt-terminate :: IO PMError-terminate = pm_Terminate >>= return . toPMError+terminate :: IO (Either PMError PMSuccess)+terminate = pm_Terminate >>= return . eitherErrorOrSuccess foreign import ccall "portmidi.h Pm_HasHostError" pm_HasHostError :: PMStreamPtr -> IO CInt hasHostError :: PMStream -> IO Bool@@ -193,6 +224,12 @@ getErrorText :: PMError -> IO String getErrorText err = pm_GetErrorText (fromIntegral $ fromEnum err) >>= peekCString +getSuccessText :: PMSuccess -> IO String+getSuccessText success = pm_GetErrorText (fromIntegral $ fromEnum success) >>= peekCString++getText :: Either PMError PMSuccess -> IO String+getText = either getErrorText getSuccessText+ foreign import ccall "portmidi.h Pm_CountDevices" pm_countDevices :: IO CInt countDevices :: IO DeviceID countDevices = pm_countDevices >>= return . fromIntegral@@ -213,72 +250,88 @@ getDeviceInfo deviceID = pm_GetDeviceInfo (fromIntegral deviceID) >>= peekDeviceInfo foreign import ccall "portmidi.h Pm_OpenInput" pm_OpenInput :: Ptr PMStreamPtr -> CInt -> Ptr () -> CLong -> Ptr () -> Ptr () -> IO CInt-openInput :: DeviceID -> IO (Either PMStream PMError)-openInput inputDevice = - with nullPtr (\ptr -> do- e <- pm_OpenInput ptr (fromIntegral inputDevice) nullPtr 0 nullPtr nullPtr- if e == 0 - then do+openInput :: DeviceID -> IO (Either PMError PMStream)+openInput inputDevice =+ with nullPtr (\ptr ->+ eitherErrorOrSuccess <$> pm_OpenInput ptr (fromIntegral inputDevice) nullPtr 0 nullPtr nullPtr >>= either+ (return . Left)+ (\_ -> do stream <- peek ptr- ptr' <- newForeignPtr_ stream- return $ Left ptr'- else return (Right (toPMError e)))- + Right <$> newForeignPtr_ stream))+ foreign import ccall "portmidi.h Pm_OpenOutput" pm_OpenOutput :: Ptr PMStreamPtr -> CInt -> Ptr () -> CLong -> Ptr () -> Ptr () -> CLong -> IO CInt-openOutput :: DeviceID -> Int -> IO (Either PMStream PMError)+openOutput :: DeviceID -> Int -> IO (Either PMError PMStream) openOutput outputDevice latency = with nullPtr (\ptr -> do- e <- pm_OpenOutput ptr (fromIntegral outputDevice) nullPtr 0 nullPtr nullPtr (fromIntegral latency)- if e == 0 - then do+ eitherErrorOrSuccess <$> pm_OpenOutput ptr (fromIntegral outputDevice) nullPtr 0 nullPtr nullPtr (fromIntegral latency) >>= either+ (return . Left)+ (\_ -> do stream <- peek ptr- ptr' <- newForeignPtr_ stream- return $ Left ptr'- else return (Right (toPMError e)))+ Right <$> newForeignPtr_ stream)) foreign import ccall "portmidi.h Pm_SetFilter" pm_SetFilter :: PMStreamPtr -> CLong -> IO CInt-setFilter :: PMStream -> CLong -> IO PMError-setFilter stream filter = withForeignPtr stream (\s -> pm_SetFilter s filter >>= return . toPMError)+setFilter :: PMStream -> CLong -> IO (Either PMError PMSuccess)+setFilter stream theFilter = withForeignPtr stream (fmap eitherErrorOrSuccess . flip pm_SetFilter theFilter) channel :: Int -> CLong channel i = 1 .<. i foreign import ccall "portmidi.h Pm_SetChannelMask" pm_SetChannelMask :: PMStreamPtr -> CLong -> IO CInt-setChannelMask :: PMStream -> CLong -> IO PMError-setChannelMask stream mask = withForeignPtr stream (\s -> pm_SetChannelMask s mask >>= return . toPMError)+setChannelMask :: PMStream -> CLong -> IO (Either PMError PMSuccess)+setChannelMask stream mask = withForeignPtr stream (fmap eitherErrorOrSuccess . flip pm_SetChannelMask mask) foreign import ccall "portmidi.h Pm_Abort" pm_Abort :: PMStreamPtr -> IO CInt-abort :: PMStream -> IO PMError-abort = flip withForeignPtr (\s -> pm_Abort s >>= return . toPMError)+abort :: PMStream -> IO (Either PMError PMSuccess)+abort = flip withForeignPtr (fmap eitherErrorOrSuccess . pm_Abort) foreign import ccall "portmidi.h Pm_Close" pm_Close :: PMStreamPtr -> IO CInt-close :: PMStream -> IO PMError-close = flip withForeignPtr (\s -> pm_Close s >>= return . toPMError)+close :: PMStream -> IO (Either PMError PMSuccess)+close = flip withForeignPtr (fmap eitherErrorOrSuccess . pm_Close) +foreign import ccall "portmidi.h Pm_Poll" pm_Poll :: PMStreamPtr -> IO CInt+-- | Returns wether or not a subsequent call to 'readEvents' would return+-- some 'PMEvent's or not.+poll :: PMStream -> IO (Either PMError PMSuccess)+poll = flip withForeignPtr (fmap eitherErrorOrSuccess . pm_Poll)+ foreign import ccall "portmidi.h Pm_Read" pm_Read :: PMStreamPtr -> Ptr PMEvent -> CLong -> IO CInt-readEvents :: PMStream -> IO (Either [PMEvent] PMError)-readEvents = flip withForeignPtr (\s -> allocaArray (fromIntegral defaultBufferSize) (\arr -> do- r <- pm_Read s arr defaultBufferSize- if r > 0- then peekArray (fromIntegral r) arr >>= return . Left- else return $ Right (toPMError r)))- where- defaultBufferSize = 256+-- | Reads at most 256 'PMEvent's, using a dynamically allocated buffer.+readEvents :: PMStream -> IO (Either PMError [PMEvent])+readEvents stream =+ allocaArray (fromIntegral defaultBufferSize) $ \arr ->+ readEventsToBuffer stream arr defaultBufferSize >>= either+ (return . Left)+ (fmap Right . flip peekArray arr . fromIntegral)+ where+ defaultBufferSize = 256 +-- | Reads 'PMEvent's and writes them to the buffer passed as argument.+readEventsToBuffer :: PMStream+ -> Ptr PMEvent+ -- ^ The 'PMEvent's buffer which will contain the results.+ -> CLong+ -- ^ The size of the 'PMEvent' buffer, in number of elements.+ -- No more that this number of 'PMEvent's can be read at once.+ -> IO (Either PMError PMEventCount)+ -- ^ When 'Right', returns the number of elements written+ -- to the 'PMEvent' buffer.+readEventsToBuffer stream ptr sz =+ withForeignPtr stream $ \s ->+ eitherErrorOrCount <$> pm_Read s ptr sz+ foreign import ccall "portmidi.h Pm_Write" pm_Write :: PMStreamPtr -> Ptr PMEvent -> CLong -> IO CInt-writeEvents :: PMStream -> [PMEvent] -> IO PMError-writeEvents stream events = withForeignPtr stream (\s -> - withArrayLen events (\len arr -> pm_Write s arr (fromIntegral len) >>= return . toPMError))+writeEvents :: PMStream -> [PMEvent] -> IO (Either PMError PMSuccess)+writeEvents stream events = withForeignPtr stream (\s ->+ withArrayLen events (\len arr -> eitherErrorOrSuccess <$> pm_Write s arr (fromIntegral len))) foreign import ccall "portmidi.h Pm_WriteShort" pm_WriteShort :: PMStreamPtr -> CULong -> CLong -> IO CInt-writeShort :: PMStream -> PMEvent -> IO PMError-writeShort stream (PMEvent msg time) = withForeignPtr stream (\s ->- pm_WriteShort s time msg >>= return . toPMError)+writeShort :: PMStream -> PMEvent -> IO (Either PMError PMSuccess)+writeShort stream (PMEvent msg t) = withForeignPtr stream (\s ->+ eitherErrorOrSuccess <$> pm_WriteShort s t msg) foreign import ccall "portmidi.h Pm_WriteSysEx" pm_WriteSysEx :: PMStreamPtr -> CULong -> CString -> IO CInt-writeSysEx :: PMStream -> Timestamp -> String -> IO PMError-writeSysEx stream time str = withForeignPtr stream (\st ->- withCAString str (\s -> pm_WriteSysEx st time s >>= return . toPMError))--foreign import ccall "porttime.h Pt_Time" time :: IO Timestamp +writeSysEx :: PMStream -> Timestamp -> String -> IO (Either PMError PMSuccess)+writeSysEx stream t str = withForeignPtr stream (\st ->+ withCAString str (\s -> eitherErrorOrSuccess <$> pm_WriteSysEx st t s)) +foreign import ccall "porttime.h Pt_Time" time :: IO Timestamp
Sound/PortMidi/DeviceInfo.hsc view
@@ -19,6 +19,7 @@ , opened :: Bool } deriving (Eq, Show) +peekDeviceInfo :: Ptr a -> IO DeviceInfo peekDeviceInfo ptr = do s <- #{peek PmDeviceInfo, interf} ptr >>= peekCString u <- #{peek PmDeviceInfo, name} ptr >>= peekCString
portmidi/pm_common/pminternal.h view
@@ -155,7 +155,7 @@ PmError pm_success_fn(PmInternal *midi); PmError pm_add_device(char *interf, char *name, int input, void *descriptor, pm_fns_type dictionary); -unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data, int len, +unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data, int len, PmTimestamp timestamp); void pm_read_short(PmInternal *midi, PmEvent *event);
portmidi/pm_common/portmidi.c view
@@ -999,7 +999,7 @@ /* * returns how many bytes processed */ -unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data, +unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data, int len, PmTimestamp timestamp) { unsigned int i = 0; /* index into data */
portmidi/pm_linux/pmlinuxalsa.c view
@@ -32,9 +32,9 @@ #endif /* to store client/port in the device descriptor */ -#define MAKE_DESCRIPTOR(client, port) ((void*)(((client) << 8) | (port))) -#define GET_DESCRIPTOR_CLIENT(info) ((((int)(info)) >> 8) & 0xff) -#define GET_DESCRIPTOR_PORT(info) (((int)(info)) & 0xff) +#define MAKE_DESCRIPTOR(client, port) ((void*)(size_t)(((client) << 8) | (port))) +#define GET_DESCRIPTOR_CLIENT(info) ((((size_t)(info)) >> 8) & 0xff) +#define GET_DESCRIPTOR_PORT(info) (((size_t)(info)) & 0xff) #define BYTE unsigned char #define UINT unsigned long @@ -209,7 +209,7 @@ if (when == 0) when = now; when = (when - now) + midi->latency; if (when < 0) when = 0; - VERBOSE printf("timestamp %d now %d latency %d, ", + VERBOSE printf("timestamp %d now %d latency %ld, ", (int) timestamp, (int) now, midi->latency); VERBOSE printf("scheduling event after %d\n", when); /* message is sent in relative ticks, where 1 tick = 1 ms */ @@ -438,7 +438,7 @@ static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); + VERBOSE printf("snd_seq_drain_output: 0x%p\n", seq); desc->error = snd_seq_drain_output(seq); if (desc->error < 0) return pmHostError;
portmidi/pm_win/pmwinmm.c view
@@ -35,14 +35,14 @@ /* callback routines */ static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn, - WORD wMsg, DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2); + WORD wMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2); static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg, - DWORD dwInstance, DWORD dwParam1, - DWORD dwParam2); + DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2); static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg, - DWORD dwInstance, DWORD dwParam1, - DWORD dwParam2); + DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2); extern pm_fns_node pm_winmm_in_dictionary; extern pm_fns_node pm_winmm_out_dictionary; @@ -578,8 +578,8 @@ /* open device */ pm_hosterror = midiInOpen(&(m->handle.in), /* input device handle */ dwDevice, /* device ID */ - (DWORD) winmm_in_callback, /* callback address */ - (DWORD) midi, /* callback instance data */ + (DWORD_PTR) winmm_in_callback, /* callback address */ + (DWORD_PTR) midi, /* callback instance data */ CALLBACK_FUNCTION); /* callback is a procedure */ if (pm_hosterror) goto free_descriptor; @@ -661,9 +661,9 @@ static void FAR PASCAL winmm_in_callback( HMIDIIN hMidiIn, /* midiInput device Handle */ WORD wMsg, /* midi msg */ - DWORD dwInstance, /* application data */ - DWORD dwParam1, /* MIDI data */ - DWORD dwParam2) /* device timestamp (wrt most recent midiInStart) */ + DWORD_PTR dwInstance, /* application data */ + DWORD_PTR dwParam1, /* MIDI data */ + DWORD_PTR dwParam2) /* device timestamp (wrt most recent midiInStart) */ { static int entry = 0; PmInternal *midi = (PmInternal *) dwInstance; @@ -859,16 +859,16 @@ pm_hosterror = midiOutOpen((LPHMIDIOUT) & m->handle.out, /* device Handle */ dwDevice, /* device ID */ /* note: same callback fn as for StreamOpen: */ - (DWORD) winmm_streamout_callback, /* callback fn */ - (DWORD) midi, /* callback instance data */ + (DWORD_PTR) winmm_streamout_callback, /* callback fn */ + (DWORD_PTR) midi, /* callback instance data */ CALLBACK_FUNCTION); /* callback type */ } else { /* use stream-based midi output (schedulable in future) */ pm_hosterror = midiStreamOpen(&m->handle.stream, /* device Handle */ (LPUINT) & dwDevice, /* device ID pointer */ 1, /* reserved, must be 1 */ - (DWORD) winmm_streamout_callback, - (DWORD) midi, /* callback instance data */ + (DWORD_PTR) winmm_streamout_callback, + (DWORD_PTR) midi, /* callback instance data */ CALLBACK_FUNCTION); } if (pm_hosterror != MMSYSERR_NOERROR) { @@ -1288,8 +1288,8 @@ #ifdef USE_SYSEX_BUFFERS /* winmm_out_callback -- recycle sysex buffers */ static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg, - DWORD dwInstance, DWORD dwParam1, - DWORD dwParam2) + DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2) { PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; @@ -1314,7 +1314,7 @@ /* winmm_streamout_callback -- unprepare (free) buffer header */ static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg, - DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) + DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor;
portmidi/porttime/ptwinmm.c view
@@ -14,8 +14,8 @@ static MMRESULT timer_id; static PtCallback *time_callback; -void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD dwUser, - DWORD dw1, DWORD dw2) +void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser, + DWORD_PTR dw1, DWORD_PTR dw2) { (*time_callback)(Pt_Time(), (void *) dwUser); } @@ -31,7 +31,7 @@ time_callback = callback; if (callback) { timer_id = timeSetEvent(resolution, 1, winmm_time_callback, - (DWORD) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + (DWORD_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if (!timer_id) return ptHostError; } return ptNoError;