| 1 | (***************************************************************************** |
|---|
| 2 | |
|---|
| 3 | Liquidsoap, a programmable audio stream generator. |
|---|
| 4 | Copyright 2003-2009 Savonet team |
|---|
| 5 | |
|---|
| 6 | This program is free software; you can redistribute it and/or modify |
|---|
| 7 | it under the terms of the GNU General Public License as published by |
|---|
| 8 | the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | (at your option) any later version. |
|---|
| 10 | |
|---|
| 11 | This program is distributed in the hope that it will be useful, |
|---|
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | GNU General Public License for more details, fully stated in the COPYING |
|---|
| 15 | file at the root of the liquidsoap distribution. |
|---|
| 16 | |
|---|
| 17 | You should have received a copy of the GNU General Public License |
|---|
| 18 | along with this program; if not, write to the Free Software |
|---|
| 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | |
|---|
| 21 | *****************************************************************************) |
|---|
| 22 | |
|---|
| 23 | (** Decode WAV files. *) |
|---|
| 24 | |
|---|
| 25 | let log = Dtools.Log.make ["decoder";"wav"] |
|---|
| 26 | |
|---|
| 27 | (** {1 Generic decoder} *) |
|---|
| 28 | |
|---|
| 29 | exception End_of_stream |
|---|
| 30 | |
|---|
| 31 | let rec really_input input len = |
|---|
| 32 | let s,i = input len in |
|---|
| 33 | if i=len then s else |
|---|
| 34 | if i=0 then raise End_of_stream else |
|---|
| 35 | String.sub s 0 i ^ really_input input (len-i) |
|---|
| 36 | |
|---|
| 37 | let input_byte input = |
|---|
| 38 | let s,i = input 1 in |
|---|
| 39 | if i=0 then raise End_of_stream ; |
|---|
| 40 | int_of_char s.[0] |
|---|
| 41 | |
|---|
| 42 | let read_int_num_bytes ic = |
|---|
| 43 | let rec aux = function |
|---|
| 44 | | 0 -> 0 |
|---|
| 45 | | n -> |
|---|
| 46 | let b = input_byte ic in |
|---|
| 47 | b + 256*(aux (n-1)) |
|---|
| 48 | in |
|---|
| 49 | aux |
|---|
| 50 | |
|---|
| 51 | let read_int ic = read_int_num_bytes ic 4 |
|---|
| 52 | |
|---|
| 53 | let read_short ic = read_int_num_bytes ic 2 |
|---|
| 54 | |
|---|
| 55 | module Make (Generator:Generator.S_Asio) = |
|---|
| 56 | struct |
|---|
| 57 | |
|---|
| 58 | (* TODO It might be more efficient to write our code for an input |
|---|
| 59 | * channel and use directly the one we have when decoding files |
|---|
| 60 | * or external processes, if we could wrap the input function used |
|---|
| 61 | * for decoding stream (in http and harbor) as an in_channel. *) |
|---|
| 62 | let create input = |
|---|
| 63 | let decoder = ref (fun gen -> assert false) in |
|---|
| 64 | |
|---|
| 65 | let main_decoder converter gen = |
|---|
| 66 | let bytes_to_get = 1024*64 in |
|---|
| 67 | let data,bytes = input bytes_to_get in |
|---|
| 68 | if bytes=0 then raise End_of_stream ; |
|---|
| 69 | log#f 4 "Read %d bytes of PCM" bytes ; |
|---|
| 70 | let content,length = converter (String.sub data 0 bytes) in |
|---|
| 71 | Generator.set_mode gen `Audio ; |
|---|
| 72 | Generator.put_audio gen content 0 length ; |
|---|
| 73 | log#f 4 "Done (%d)" length |
|---|
| 74 | in |
|---|
| 75 | |
|---|
| 76 | let read_header () = |
|---|
| 77 | |
|---|
| 78 | if really_input input 4 <> "RIFF" then |
|---|
| 79 | raise (Wav.Not_a_wav_file "Bad header: \"RIFF\" not found") ; |
|---|
| 80 | (* Ignore the file size *) |
|---|
| 81 | ignore (really_input input 4) ; |
|---|
| 82 | if really_input input 8 <> "WAVEfmt " then |
|---|
| 83 | raise (Wav.Not_a_wav_file "Bad header: \"WAVEfmt \" not found") ; |
|---|
| 84 | (* Now we always have the following uninteresting bytes: |
|---|
| 85 | * 0x10 0x00 0x00 0x00 0x01 0x00 *) |
|---|
| 86 | ignore (really_input input 6) ; |
|---|
| 87 | |
|---|
| 88 | let channels = read_short input in |
|---|
| 89 | let samplerate (* in Hz *) = read_int input in |
|---|
| 90 | let _ (* byt_per_sec *) = read_int input in |
|---|
| 91 | let _ (* byt_per_samp *) = read_short input in |
|---|
| 92 | let samplesize (* in bits *) = read_short input in |
|---|
| 93 | |
|---|
| 94 | let signed = samplesize <> 8 in |
|---|
| 95 | let big_endian = false in |
|---|
| 96 | |
|---|
| 97 | let section = really_input input 4 in |
|---|
| 98 | if section <> "data" then begin |
|---|
| 99 | if section = "INFO" then |
|---|
| 100 | raise (Wav.Not_a_wav_file "Valid wav file but unread"); |
|---|
| 101 | raise (Wav.Not_a_wav_file "Bad header : string \"data\" not found") |
|---|
| 102 | end ; |
|---|
| 103 | |
|---|
| 104 | let _ (* len_dat *) = read_int input in |
|---|
| 105 | |
|---|
| 106 | let converter = |
|---|
| 107 | Rutils.create_from_s16le |
|---|
| 108 | ~channels ~samplesize ~signed ~big_endian () |
|---|
| 109 | in |
|---|
| 110 | |
|---|
| 111 | log#f 4 |
|---|
| 112 | "WAV header read (%dHz, %dbits), starting decoding..." |
|---|
| 113 | samplerate samplesize ; |
|---|
| 114 | decoder := |
|---|
| 115 | main_decoder |
|---|
| 116 | (fun pcm -> converter ~audio_src_rate:(float samplerate) pcm) |
|---|
| 117 | |
|---|
| 118 | in |
|---|
| 119 | decoder := (fun _ -> read_header ()) ; |
|---|
| 120 | Decoder.Decoder (fun gen -> !decoder gen) |
|---|
| 121 | |
|---|
| 122 | end |
|---|
| 123 | |
|---|
| 124 | module Generator = Generator.From_audio_video |
|---|
| 125 | module Buffered = Decoder.Buffered(Generator) |
|---|
| 126 | |
|---|
| 127 | (* File decoding *) |
|---|
| 128 | |
|---|
| 129 | module D = Make(Generator) |
|---|
| 130 | |
|---|
| 131 | let get_type filename = |
|---|
| 132 | let chan = open_in filename in |
|---|
| 133 | let info = Wav.read_header chan filename in |
|---|
| 134 | close_in chan ; |
|---|
| 135 | { Frame. video = 0 ; midi = 0 ; audio = Wav.channels info } |
|---|
| 136 | |
|---|
| 137 | let create_file_decoder filename kind = |
|---|
| 138 | let generator = Generator.create `Audio in |
|---|
| 139 | Buffered.file_decoder filename kind D.create generator |
|---|
| 140 | |
|---|
| 141 | let () = |
|---|
| 142 | Decoder.file_decoders#register "WAV" |
|---|
| 143 | ~sdoc:"Decode as WAV any file with a correct header." |
|---|
| 144 | (fun filename kind -> |
|---|
| 145 | let file_type = get_type filename in |
|---|
| 146 | if Frame.type_has_kind file_type kind then |
|---|
| 147 | Some (fun () -> create_file_decoder filename kind) |
|---|
| 148 | else begin |
|---|
| 149 | log#f 3 |
|---|
| 150 | "WAV file %S has content type %s but %s was expected." |
|---|
| 151 | filename |
|---|
| 152 | (Frame.string_of_content_type file_type) |
|---|
| 153 | (Frame.string_of_content_kind kind) ; |
|---|
| 154 | None |
|---|
| 155 | end) |
|---|