let output_int chan n = output_char chan (char_of_int ((n lsr 0) land 0xff)); output_char chan (char_of_int ((n lsr 8) land 0xff)); output_char chan (char_of_int ((n lsr 16) land 0xff)); output_char chan (char_of_int ((n lsr 24) land 0xff)) let output_short chan n = output_char chan (char_of_int ((n lsr 0) land 0xff)); output_char chan (char_of_int ((n lsr 8) land 0xff)) let progress_bar = let spin = ref 0 in ( fun title pos tot -> let nbeq = 40 in let n = min (100. *. (float_of_int pos) /. (float_of_int tot)) 100. in Printf.printf "\r%s " title; if tot > 0 then begin Printf.printf "%6.2f%% [" n; let e = int_of_float (n /. 100. *. (float_of_int nbeq)) in for i = 1 to e do Printf.printf "=" done; if e != nbeq then Printf.printf ">"; for i = e + 2 to nbeq do Printf.printf " " done; Printf.printf "] " end ; incr spin; if !spin > 4 then spin := 1; Printf.printf "%c%!" ( if tot > 0 && n = 100. then ' ' else match !spin with | 1 -> '|' | 2 -> '/' | 3 -> '-' | 4 -> '\\' | _ -> failwith "this did not happen" ) ) let infile = ref "input.flac" let outfile = ref "output.raw" let ogg = ref false let () = Arg.parse [ "-o", Arg.Set_string outfile, "Output file"; "-i", Arg.Set_string infile, "Input file"; "-ogg", Arg.Bool (fun x -> ogg := x), "Ogg/flac file"; ] ignore "decode [options]" let () = let fd = Printf.printf "Opening input file %S\n%!" !infile; Unix.openfile !infile [Unix.O_RDONLY] 0o640 in let oc = Printf.printf "Opening output file %S\n%!" !outfile; open_out !outfile in let ret = Buffer.create 1024 in let write x = Buffer.add_string ret (Flac.Decoder.to_s16le x) in let get () = let ans = Buffer.contents ret in Buffer.reset ret; ans in let process,info,comments = if not !ogg then let h = Flac.Decoder.File.create_from_fd write fd in let process () = Flac.Decoder.process h.Flac.Decoder.File.dec h.Flac.Decoder.File.callbacks; Flac.Decoder.state h.Flac.Decoder.File.dec h.Flac.Decoder.File.callbacks in process,h.Flac.Decoder.File.info, h.Flac.Decoder.File.comments else let read_f n = let s = String.create n in let ret = Unix.read fd s 0 n in s,ret in let sync = Ogg.Sync.create read_f in let test_flac () = (** Get First page *) let page = Ogg.Sync.read sync in (** Check wether this is a b_o_s *) if not (Ogg.Page.bos page) then raise Flac.Decoder.Not_flac ; (** Create a stream with this ID *) let serial = Ogg.Page.serialno page in Printf.printf "Testing stream %nx\n" serial ; let os = Ogg.Stream.create ~serial () in Ogg.Stream.put_page os page ; let packet = Ogg.Stream.get_packet os in (** Test header. Do not catch anything, first page should be sufficient *) if not (Ogg_flac.Decoder.check_packet packet) then raise Not_found; Printf.printf "Got a flac stream !\n" ; let fill () = let page = Ogg.Sync.read sync in if Ogg.Page.serialno page = serial then Ogg.Stream.put_page os page in let callbacks = Ogg_flac.Decoder.get_callbacks write in let dec = Ogg_flac.Decoder.create packet os callbacks in let rec info () = try Flac.Decoder.init dec callbacks with | Ogg.Not_enough_data -> fill (); info () in let dec,info,meta = info () in let rec process () = try Flac.Decoder.process dec callbacks; Flac.Decoder.state dec callbacks with | Ogg.Not_enough_data -> ( try fill (); process () with Ogg.Not_enough_data -> `End_of_stream) in process,info,meta in (** Now find a flac stream *) let rec init () = try test_flac () with | Not_found -> ( Printf.printf "This stream was not flac..\n"; init () ) | Flac.Decoder.Not_flac -> ( Printf.printf "No flac stream was found..\n%!"; raise Flac.Decoder.Not_flac ) in init () in Printf.printf "Stream info:\n"; Printf.printf "sample rate: %i\n" info.Flac.Decoder.sample_rate ; Printf.printf "bits per sample: %i\n" info.Flac.Decoder.bits_per_sample ; Printf.printf "channels: %i\n" info.Flac.Decoder.channels ; Printf.printf "total samples: %s\n" (Int64.to_string info.Flac.Decoder.total_samples) ; Printf.printf "md5sum: " ; String.iter (fun c -> Printf.printf "%x" (int_of_char c)) info.Flac.Decoder.md5sum ; Printf.printf "\n"; if info.Flac.Decoder.bits_per_sample <> 16 then failwith "Unsupported bits per sample." ; let srate = info.Flac.Decoder.sample_rate in let chans = info.Flac.Decoder.channels in let datalen = (Int64.to_int info.Flac.Decoder.total_samples) * chans * 2 in let () = match comments with | None -> Printf.printf "No comment found..\n" ; | Some (vendor,comments) -> Printf.printf "Metadata:\n"; List.iter (fun (x,y) -> Printf.printf "%s: %s\n" x y) comments ; Printf.printf "VENDOR: %s\n" vendor in output_string oc "RIFF"; output_int oc (4 + 24 + 8 + datalen); output_string oc "WAVE"; output_string oc "fmt "; output_int oc 16; output_short oc 1; (* WAVE_FORMAT_PCM *) output_short oc chans; (* channels *) output_int oc srate; (* freq *) output_int oc (srate * chans * 2); (* bytes / s *) output_short oc (chans * 2); (* block alignment *) output_short oc 16; (* bits per sample *) output_string oc "data"; output_int oc datalen; let pos = ref 0 in let rec decode () = let state = process () in let ret = get () in pos := !pos + (String.length ret) ; progress_bar "Decoding FLAC file:" !pos datalen ; output_string oc ret ; flush oc ; match state with | `End_of_stream -> Printf.printf "\n" | _ -> decode () in decode () ; Printf.printf "\n"; close_out oc ; Unix.close fd ; (* We have global root values * so we need to do two full major.. *) Gc.full_major () ; Gc.full_major () ;