package mad

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file mad.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
(*
 * Copyright 2003-2006 Savonet team
 *
 * This file is part of Ocaml-mad.
 *
 * Ocaml-mad is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Ocaml-mad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Ocaml-mad; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *)

(**
  * Functions for decoding mp3 files using libmad.
  *
  * @author Samuel Mimram
  *)

(* $Id$ *)

type read = bytes -> int -> int -> int
type mad_file
type mpeg_layer = Layer_I | Layer_II | Layer_III
type emphasis = None | MS_50_15 | CCITT_J_17 | Reserved
type channel_mode = Single_channel | Dual_channel | Joint_stereo | Stereo

type frame_format = {
  layer : mpeg_layer;
  mode : channel_mode;
  emphasis : emphasis;
  bitrate : int;
  samplerate : int;
  channels : int;
  samples_per_channel : int;
  original : bool;
  copyright : bool;
  private_bit : bool;
}

exception Mad_error of string
exception Read_error of string
exception End_of_stream
exception Openfile_error of string
exception Closefile_error of string

let _ =
  Callback.register_exception "mad_exn_mad_error" (Mad_error "");
  Callback.register_exception "mad_exn_read_error" (Read_error "");
  Callback.register_exception "mad_exn_end_of_stream" End_of_stream;
  Callback.register_exception "mad_exn_openfile_error" (Openfile_error "");
  Callback.register_exception "mad_exn_closefile_error" (Closefile_error "")

external openfile : string -> mad_file = "ocaml_mad_openfile"
external openstream : read -> mad_file = "ocaml_mad_openstream"

external skip_id3tags : read -> (int -> int) -> (unit -> int) -> unit
  = "ocaml_mad_skip_id3tag"

let skip_id3tags ~read ~seek ~tell = skip_id3tags read seek tell

external close : mad_file -> unit = "ocaml_mad_close"

external get_current_position : mad_file -> int
  = "ocaml_mad_get_current_position"

external get_current_time : mad_file -> int -> int = "ocaml_mad_time"

type time_unit =
  | Hours
  | Minutes
  | Seconds
  | Deciseconds
  | Centiseconds
  | Milliseconds

let int_of_time_unit = function
  | Hours -> -2
  | Minutes -> -1
  | Seconds -> 0
  | Deciseconds -> 10
  | Centiseconds -> 100
  | Milliseconds -> 1000

let get_current_time dec u = get_current_time dec (int_of_time_unit u)

external skip_frame : mad_file -> unit = "ocaml_mad_skip_frame"
external decode_frame : mad_file -> string = "ocaml_mad_decode_frame"

external decode_frame_float : mad_file -> float array array
  = "ocaml_mad_decode_frame_float"

external decode_frame_floatarray : mad_file -> floatarray array
  = "ocaml_mad_decode_frame_floatarray"

external decode_frame_float_ba :
  mad_file ->
  (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t array
  = "ocaml_mad_decode_frame_float_ba"

external get_frame_format : mad_file -> frame_format
  = "ocaml_mad_get_frame_format"

let get_output_format mf =
  let header = get_frame_format mf in
  (header.samplerate, header.channels, header.samples_per_channel)

let duration file =
  let mf = openfile file in
  let close () = try close mf with _ -> () in
  try
    begin
      try
        while true do
          skip_frame mf
        done
      with _ -> ()
    end;
    let ret = float (get_current_time mf Centiseconds) /. 100. in
    close ();
    ret
  with _ ->
    close ();
    0.