LeapMotionをHaskellで動かすための準備 その2
前回の続き。
今回はHaskellでLeapMotionを動かすところまでやる。
具体的には、HaskellでFFIを通してc++用のLeapMotoinSDKを使う。
まずは普通にc++でLeapMotionSDKを使ってみる。
step4.cc
#include <iostream> #include "Leap.h" using namespace Leap; Controller *new_controller(void){ return new Controller(); } void delete_controller(Controller *controller){ delete controller; } int num_hands(const Controller *controller){ return controller->frame().hands().count(); } int main() { Controller *controller = new_controller(); while(true){ std::cout << "num hands: " << num_hands(controller) << std::endl; sleep(1); } delete_controller(controller); return 0; }
Haskellから呼べるように、手の数を得るための関数を書いている。
LeapMotionのヘッダファイルを"include/Leap.h"に用意し、コンパイルする。
g++ step4.cc -I./include -o step4 libLeap.dylib
実行してみる。
num hands: 0 num hands: 0 num hands: 1 num hands: 1 num hands: 2 num hands: 0
手を検出して手の数が表示された。
では、これをHaskellで実行するように改造する。
先ほどのstep4.ccのメイン関数以外を抜き出して、extern "C"で囲って、wrapper.ccとして保存する。
wrapper.cc
#include "Leap.h" using namespace Leap; extern "C" { Controller *new_controller(void){ return new Controller(); } void delete_controller(Controller *controller){ delete controller; } int num_hands(const Controller *controller){ return controller->frame().hands().count(); } }
LeapMod.hs
{-# LANGUAGE ForeignFunctionInterface #-} module LeapMod where import Foreign.Ptr import Foreign.C data LeapController = LeapController data LeapFrame = LeapFrame foreign import ccall "wrapper.h new_controller" cNewController :: IO (Ptr LeapController) foreign import ccall "wrapper.h delete_controller" cDeleteController :: Ptr LeapController -> IO () foreign import ccall "wrapper.h num_hands" cNumHands :: Ptr LeapController -> IO CInt numHands :: Ptr LeapController -> IO Int numHands controller = do num <- cNumHands controller return $ fromIntegral num
そしてそれをmain関数からループ内で呼ぶコードを書く。
Main.hs
import Control.Monad import Control.Concurrent import LeapMod main = do ctrl <- cNewController forever $ do threadDelay $ 1 * 1000 * 1000 num <- numHands ctrl putStrLn $ "num hands: " ++ (show num)
controllerをdeleteする場所が無いのが気になるものの、とりあえずこれで準備はできた。
コンパイルしてみる。
g++ -c -I./include wrapper.cc -o wrapper.o ghc --make -main-is Main Main.hs -o ex_step4 libLeap.dylib -lstdc++ wrapper.o
実行する。
num hands: 0 num hands: 0 num hands: 1 num hands: 1 num hands: 2 num hands: 0
同じ結果を得ることができました。
これでHaskellからLeapMotionを触れることがわかりました。
あとは、適当にラッパーを充実させてやれば、色々できそうです。