<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    Thanks very much!  This helped a lot (and you were right on #2... I
    really should have caught that).<br>
    <br>
    <div class="moz-cite-prefix">On 3/2/15 10:20 AM, Sylvain Henry
      wrote:<br>
    </div>
    <blockquote
cite="mid:CAPmptcWKW0-nyttQnu_-n-WsWdmndE_Z1RcBKwn=NvhCwaVpuw@mail.gmail.com"
      type="cite">
      <div dir="ltr">Hi,<br>
        <br>
        1) You have a copy-paste error on the following line
        (s/bitrate/track)<br>
         track <- ((#peek struct music_metadata, bitrate) a) :: IO
        Int<br>
        <br>
        2) By looking at the values you get in hexadecimal, you are
        reading 64bits values when your C struct contains 32 bits
        values. If you use: peek ... :: IO Int32, it should be ok.<br>
        <br>
        3) From a style point of view, you could use Applicative
        operators (from Control.Applicative) to avoid temporary names:<br>
        peek a = MusicMetaData<br>
                <$> liftM constantToCodec $ (((#peek struct
        music_metadata, codec) a) :: IO Int32)<br>
                <*> fmap fromIntegral (((#peek struct
        music_metadata, length) a) :: IO Int32)<br>
                <*> fmap fromIntegral (((#peek struct
        music_metadata, bitrate) a) :: IO Int32)<br>
                <*> fmap fromIntegral (((#peek struct
        music_metadata, channels) a) :: IO Int32)<br>
                <*> fmap fromIntegral (((#peek struct
        music_metadata, track) a) :: IO Int32)<br>
                <*> (peekCString =<< (#peek struct
        music_metadata, title) a)<br>
                ...<br>
        <br>
        4) In your constantToCodec function, you don't need the
        temporary names for all the constants.<br>
        <br>
        Best regards,<br>
        Sylvain<br>
        <br>
        PS : recently I have been working on rewriting the FFI page on
        the wiki to make it more beginner-friendly ;-). It is not
        totally finished but I'm open to any comment. <a
          moz-do-not-send="true"
          href="https://www.haskell.org/wiki/Foreign_Function_Interface"
          target="_blank">https://www.haskell.org/wiki/Foreign_Function_Interface</a><br>
      </div>
      <div class="gmail_extra"><br>
        <div class="gmail_quote">2015-02-28 14:20 GMT+01:00 Thomas
          Jakway <span dir="ltr"><<a moz-do-not-send="true"
              href="mailto:tjakway@nyu.edu" target="_blank">tjakway@nyu.edu</a>></span>:<br>
          <blockquote class="gmail_quote" style="margin:0 0 0
            .8ex;border-left:1px #ccc solid;padding-left:1ex">
            <div bgcolor="#FFFFFF" text="#000000"> I'm very new to
              Haskell and am trying to write a "real" program to
              motivate myself to learn it better (so far I've only
              gotten through Project Euler problems after reading LYAH
              and most of RWH).  I'm using Taglib (<a
                moz-do-not-send="true"
                href="https://github.com/taglib/taglib" target="_blank">https://github.com/taglib/taglib</a>)
              to read the metadata from a music file and print it.  I
              have a struct C-side (with C linkage) serving as the
              bridge between Taglib's C++ and Haskell's FFI.  A small
              demo program (compiled with gcc and linked against the C++
              object files) gives the correct results, but Haskell is
              weirdly only getting <i>some </i>of it right. 
              Specifically, the C string fields are working but ints are
              not.<br>
              <br>
              The output from the C demo (what Haskell should be
              printing):<br>
              <br>
              music_metadata<br>
              title: It's My Life,    artist: Bon Jovi,    album: Bon
              Jovi Greatest Hits - The Ultimate Collection<br>
              comment: ,    genre: Rock,    track: 3,<br>
              length: 224,    bitrate: 256,    channels: 2,<br>
              codec: 768<br>
              <br>
              The output from Haskell:<br>
              <br>
              MusicMetadata {codec = UNKNOWN, length = 1099511628000,
              bitrate = <a moz-do-not-send="true" href="tel:8589934848"
                value="+18589934848" target="_blank">8589934848</a>,
              channels = 12884901890, track = <a moz-do-not-send="true"
                href="tel:8589934848" value="+18589934848"
                target="_blank">8589934848</a>, title = "It's My Life",
              artist = "Bon Jovi", album = "Bon Jovi Greatest Hits - The
              Ultimate Collection", comment = "", genre = "Rock"}<br>
              <br>
              I would have expected it to work or not work at all, but
              did not anticipate getting only some of it right.<br>
              <br>
              I was going to include snippets from my hsc file but given
              how new I am to Haskell I don't trust myself to assume
              where the problem is, so sorry if this is way too long:<br>
              <br>
              {-# LANGUAGE CPP, ForeignFunctionInterface #-}<br>
              <br>
              module MusicReader<br>
              ( Codec,<br>
                MusicMetadata,<br>
                readMusicMetadata<br>
              ) where<br>
              <br>
              import Control.Monad<br>
              import Foreign<br>
              import Foreign.C.Types<br>
              import Foreign.C.String<br>
              import System.IO.Unsafe as Unsafe<br>
              <br>
              #include "CodecDefines.h"<br>
              #include "MusicReader.h"<br>
              <br>
              constantToCodec code<br>
                                  | code == mp3 = MP3<br>
                                  | code == flac = FLAC<br>
                                  | code == ogg = OGG_VORBIS<br>
                                  | code == mp4 = MP4<br>
                                  | code == mpeg = MPEG<br>
                                  | code == none = NONE<br>
                                  | code == unknown = UNKNOWN<br>
                                  | otherwise = UNKNOWN<br>
                                     where mp3 = #const MP3_CODEC<br>
                                           flac = #const FLAC_CODEC<br>
                                           ogg = #const OGG_VORBIS_CODEC
              <br>
                                           mp4 = #const MP4_CODEC<br>
                                           mpeg = #const MPEG_CODEC<br>
                                           none = #const NO_EXTENSION<br>
                                           unknown = #const
              UNKNOWN_EXTENSION<br>
              <br>
              data Codec = MP3 | FLAC | OGG_VORBIS | MP4 | MPEG | NONE |
              UNKNOWN deriving (Show)<br>
              <br>
              data MusicMetadata = MusicMetadata { codec :: Codec,<br>
                                    length :: Int,<br>
                                    bitrate :: Int,<br>
                                    channels :: Int,<br>
                                    track :: Int,<br>
                                    title :: String,<br>
                                    artist :: String,<br>
                                    album :: String,<br>
                                    comment :: String,<br>
                                    genre :: String } deriving (Show)<br>
              <br>
              instance Storable MusicMetadata where<br>
                  sizeOf _ = (#size struct music_metadata)<br>
                  alignment _ = alignment (undefined::CDouble)<br>
                  peek a = do<br>
                      codec <- liftM constantToCodec $ (((#peek
              struct music_metadata, codec) a) :: IO Int)<br>
                      length <- ((#peek struct music_metadata,
              length) a) :: IO Int<br>
                      bitrate <- ((#peek struct music_metadata,
              bitrate) a) :: IO Int<br>
                      channels <- ((#peek struct music_metadata,
              channels) a) :: IO Int<br>
                      track <- ((#peek struct music_metadata,
              bitrate) a) :: IO Int<br>
                      title <-  ((#peek struct music_metadata, title)
              a) :: IO CString<br>
                      artist <- ((#peek struct music_metadata,
              artist) a) :: IO CString<br>
                      album <- ((#peek struct music_metadata, album)
              a) :: IO CString<br>
                      comment <- ((#peek struct music_metadata,
              comment) a) :: IO CString<br>
                      genre <- ((#peek struct music_metadata, genre)
              a) :: IO CString<br>
                      --FIXME: find replacement for temporary names<br>
                      marshalledTitle <- peekCString title<br>
                      marshalledArtist <- peekCString artist<br>
                      marshalledAlbum <- peekCString album<br>
                      marshalledComment <- peekCString comment<br>
                      marshalledGenre <- peekCString genre<br>
                      return (MusicMetadata codec length bitrate
              channels track marshalledTitle marshalledArtist
              marshalledAlbum marshalledComment marshalledGenre)<br>
                  poke a = undefined<br>
              <br>
              --This is the "primitive" FFI call--calls the C function
              and gets a pointer<br>
              --in return<br>
              --TODO: write a higher level function this module should
              export that calls<br>
              --primReadMusicMetadata and converts the C Pointer into
              the Haskell data<br>
              --MusicMetadata<br>
              foreign import ccall unsafe "read_metadata"
              primReadMusicMetadata :: CString -> IO (Ptr
              MusicMetadata)<br>
              <br>
              --convert the Haskell string to a CString, call into the
              FFI then<br>
              --dereference the resulting pointer<br>
              readMusicMetadata a = join $ withCString a $ \cs ->
              ((liftM peek) $ primReadMusicMetadata cs)<br>
              <br>
              <br>
              <br>
              Here's the struct in MusicReader.h (in an extern C block):<br>
                  struct music_metadata<br>
                  {<br>
                      int codec;<br>
                      int length,<br>
                              bitrate,<br>
                              channels;<br>
                      int track;<br>
                      char *title,<br>
                           *artist,<br>
                           *album,<br>
                           *comment,<br>
                           *genre;<br>
                  };<br>
              <br>
              <br>
              with the corresponding call:<br>
                  struct music_metadata* read_metadata(char*);<br>
              <br>
              <br>
              I've tried playing around with the alignment but it didn't
              do anything.  I also tried declaring the struct's fields
              as int32_t which also did nothing.<br>
              <br>
              The C demo in question is a very simple:<br>
              <br>
              #include <stdio.h><br>
              #include "MusicReader.h"<br>
              <br>
              #define FILENAME "Its_My_Life.m4a"<br>
              <br>
              int main()<br>
              {<br>
                  struct music_metadata* metadata =
              read_metadata(FILENAME);   <br>
                  printf("music_metadata\ntitle: %s,\tartist:
              %s,\talbum: %s\n",<br>
                          metadata->title, metadata->artist,
              metadata->album);<br>
                  printf("comment: %s,\tgenre: %s,\ttrack: %d,\n", <br>
                          metadata->comment, metadata->genre,
              metadata->track);<br>
                  printf("length: %d,\tbitrate: %d,\tchannels: %d,\n",<br>
                          metadata->length, metadata->bitrate,
              metadata->channels);<br>
                  printf("codec: %d\n");<br>
              <br>
              }<br>
              <br>
              It just reads the metadata into the struct and prints the
              fields.<br>
              <br>
              I've gotten the impression of the Haskell FFI being very
              beginner-unfriendly, which isn't surprising but still
              disappointing because it would be a great opportunity to
              replace some projects with Haskell.<br>
              <br>
              Any help is appreciated, including general feedback on my
              code!<br>
            </div>
            <br>
            _______________________________________________<br>
            Beginners mailing list<br>
            <a moz-do-not-send="true"
              href="mailto:Beginners@haskell.org">Beginners@haskell.org</a><br>
            <a moz-do-not-send="true"
              href="http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners"
              target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners</a><br>
            <br>
          </blockquote>
        </div>
        <br>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
Beginners mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Beginners@haskell.org">Beginners@haskell.org</a>
<a class="moz-txt-link-freetext" href="http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners">http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>