* Bugs 16137 16138 16140 fixed: playsnd() fixed & upgraded
[scilab.git] / scilab / modules / sound / macros / playsnd.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) ???? - INRIA - Scilab
3 // Copyright (C) ???? - ENPC
4 // Copyright (C) 2009 - DIGITEO - Allan CORNET
5 // Copyright (C) 2012 - 2016 - Scilab Enterprises
6 // Copyright (C) 2019 - Samuel GOUGEON
7 //
8 // This file is hereby licensed under the terms of the GNU GPL v2.0,
9 // pursuant to article 5.3.4 of the CeCILL v.2.1.
10 // This file was originally licensed under the terms of the CeCILL v2.1,
11 // and continues to be available under such terms.
12 // For more information, see the COPYING file which you should have received
13 // along with this program.
14
15 function playsnd(y, rate, nbiter, playerCmd)
16
17     [lhs,rhs] = argn(0);
18     fname = "playsnd"
19     File = ""
20     if argn(2) < 1 | argn(2) > 4
21         msg = _("%s: Wrong number of input arguments: %d or %d expected.\n")
22         error(msprintf(msg, fname, 1, 4))
23     end
24
25     // PARSING INPUT ARGUMENTS and SETTING DEFAULT VALUES
26     // ==================================================
27     // rate / speed
28     // ------------
29     if ~isdef("rate","l") then
30         if type(y)==1
31             rate = 22050;
32         else
33             rate = 1
34         end
35     end
36
37     // nbiter
38     // ------
39     iPlayerCmd = 4    // index of playerCmd (if any)
40     if ~isdef("nbiter","l")
41         nbiter = -1
42         iPlayerCmd = 3
43     else
44         if and(type(nbiter)<>[1 10])
45             msg = _("%s: Argument #%d: %s expected.\n")
46             error(msprintf(msg, fname, 3, "Decimal numbers or Text"))
47         end
48         nbiter = nbiter(1)
49         if type(nbiter)==10
50             playerCmd = nbiter
51             iPlayerCmd = 3
52             nbiter = -1
53         elseif nbiter < 1
54             msg = _("%s: Argument #%d: Must be >= %d.\n")
55             error(msprintf(msg, fname, 3, 1))
56         else
57             nbiter = int(nbiter)
58         end
59     end
60
61     // playerCmd
62     // ---------
63     if ~isdef("playerCmd","l") then
64         if getos() == "Darwin" then
65             playerCmd = "afplay"
66         else
67             playerCmd = "aplay";
68         end
69     else
70         if type(playerCmd) <> 10 then
71             error(msprintf(_("%s: Wrong type for input argument #%d: string expected.\n"), fname, iPlayerCmd));
72         end
73         if size(playerCmd,"*") <> 1 then
74             error(msprintf(_("%s: Wrong size for input argument #%d: string expected.\n"), fname, iPlayerCmd));
75         end
76     end
77
78     // Input sound data
79     // ----------------
80     if and(type(y) <> [1 10]) then
81         msg = _("%s: Argument #%d: %s expected.\n")
82         error(msprintf(msg, fname, 1, "Decimal numbers or Text"))
83     end
84     if type(y)==10 then
85         File = pathconvert(y(1),%f)
86         if isdir(File)
87             msg = _("%s: Argument #%d: ''%s'' is a directory. File expected.\n")
88             error(msprintf(msg, fname, 1, File))
89         end
90         if ~isfile(File)
91             msg = _("%s: Argument #%d: The file ''%s'' does not exist.\n")
92             error(msprintf(msg, fname, 1, File))
93         end
94         if type(rate) <> 1
95             msg = _("%s: Argument #%d: Decimal number expected.\n")
96             error(msprintf(msg, fname, 2))
97         end
98         rate = rate(1)
99         if rate <= 0
100             msg = _("%s: Argument #%d: Must be > %d.\n")
101             error(msprintf(msg, fname, 2, 0))
102         end
103         info = wavread(y,"info");
104         // The only case where the file can be used as is without being
105         // loaded is when the speed = 1 & OS = Linux | MacOS &
106         // playerCmd <> "dev/audio"
107         // Note : On linux and MacOS: aplay and afplay have a -r option
108         //    but it does not work
109         if getos()=="Windows" | rate <> 1 | grep(playerCmd,"/dev/audio")<>[]
110             y = wavread(y);
111         end
112         rate = rate * info(3);
113         duration = info(8) / rate   // [s]
114     end
115
116     // wav file
117     // ========
118     if type(y)==1 & y <> [] & grep(playerCmd,"/dev/audio")==[] then
119         File = pathconvert("TMPDIR/_playsnd_.wav", %f)
120         [fid, typ, names] = file();
121         tmp = find(names==File,1)
122         if tmp <> []
123             mclose(fid(tmp))
124         end
125         savewave(File, y, rate);
126         duration = size(y,2)/rate
127     elseif y<>[] & isdef("File","l")
128         info = wavread(File,"info");
129         duration = info(8)/rate
130     end
131
132     // Play
133     // ====
134     if getos() == "Windows" then
135         PlaySound("")
136         if y <> []
137             if nbiter==-1
138                 PlaySound(File) // Asynchronous
139             else
140                 realtimeinit(1)
141                 realtime(0)
142                 for i = 1:nbiter
143                     PlaySound(File);
144                     realtime(i*duration)
145                 end
146             end
147         end
148     else
149         // We should use a external C library here
150         if playerCmd <> "/dev/audio" then
151             player = strtok(playerCmd, " ")
152             options = strchr(playerCmd," ")
153             unix("killall -9 " + player + " 2> /dev/null")
154             //cmd = "%s --disable-resample -r %d %s ''%s'' > /dev/null 2>&1 &"
155             cmd = "%s %s ''%s'' > /dev/null 2>&1 &"
156             cmd = msprintf(cmd, player, options, File);
157             if y <> []
158                 msg = msprintf(_("%s: Failed to play the sound with command: %s.\n"), fname,  cmd)
159                 if nbiter==-1
160                     unix_g(cmd);
161                 else
162                     realtimeinit(1)
163                     realtime(0)
164                     for i = 1:nbiter
165                         unix_g(cmd);
166                         realtime(i*duration)
167                     end
168                 end
169             end
170         else
171             [fp, www] = mopen("/dev/audio","wb", 0);
172             if www < 0 then
173                 fp = -1;
174             end
175             if fp == -1 then
176                 warning(msprintf(_("%s: Audio capabilities not available.\n"), fname));
177             else
178                 y = lin2mu(y)
179                 // Here: Don't know how to interrupt a running audio stream
180                 if nbiter==-1
181                     mput(y,"uc",fp);
182                 else
183                     realtimeinit(1)
184                     realtime(0)
185                     for i = 1:nbiter
186                         mput(y,"uc",fp);
187                         realtime(i*duration)
188                     end
189                 end
190                 mclose(fp);
191             end
192         end
193     end
194
195     // Cleaning
196     // ========
197     sleep(100)
198     deletefile(TMPDIR+"/_playsnd_.wav")
199 endfunction