Changeset 6701

Show
Ignore:
Timestamp:
06/30/09 18:04:10 (9 months ago)
Author:
smimram
Message:

MIDI files support is starting to work.

Location:
trunk/liquidsoap/src
Files:
6 modified
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/liquidsoap/src/Makefile

    r6695 r6701  
    3535        $(if $(W_NSV),formats/nattyformat_mp3.ml) \ 
    3636        $(if $(W_NATTY),formats/nattyformat.ml) \ 
    37         $(if $(W_MP3),formats/mp3.ml) 
    38 #       formats/midiformat.ml 
     37        $(if $(W_MP3),formats/mp3.ml) \ 
     38        formats/midiformat.ml 
    3939 
    4040playlists = \ 
     
    144144        $(if $(W_GL),visualization/GLvisualizer.ml) \ 
    145145        $(if $(W_GL),visualization/vis_glvolume.ml) \ 
    146         visualization/video_volume.ml 
     146        visualization/video_volume.ml \ 
     147        visualization/midimeter.ml 
    147148 
    148149synth = synth/synth.ml synth/synth_op.ml \ 
  • trunk/liquidsoap/src/formats/midiformat.ml

    r6344 r6701  
    5353    if division land 0x8000 = 0 then 
    5454      ( 
     55        (* Delta-time ticks per quarter *) 
    5556        log#f 5 "Ticks per quarter: %d" division; 
    5657        Midi.Ticks_per_quarter division 
     
    5960      let frames = (division lsr 8) land 0x7f in 
    6061      let ticks = division land 0xff in 
     62        log#f 5 "SMPTE: %d * %d" frames ticks; 
    6163        Midi.SMPTE (frames, ticks) 
    6264  in 
     
    6668        raise Invalid_header; 
    6769      ); 
    68     log#f 5 "Tracks: %d" tracks; 
     70    log#f 5 "Format: %d (%d tracks)" fmt tracks; 
    6971    tracks, division 
    7072 
     
    9092      !ans 
    9193  in 
     94  let status = ref 0 in (* for running status *) 
    9295  let read_event () = 
    9396    let get_byte () = 
     
    103106        ans 
    104107    in 
    105     let cmd = (data.(!pos) lsr 4) land 0xf in 
    106     let chan = data.(!pos) land 0xf in 
     108    let advance len = 
     109      pos := !pos + len 
     110    in 
     111    let command = data.(!pos) in 
    107112    incr pos; 
    108     let event = 
     113    let command = 
     114      if command land 0x80 <> 0 then 
     115        ( 
     116          status := command; 
     117          command 
     118        ) 
     119      else 
     120        ( 
     121          decr pos; 
     122          !status 
     123        ) 
     124    in 
     125    let cmd = (command lsr 4) land 0xf in 
     126    let chan = command land 0xf in 
    109127      match cmd with 
    110128        | 8 -> 
    111129            let n = get_byte () in 
    112130            let v = get_byte () in 
    113               Midi.Note_off (n, v) 
     131              Some chan, Midi.Note_off (n, float v /. 127.) 
    114132        | 9 -> 
    115133            let n = get_byte () in 
    116134            let v = get_byte () in 
    117               log#f 6 "Note on: %d %d" n v; 
    118               Midi.Note_on (n, v) 
    119         | 10 -> 
     135              Some chan, Midi.Note_on (n, float v /. 127.) 
     136        | 0xa -> 
    120137            let n = get_byte () in 
    121138            let v = get_byte () in 
    122               Midi.Aftertouch (n, v) 
    123         | 11 -> 
     139              Some chan, Midi.Aftertouch (n, float v /. 127.) 
     140        | 0xb -> 
    124141            let c = get_byte () in 
    125142            let v = get_byte () in 
    126               Midi.Control_change (c, v) 
    127         | 12 -> 
     143              Some chan, Midi.Control_change (c, v) 
     144        | 0xc -> 
    128145            let p = get_byte () in 
    129               Midi.Patch p 
    130         | 13 -> 
     146              Some chan, Midi.Patch p 
     147        | 0xd -> 
    131148            let c = get_byte () in 
    132               Midi.Channel_aftertouch c 
    133         | 14 -> 
     149              Some chan, Midi.Channel_aftertouch c 
     150        | 0xe -> 
    134151            let l = get_byte () land 0x7f in 
    135152            let h = get_byte () land 0x7f in 
    136               Midi.Pitch ((h lsl 7) + l) 
    137         | 15 -> 
    138             ( 
    139               let cmd = get_byte () in 
    140                 match cmd with 
    141                   | 0 -> 
    142                       assert (get_byte () = 2); 
    143                       let h = get_byte () in 
    144                       let l = get_byte () in 
    145                         Midi.Sequence_number ((h lsl 8) + l) 
    146                   | 1 -> 
    147                       let len = get_byte () in 
    148                         Midi.Text (get_text len) 
    149                   | 2 -> 
    150                       let len = get_byte () in 
    151                         Midi.Copyright (get_text len) 
    152                   | 3 -> 
    153                       let len = get_byte () in 
    154                         Midi.Track_name (get_text len) 
    155                   | 4 -> 
    156                       let len = get_byte () in 
    157                         Midi.Instrument_name (get_text len) 
    158                   | 5 -> 
    159                       let len = get_byte () in 
    160                         Midi.Lyric (get_text len) 
    161                   | 6 -> 
    162                       let len = get_byte () in 
    163                         Midi.Marker (get_text len) 
    164                   | 7 -> 
    165                       let len = get_byte () in 
    166                         Midi.Cue (get_text len) 
    167                   | _ -> 
    168                       log#f 5 "Unknown command 15,%d" cmd; 
    169                       raise Not_found 
    170             ) 
     153              Some chan, Midi.Pitch ((h lsl 7) + l) 
    171154        | _ -> 
    172             (* log#f 5 "Unknown command %d" cmd; *) 
    173             raise Not_found 
    174     in 
    175       chan, event 
     155            match command with 
     156              | 0xf0 
     157              | 0xf7 -> 
     158                  (* SysEx *) 
     159                  let len = read_delta () in 
     160                    advance len; 
     161                    raise Not_found 
     162              | 0xff -> 
     163                  ( 
     164                  let cmd = get_byte () in 
     165                  let len = read_delta () in 
     166                    match cmd with 
     167                      | 0 -> 
     168                          assert (len = 2); 
     169                          let h = get_byte () in 
     170                          let l = get_byte () in 
     171                            None, Midi.Sequence_number ((h lsl 8) + l) 
     172                      | 1 -> 
     173                          None, Midi.Text (get_text len) 
     174                      | 2 -> 
     175                          None, Midi.Copyright (get_text len) 
     176                      | 3 -> 
     177                          None, Midi.Track_name (get_text len) 
     178                      | 4 -> 
     179                          None, Midi.Instrument_name (get_text len) 
     180                      | 5 -> 
     181                          None, Midi.Lyric (get_text len) 
     182                      | 6 -> 
     183                          None, Midi.Marker (get_text len) 
     184                      | 7 -> 
     185                          None, Midi.Cue (get_text len) 
     186                      | 0x2f (* End of track *) -> 
     187                          assert (len = 0); 
     188                          raise Not_found 
     189                      | 0x51 (* Tempo in microseconds per quarter note *) -> 
     190                          assert (len = 3); 
     191                          let t1 = get_byte () in 
     192                          let t2 = get_byte () in 
     193                          let t3 = get_byte () in 
     194                          let t = t1 lsl 16 + t2 lsl 8 + t3 in 
     195                            ignore t; 
     196                            None, Midi.Tempo t 
     197                      | 0x58 (* Time signature *) -> 
     198                          assert (len = 4); 
     199                          let n = get_byte () in (* numerator *) 
     200                          let d = get_byte () in (* denominator *) 
     201                          let c = get_byte () in (* ticks in a metronome click *) 
     202                          let b = get_byte () in (* 32nd notes to the quarter note *) 
     203                            ignore (n, d, c, b); 
     204                            None, Midi.Time_signature (n, d, c, b) 
     205                      | 0x59 (* Key signature *) -> 
     206                          assert (len = 2); 
     207                          let sf = get_byte () in (* sharps / flats *) 
     208                          let m = get_byte () in (* minor? *) 
     209                            ignore (sf, m); 
     210                            None, Midi.Key_signature (sf, m <> 0) 
     211                      | 0x54 (* SMPTE Offset *) 
     212                      | 0x7f (* Sequencer-specific data *) -> 
     213                          advance len; 
     214                          raise Not_found 
     215                      | _ -> 
     216                          advance len; 
     217                          log#f 5 "Unknown meta-event %x" cmd; 
     218                          raise Not_found 
     219                  ) 
     220              | _ -> 
     221                  advance 1; 
     222                  log#f 5 "Unknown command %x (pos: %d)" command !pos; 
     223                  raise Not_found 
    176224  in 
    177225  let ans = ref [] in 
    178226    while !pos < len do 
    179227      try 
    180         ans := (read_delta (), read_event ())::!ans 
     228        let d = read_delta () in 
     229        let e = read_event () in 
     230        ans := (d, e)::!ans 
    181231      with 
    182232        | Not_found -> () 
     
    186236let decoder file = 
    187237  log#f 4 "Decoding %s..." file; 
    188   let fd = Unix.openfile file [Unix.O_RDONLY] 0 in 
     238  let fd = Unix.openfile file [Unix.O_RDONLY] 0o644 in 
    189239  let closed = ref false in 
    190240 
     
    202252    (* We don't need to access the file anymore. *) 
    203253    close (); 
    204     log#f 5 "Read %d events" (List.length tracks.(0)); 
     254    (* Convert delta-times in delta-liquidsoap-ticks. *) 
     255    for n = 0 to ntracks - 1 do 
     256      let tpq = 
     257        match division with 
     258          | Midi.Ticks_per_quarter tpq -> tpq 
     259          | _ -> assert false 
     260      in 
     261      let tempo = ref 125000 in 
     262        tracks.(n) <- 
     263          List.map 
     264            (fun (d,(c,e)) -> 
     265               let d = (d * !tempo / tpq) * Fmt.ticks_per_second () / 1000000 in 
     266               let d = d * 2 in (* TODO: remove this! *) 
     267                 ( 
     268                   match e with 
     269                     | Midi.Tempo t -> 
     270                         tempo := t 
     271                     | _ -> () 
     272                 ); 
     273                 (d,(c,e)) 
     274            ) tracks.(n) 
     275    done; 
     276    (* Merge all tracks. *) 
     277    let track = ref tracks.(0) in (* TODO! *) 
     278    (* Filling function. *) 
    205279    let fill buf = 
    206       1000 (* TODO *) 
     280      let m = MFrame.tracks buf in 
     281      (* TODO: why do we have to do this here??? *) 
     282      AFrame.blankify buf 0 (AFrame.size buf); 
     283      m.(0) := []; 
     284      let buflen = MFrame.size buf in 
     285      let offset_in_buf = ref 0 in 
     286        while !track <> [] && !offset_in_buf < buflen do 
     287          let d,(c,e) = List.hd !track in 
     288            (* Printf.printf "delta: %d\n%!" d; *) 
     289            offset_in_buf := !offset_in_buf + d; 
     290            if !offset_in_buf < buflen then 
     291              ( 
     292                track := List.tl !track; 
     293                match c with 
     294                  | Some c -> 
     295                      ( 
     296                        match e with 
     297                          | Midi.Note_on _ 
     298                          | Midi.Note_off _ -> 
     299                              (* Printf.printf "EVENT (chan %d)!\n%!" c; *) 
     300                              let c = if c <> 10 then 0 else c in (* TODO: remove this *) 
     301                              m.(c) := !(m.(c))@[!offset_in_buf, e] 
     302                          | _ -> () (* TODO *) 
     303                      ) 
     304                  | None -> () (* TODO *) 
     305              ) 
     306            else 
     307              track := (!offset_in_buf - buflen,(c,e))::(List.tl !track) 
     308        done; 
     309        MFrame.add_break buf (MFrame.size buf); 
     310        0 
    207311    in 
    208312      { Decoder.fill = fill ; Decoder.close = fun () -> () } 
     
    213317 
    214318(* TODO *) 
     319(* 
    215320let metadatas ~format file = 
    216321  [] 
    217322 
    218323let () = Request.mresolvers#register "MID" metadatas 
     324*) 
  • trunk/liquidsoap/src/stream/mFrame.mli

    r6694 r6701  
    66val is_partial : t -> bool 
    77 
    8 (** Number of video frames. *) 
     8(** Number of ticks in a MIDI frame. *) 
    99val size : t -> int 
    1010 
  • trunk/liquidsoap/src/synth/keyboard_sdl.ml

    r6699 r6701  
    9898  Lang.add_operator "input.keyboard.sdl" 
    9999    [ 
    100       "velocity", Lang.float_t, Some (Lang.float 0.3), Some "Velocity of notes." 
     100      "velocity", Lang.float_t, Some (Lang.float 0.8), Some "Velocity of notes." 
    101101    ] 
    102102    ~category:Lang.Input 
  • trunk/liquidsoap/src/synth/synth.ml

    r6700 r6701  
    55class type synth = 
    66object 
     7  method set_volume : float -> unit 
     8 
    79  method note_on : int -> float -> unit 
    810 
     
    1012 
    1113  method synth : float -> float array array -> int -> int -> unit 
     14 
     15  method reset : unit 
    1216end 
    1317 
     
    1519class virtual ['gs,'ns] base = 
    1620object (self) 
     21  val mutable volume = 1. 
     22 
     23  method set_volume v = volume <- v 
     24 
    1725  val mutable state = None 
    1826 
     
    2331 
    2432  val mutable notes = [] 
     33 
     34  method reset = notes <- [] 
    2535 
    2636  method virtual state_init : 'gs 
     
    3545 
    3646  method note_on n v = 
     47    (* Limit the number of notes for now. TODO: parameter *) 
     48    if List.length notes > 8 then notes <- List.rev (List.tl (List.rev notes)); 
    3749    notes <- (n, ref (self#note_init n v))::notes 
    3850 
     
    8496    let phase i = ns.simple_phase +. float i /. freq *. ns.simple_freq in 
    8597      for i = ofs to ofs + len - 1 do 
    86         buf.(i) <- buf.(i) +. ns.simple_ampl *. f (phase i) 
     98        buf.(i) <- buf.(i) +. volume *. ns.simple_ampl *. f (phase i) 
    8799      done; 
    88100      gs, { ns with simple_phase = fst (modf (phase len)) } 
  • trunk/liquidsoap/src/synth/synth_op.ml

    r6700 r6701  
    2323open Source 
    2424 
    25 class synth (synth:Synth.synth) (source:source) chan = 
     25class synth (synth:Synth.synth) (source:source) chan volume = 
    2626object (self) 
    2727  inherit operator [source] as super 
     28 
     29  initializer 
     30    synth#set_volume volume 
    2831 
    2932  method stype = source#stype 
     
    6265end 
    6366 
    64 let () = 
    65   Lang.add_operator "synth.sine" 
    66     [ "", Lang.source_t, None, None ] 
     67let register obj name descr = 
     68  Lang.add_operator ("synth." ^ name) 
     69    [ 
     70      "channel", Lang.int_t, Some (Lang.int 0), Some "MIDI channel to handle."; 
     71      "volume", Lang.float_t, Some (Lang.float 0.3), Some "Volume."; 
     72      "", Lang.source_t, None, None 
     73    ] 
    6774    ~category:Lang.SoundSynthesis 
    68     ~descr:"Sine synthesiser." 
     75    ~descr 
    6976    (fun p _ -> 
    7077       let f v = List.assoc v p in 
     78       let chan = Lang.to_int (f "channel") in 
     79       let volume = Lang.to_float (f "volume") in 
    7180       let src = Lang.to_source (f "") in 
    72          new synth (new Synth.sine :> Synth.synth) src 0) 
     81         new synth (obj ()) src chan volume) 
    7382 
    74 let () = 
    75   Lang.add_operator "synth.square" 
    76     [ "", Lang.source_t, None, None ] 
    77     ~category:Lang.SoundSynthesis 
    78     ~descr:"Square synthesiser." 
    79     (fun p _ -> 
    80        let f v = List.assoc v p in 
    81        let src = Lang.to_source (f "") in 
    82          new synth (new Synth.square :> Synth.synth) src 0) 
    83  
    84 let () = 
    85   Lang.add_operator "synth.saw" 
    86     [ "", Lang.source_t, None, None ] 
    87     ~category:Lang.SoundSynthesis 
    88     ~descr:"Saw synthesiser." 
    89     (fun p _ -> 
    90        let f v = List.assoc v p in 
    91        let src = Lang.to_source (f "") in 
    92          new synth (new Synth.saw :> Synth.synth) src 0) 
     83let () = register (fun () -> (new Synth.sine :> Synth.synth)) "sine" "Sine synthesiser." 
     84let () = register (fun () -> (new Synth.square :> Synth.synth)) "square" "Square synthesiser." 
     85let () = register (fun () -> (new Synth.saw :> Synth.synth)) "saw" "Saw synthesiser." 
  • trunk/liquidsoap/src/visualization/midimeter.ml

    r6527 r6701  
    2121 *****************************************************************************) 
    2222 
    23 (** VU meter. *) 
    24  
    2523open Source 
    2624 
    27 let screen_width = 80 
    28 let rms_max = -5. 
    29 let rms_min = -25. 
    30  
    31 let vol n v = 
    32   let v = Sutils.dB_of_lin v in 
    33   let ans = ref "" in 
    34   let barwidth = screen_width / n - 7 in 
    35   let barlen = int_of_float (float barwidth *. min 1. (max 0. ((v -. rms_min) /. (rms_max -. rms_min)))) in 
    36     for i = 0 to barlen - 1 do ans := !ans ^ "=" done; 
    37     for i = 0 to barwidth - barlen - 1 do ans := !ans ^ "." done; 
    38     Printf.sprintf "% 5.1f %s" v !ans 
    39  
    40 class vumeter source scroll = 
     25class midimeter source = 
    4126object 
    4227  inherit operator [source] as super 
     
    4833 
    4934  method get_frame buf = 
    50     let offset = AFrame.position buf in 
    5135    source#get buf; 
    52     let rms = AFrame.rms buf offset (AFrame.position buf - offset) in 
    53     let vol = Array.map (vol (Array.length rms)) rms in 
    54     let vol = Array.fold_left (fun ans s -> ans ^ "  " ^ s) "" vol in 
    55     let vol = String.sub vol 2 (String.length vol - 2) in 
    56       if scroll then 
    57         Printf.printf "%s\n%!" vol 
    58       else 
    59         Printf.printf "\r%s%!" vol 
     36    let m = MFrame.tracks buf in 
     37      for c = 0 to Array.length m - 1 do 
     38        List.iter 
     39          (fun (t, e) -> 
     40             let s = 
     41               match e with 
     42                 | Midi.Note_on (n, v) -> 
     43                     Printf.sprintf "Note %d on at %.02f" n v 
     44                 | Midi.Note_off (n, v) -> 
     45                     Printf.sprintf "Note %d off at %.02f" n v 
     46                 | _ -> "???" 
     47             in 
     48               Printf.printf "%d: %s.\n%!" c s 
     49          ) !(m.(c)) 
     50      done 
    6051end 
    6152 
    6253let () = 
    63   Lang.add_operator "vumeter" 
    64     [ "scroll", Lang.bool_t, Some (Lang.bool false), Some "Scroll."; 
    65       "", Lang.source_t, None, None ] 
     54  Lang.add_operator "midimeter" 
     55    [ "", Lang.source_t, None, None ] 
    6656    ~category:Lang.Visualization 
    67     ~descr:"VU meter (display the volume)." 
     57    ~flags:[Lang.Hidden; Lang.Experimental] 
     58    ~descr:"Display midi events." 
    6859    (fun p _ -> 
    6960       let f v = List.assoc v p in 
    70        let scroll, src = 
    71          Lang.to_bool (f "scroll"), 
    72          Lang.to_source (f "") 
    73        in 
    74          ((new vumeter src scroll):>Source.source)) 
     61       let src = Lang.to_source (f "") in 
     62         ((new midimeter src):>Source.source))