<commit_before>module Midi where

{-| A Library for working with MIDI

# Midi Messages
@docs incoming

# Representing Notes
@docs note, isNoteOn, isNoteOff

# Utility Functions
@docs velocity, emptyMessage

-}

import Signal (Signal)
import Native.Midi
import Bitwise (and)

type Input = { id:String, name:String, manufacturer:String }
type IncomingMessage = { input:Input, receivedTime:Int, midiData:[Int] }
type Note = { noteNumber:Int, velocity:Int }

incomingInputId : Signal String
incomingInputId = Native.Midi.incomingInputId

incomingInputManufacturer : Signal String
incomingInputManufacturer = Native.Midi.incomingInputManufacturer

incomingInputName : Signal String
incomingInputName = Native.Midi.incomingInputName

incomingData : Signal [Int]
incomingData = Native.Midi.incomingData

receivedTime : Signal Int
receivedTime = Native.Midi.receivedTime

incomingInput : String -> String -> String -> Input
incomingInput id name manufacturer = { id=id, name=name, manufacturer=manufacturer }

incomingMessage : Input -> Int -> [Int] -> IncomingMessage
incomingMessage input receivedTime midiData = { input=input, receivedTime=receivedTime, midiData=midiData }

{-| The signal of incoming MIDI message.

A MIDI message has following attributes.

  * input
    * id -- the id of MIDI input
    * manufacturer -- the manufacturer of MIDI input
    * name -- the name of MIDI input
  * receivedTime -- the time that the message was received
  * midiData -- the midi data([Int])
-}
incoming : Signal IncomingMessage
incoming = lift3 incomingMessage
     (lift3 incomingInput incomingInputId incomingInputName incomingInputManufacturer)
     receivedTime
     incomingData

{-| Whether given message is "note on". -}
isNoteOn : IncomingMessage -> Bool
isNoteOn msg =
    let midiData = msg.midiData
        f = (head midiData) `and` 240
        vel = velocity midiData
    in
      case f of
        144 -> if vel == 0 then False else True
        _ -> False

{-| Whether given message is "note off". -}
isNoteOff : IncomingMessage -> Bool
isNoteOff msg =
    ((head msg.midiData) `and` 240) == 128

{-| Get following note information from given message.

  * noteNumber
  * velocity
-}
note : IncomingMessage -> Maybe Note
note msg =
    if (isNoteOff msg) || (isNoteOn msg)
    then Just { noteNumber=head <| tail msg.midiData, velocity=velocity msg.midiData }
    else Nothing

{-| The empty MIDI message. -}
emptyMessage = { input=(incomingInput "" "" ""), receivedTime=0, midiData=[0, 0, 0] }

{-| Get velocity from MIDI data. -}
velocity : [Int] -> Int<commit_msg>fix emptyMessage<commit_after>module Midi where

{-| A Library for working with MIDI

# Midi Messages
@docs incoming

# Representing Notes
@docs note, isNoteOn, isNoteOff

# Utility Functions
@docs velocity, emptyMessage

-}

import Signal (Signal)
import Native.Midi
import Bitwise (and)

type Input = { id:String, name:String, manufacturer:String }
type IncomingMessage = { input:Input, receivedTime:Int, midiData:[Int] }
type Note = { noteNumber:Int, velocity:Int }

incomingInputId : Signal String
incomingInputId = Native.Midi.incomingInputId

incomingInputManufacturer : Signal String
incomingInputManufacturer = Native.Midi.incomingInputManufacturer

incomingInputName : Signal String
incomingInputName = Native.Midi.incomingInputName

incomingData : Signal [Int]
incomingData = Native.Midi.incomingData

receivedTime : Signal Int
receivedTime = Native.Midi.receivedTime

incomingInput : String -> String -> String -> Input
incomingInput id name manufacturer = { id=id, name=name, manufacturer=manufacturer }

incomingMessage : Input -> Int -> [Int] -> IncomingMessage
incomingMessage input receivedTime midiData = { input=input, receivedTime=receivedTime, midiData=midiData }

{-| The signal of incoming MIDI message.

A MIDI message has following attributes.

  * input
    * id -- the id of MIDI input
    * manufacturer -- the manufacturer of MIDI input
    * name -- the name of MIDI input
  * receivedTime -- the time that the message was received
  * midiData -- the midi data([Int])
-}
incoming : Signal IncomingMessage
incoming = lift3 incomingMessage
     (lift3 incomingInput incomingInputId incomingInputName incomingInputManufacturer)
     receivedTime
     incomingData

{-| Whether given message is "note on". -}
isNoteOn : IncomingMessage -> Bool
isNoteOn msg =
    let midiData = msg.midiData
        f = (head midiData) `and` 240
        vel = velocity midiData
    in
      case f of
        144 -> if vel == 0 then False else True
        _ -> False

{-| Whether given message is "note off". -}
isNoteOff : IncomingMessage -> Bool
isNoteOff msg =
    ((head msg.midiData) `and` 240) == 128

{-| Get following note information from given message.

  * noteNumber
  * velocity
-}
note : IncomingMessage -> Maybe Note
note msg =
    if (isNoteOff msg) || (isNoteOn msg)
    then Just { noteNumber=head <| tail msg.midiData, velocity=velocity msg.midiData }
    else Nothing

{-| The empty MIDI message. -}
emptyMessage : IncomingMessage
emptyMessage = { input=(incomingInput "" "" ""), receivedTime=0, midiData=[0, 0, 0] }

{-| Get velocity from MIDI data. -}
velocity : [Int] -> Int
{'fraction_non_alphanumeric': 0.09362934362934362, 'fraction_numerical': 0.007335907335907336, 'mean_word_length': 3.9389895138226882, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '386036', 'n_tokens_mistral': 1616, 'n_tokens_neox': 1529, 'n_words': 500}