Merge branch 'newtree'
[Faustine.git] / interpretor / faustio.ml
1 (**
2 Module: Faustio
3 Description: audio input/output, csv input/output
4 @author WANG Haisheng
5 Created: 12/08/2013 Modified: 13/08/2013
6 *)
7
8 open Types;;
9 open Basic;;
10 open Value;;
11 open Signal;;
12 open Beam;;
13 open Aux;;
14
15 let csv_read_buffer_length = 0xFFFF;;
16
17 class virtual io =
18 object
19 val mutable _basename = ""
20 val mutable _dir = ""
21 method set : string -> string -> unit =
22 fun (dir : string) ->
23 fun (basename : string) ->
24 _basename <- basename; _dir <- dir
25
26 method virtual read : string array -> beam
27 method virtual write : int array -> float array array array -> string array
28
29 method private concat : float array array array -> float array array =
30 fun (origin : float array array array) ->
31 Array.map Array.concat (Array.map Array.to_list origin)
32
33 method private channels : float array array array -> int array =
34 fun data ->
35 let get_channel = fun s ->
36 let l = Array.length s in
37 Array.length s.(l - 1) in
38 Array.map get_channel data
39 end;;
40
41 class waveio : io_type =
42 object (self)
43 inherit io
44 method read : string array -> beam =
45 fun (paths : string array) ->
46 let n = Array.length paths in
47 if n = 0 then
48 new beam [||]
49 else
50 let signals =
51 let files = Array.map Sndfile.openfile paths in
52 let frames = Array.map Int64.to_int
53 (Array.map Sndfile.frames files) in
54 let rates = Array.map Sndfile.samplerate files in
55 let create_container = fun l -> Array.create l 1. in
56 let containers = Array.map create_container frames in
57 let _ = array_map2 Sndfile.read files containers in
58 let _ = Array.map Sndfile.close files in
59 let stream2func =
60 fun stream -> fun t -> new value (R stream.(t)) in
61 array_map2 (new signal) rates (Array.map stream2func containers) in
62 new beam signals
63
64 method write : int array -> float array array array -> string array =
65 fun (rates : int array) ->
66 fun (output : float array array array) ->
67 let n = Array.length output in
68 let paths = Array.init n (fun i ->
69 _dir ^ _basename ^ (string_of_int (i + 1)) ^ ".wav") in
70
71 let files =
72 let channels = self#channels output in
73 let file_format = Sndfile.format
74 Sndfile.MAJOR_WAV Sndfile.MINOR_PCM_16 in
75 let openwr = fun path -> fun channel -> fun rate ->
76 Sndfile.openfile ~info:(Sndfile.RDWR, file_format, channel, rate) path in
77 array_map3 openwr paths channels rates in
78
79 let data = self#concat output in
80 let _ = array_map2 Sndfile.write files data in
81 let _ = Array.map Sndfile.close files in
82 paths
83 end;;
84
85
86
87 class csvio : io_type =
88 object (self)
89 inherit io
90 method private csvread : in_channel -> signal =
91 fun (ic : in_channel) ->
92 let buffer = Buffer.create csv_read_buffer_length in
93 let () =
94 try
95 while true do
96 Buffer.add_string buffer (input_line ic);
97 Buffer.add_char buffer '\t';
98 done;
99 with End_of_file -> () in
100 let content = Buffer.contents buffer in
101 let lines = Str.split (Str.regexp "\t") content in
102 let elements = List.map (Str.split (Str.regexp ",")) lines in
103 let data =
104 let data_in_list = List.map (List.map float_of_string) elements in
105 Array.of_list (List.map Array.of_list data_in_list) in
106 let values =
107 let convertor = new value Zero in
108 Array.map (convertor#of_float_array) data in
109 new signal 0 (Array.get values)
110
111 method read : string array -> beam =
112 fun (paths : string array) ->
113 let files = Array.map open_in paths in
114 let signals = Array.map self#csvread files in
115 new beam signals
116
117 method write : int array -> float array array array -> string array =
118 fun (rates : int array) ->
119 fun (data : float array array array) ->
120 let paths =
121 let n = Array.length data in
122 let path_pattern = fun i ->
123 _dir ^ _basename ^ (string_of_int (i + 1)) ^ ".csv" in
124 Array.init n path_pattern in
125
126 let files = Array.map open_out paths in
127 let strings =
128 let value2string : float array -> string =
129 fun (v : float array) ->
130 let strings = Array.map string_of_float v in
131 String.concat "," (Array.to_list strings) in
132 let signal2string : float array array -> string =
133 fun (s : float array array) ->
134 let lines = Array.map value2string s in
135 String.concat "\n" (Array.to_list lines) in
136 Array.map signal2string data in
137 let _ = array_map2 output_string files strings in
138 let _ = Array.map close_out files in
139 paths
140 end;;
141
142
143 class iomanager =
144 object (self)
145 val wave = new waveio
146 val csv = new csvio
147 val mutable _dir = ""
148 val mutable _format = ""
149 val mutable _basename = ""
150
151 method private grab_format : string -> string =
152 fun (path : string) ->
153 let fragments = Str.split (Str.regexp "\.") path in
154 let n = List.length fragments in
155 List.nth fragments (n - 1)
156
157 method read : string list -> beam_type =
158 fun (paths : string list) ->
159 let formats = List.map self#grab_format paths in
160 let read_one : string -> string -> beam_type =
161 fun (format : string) ->
162 fun (path : string) ->
163 if format = "wav" then wave#read [|path|]
164 else if format = "csv" then csv#read [|path|]
165 else raise (Invalid_argument "Unknown format.") in
166 let beams = List.map2 read_one formats paths in
167 let concat : beam_type -> beam_type -> beam_type =
168 fun b1 -> fun b2 -> b1#append b2 in
169 List.fold_left concat (new beam [||]) beams
170
171 method set : string -> string -> string -> unit =
172 fun (dir : string) ->
173 fun (format : string) ->
174 fun (basename : string) ->
175 _dir <- dir;
176 _format <- format;
177 _basename <- basename;
178 wave#set _dir _basename;
179 csv#set _dir _basename
180
181 method write : int array -> float array array array -> string array =
182 fun (rates : int array) ->
183 fun (data : float array array array) ->
184 if _format = "" then
185 raise (Invalid_argument "output format unset.")
186 else if _format = "wav" then
187 wave#write rates data
188 else if _format = "csv" then
189 csv#write rates data
190 else raise (Invalid_argument "unknown format.")
191
192 end;;