melder_audio.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487
  1. /* melder_audio.cpp
  2. *
  3. * Copyright (C) 1992-2017 Paul Boersma, David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #if defined (macintosh)
  19. #include <sys/time.h>
  20. #elif defined (_WIN32)
  21. #include <windows.h>
  22. #elif defined (linux)
  23. #include <sys/time.h>
  24. #include <signal.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/ioctl.h>
  28. #include <fcntl.h>
  29. #include <unistd.h>
  30. #if defined HAVE_PULSEAUDIO
  31. #include <pulse/pulseaudio.h>
  32. #endif
  33. #if ! defined (NO_AUDIO)
  34. #if defined (__OpenBSD__) || defined (__NetBSD__)
  35. #include <soundcard.h>
  36. #else
  37. #include <sys/soundcard.h>
  38. #endif
  39. #endif
  40. #include <errno.h>
  41. #endif
  42. #include "melder.h"
  43. #include <time.h>
  44. #include "../sys/Gui.h"
  45. #include "../sys/Preferences.h"
  46. #include "../external/portaudio/portaudio.h"
  47. #ifdef HAVE_PULSEAUDIO
  48. void pulseAudio_initialize ();
  49. void pulseAudio_cleanup ();
  50. void pulseAudio_serverReport ();
  51. void stream_state_cb (pa_stream *stream, void *userdata);
  52. void stream_drain_complete_cb (pa_stream *stream, int success, void *userdata);
  53. void context_state_cb (pa_context *context, void *userdata);
  54. void context_drain_complete_cb (pa_context *context, void *userdata);
  55. void prepare_and_play (struct MelderPlay *me);
  56. void stream_write_cb (pa_stream *stream, size_t length, void *userdata);
  57. void stream_write_cb2 (pa_stream *stream, size_t length, void *userdata);
  58. void pulseAudio_server_info_cb (pa_context *context, const pa_server_info *info, void *userdata);
  59. #endif
  60. bool Melder_asynchronous;
  61. static struct {
  62. enum kMelder_asynchronicityLevel maximumAsynchronicity;
  63. enum kMelder_inputSoundSystem inputSoundSystem;
  64. enum kMelder_outputSoundSystem outputSoundSystem;
  65. bool useInternalSpeaker;
  66. double silenceBefore, silenceAfter;
  67. } preferences;
  68. void Melder_audio_prefs () {
  69. Preferences_addEnum (U"Audio.maximumAsynchronicity", & preferences. maximumAsynchronicity, kMelder_asynchronicityLevel, kMelder_asynchronicityLevel::DEFAULT);
  70. Preferences_addEnum (U"Audio.inputSoundSystem", & preferences. inputSoundSystem, kMelder_inputSoundSystem, kMelder_inputSoundSystem::DEFAULT);
  71. Preferences_addEnum (U"Audio.outputSoundSystem", & preferences. outputSoundSystem, kMelder_outputSoundSystem, kMelder_outputSoundSystem::DEFAULT);
  72. Preferences_addBool (U"Audio.useInternalSpeaker", & preferences. useInternalSpeaker, true);
  73. Preferences_addDouble (U"Audio.silenceBefore2", & preferences. silenceBefore, kMelderAudio_outputSilenceBefore_DEFAULT);
  74. Preferences_addDouble (U"Audio.silenceAfter2", & preferences. silenceAfter, kMelderAudio_outputSilenceAfter_DEFAULT);
  75. }
  76. void MelderAudio_setOutputMaximumAsynchronicity (enum kMelder_asynchronicityLevel maximumAsynchronicity) {
  77. //MelderAudio_stopPlaying (MelderAudio_IMPLICIT); // BUG
  78. preferences. maximumAsynchronicity = maximumAsynchronicity;
  79. }
  80. enum kMelder_asynchronicityLevel MelderAudio_getOutputMaximumAsynchronicity () {
  81. return preferences. maximumAsynchronicity;
  82. }
  83. void MelderAudio_setInputSoundSystem (enum kMelder_inputSoundSystem inputSoundSystem) {
  84. preferences. inputSoundSystem = inputSoundSystem;
  85. }
  86. enum kMelder_inputSoundSystem MelderAudio_getInputSoundSystem () {
  87. return preferences. inputSoundSystem;
  88. }
  89. void MelderAudio_setOutputSoundSystem (enum kMelder_outputSoundSystem outputSoundSystem) {
  90. MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
  91. preferences. outputSoundSystem = outputSoundSystem;
  92. }
  93. enum kMelder_outputSoundSystem MelderAudio_getOutputSoundSystem () {
  94. return preferences. outputSoundSystem;
  95. }
  96. void MelderAudio_setUseInternalSpeaker (bool useInternalSpeaker) {
  97. MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
  98. preferences. useInternalSpeaker = useInternalSpeaker;
  99. }
  100. bool MelderAudio_getUseInternalSpeaker () { return preferences. useInternalSpeaker; }
  101. void MelderAudio_setOutputSilenceBefore (double silenceBefore) {
  102. MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
  103. preferences. silenceBefore = silenceBefore;
  104. }
  105. double MelderAudio_getOutputSilenceBefore () { return preferences. silenceBefore; }
  106. void MelderAudio_setOutputSilenceAfter (double silenceAfter) {
  107. MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
  108. preferences. silenceAfter = silenceAfter;
  109. }
  110. double MelderAudio_getOutputSilenceAfter () { return preferences. silenceAfter; }
  111. integer MelderAudio_getOutputBestSampleRate (integer fsamp) {
  112. #if defined (macintosh)
  113. return fsamp == 44100 || fsamp == 96000 ? fsamp : 44100;
  114. #elif defined (_WIN32)
  115. return fsamp == 8000 || fsamp == 11025 || fsamp == 16000 || fsamp == 22050 ||
  116. fsamp == 32000 || fsamp == 44100 || fsamp == 48000 || fsamp == 96000 ? fsamp : 44100;
  117. #elif defined (linux)
  118. return fsamp == 44100 || fsamp == 48000 || fsamp == 96000 ? fsamp : 44100;
  119. #else
  120. return 44100;
  121. #endif
  122. }
  123. bool MelderAudio_isPlaying;
  124. static double theStartingTime = 0.0;
  125. #define PA_GETTINGINFO 1
  126. #define PA_GETTINGINFO_DONE 2
  127. #define PA_WRITING 4
  128. #define PA_WRITING_DONE 8
  129. #define PA_RECORDING 16
  130. #define PA_RECORDING_DONE 32
  131. #define PA_QUERY_NUMBEROFCHANNELS 64
  132. #define PA_QUERY_NUMBEROFCHANNELS_DONE 128
  133. #ifdef HAVE_PULSEAUDIO
  134. typedef struct pulseAudio {
  135. pa_sample_spec sample_spec;
  136. pa_threaded_mainloop *mainloop = nullptr;
  137. pa_mainloop_api *mainloop_api = nullptr;
  138. pa_context *context = nullptr;
  139. pa_stream *stream = nullptr;
  140. pa_operation *operation_drain = nullptr;
  141. pa_operation *operation_info = nullptr;
  142. pa_stream_flags_t stream_flags;
  143. const pa_timing_info *timing_info = nullptr;
  144. struct timeval startTime = {0, 0};
  145. pa_usec_t timer_event_usec = 50000; // 50 ms
  146. pa_time_event *timer_event = nullptr;
  147. const pa_channel_map *channel_map = nullptr;
  148. pa_usec_t r_usec;
  149. pa_buffer_attr buffer_attr;
  150. uint32 latency = 0; // in bytes of buffer
  151. int32 latency_msec = 20;
  152. bool pulseAudioInitialized = false;
  153. unsigned int occupation = PA_WRITING;
  154. } pulseAudioStruct;
  155. #endif
  156. static struct MelderPlay {
  157. int16 *buffer;
  158. integer sampleRate, numberOfSamples, samplesLeft, samplesSent, samplesPlayed;
  159. kMelder_asynchronicityLevel asynchronicity;
  160. int numberOfChannels;
  161. bool explicitStop, fakeMono;
  162. volatile int volatile_interrupted;
  163. bool (*callback) (void *closure, integer samplesPlayed);
  164. void *closure;
  165. #if gtk
  166. gint workProcId_gtk = 0;
  167. #elif motif
  168. XtWorkProcId workProcId_motif;
  169. #elif cocoa
  170. CFRunLoopTimerRef cocoaTimer;
  171. #endif
  172. bool usePortAudio, supports_paComplete, usePulseAudio;
  173. PaStream *stream;
  174. double paStartingTime;
  175. #if defined (macintosh)
  176. #elif defined (linux)
  177. int audio_fd, val, err;
  178. #elif defined (_WIN32)
  179. HWAVEOUT hWaveOut;
  180. WAVEHDR waveHeader;
  181. MMRESULT status;
  182. #endif
  183. #ifdef HAVE_PULSEAUDIO
  184. pulseAudioStruct pulseAudio;
  185. #endif
  186. } thePlay;
  187. integer MelderAudio_getSamplesPlayed () {
  188. return thePlay. samplesPlayed;
  189. }
  190. bool MelderAudio_stopWasExplicit () {
  191. return thePlay. explicitStop;
  192. }
  193. /*
  194. * The flush () procedure will always have to be invoked after normal play, i.e. in the following cases:
  195. * 1. After synchronous play (asynchronicity = 0, 1, or 2).
  196. * 2. After interruption of asynchronicity 2 by the ESCAPE key.
  197. * 3. After asynchronous play, by the workProc.
  198. * 4. After interruption of asynchronicity 3 by MelderAudio_stopPlaying ().
  199. */
  200. static bool flush () {
  201. struct MelderPlay *me = & thePlay;
  202. if (my usePortAudio) {
  203. if (my stream) {
  204. #ifdef linux
  205. Pa_Sleep (200); // this reduces the chance of seeing the Alsa/PulseAudio deadlock:
  206. /*
  207. (gdb) thread apply all bt
  208. Thread 13 (Thread 0x7fffde1d2700 (LWP 25620)):
  209. #0 0x00007ffff65a3d67 in pthread_cond_wait@@GLIBC_2.3.2 ()
  210. from /lib/x86_64-linux-gnu/libpthread.so.0
  211. #1 0x00007fffec0b3980 in pa_threaded_mainloop_wait () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
  212. #2 0x00007fffde407054 in pulse_wait_operation ()
  213. from /usr/lib/x86_64-linux-gnu/alsa-lib/libasound_module_pcm_pulse.so
  214. #3 0x00007fffde405c10 in ?? ()
  215. from /usr/lib/x86_64-linux-gnu/alsa-lib/libasound_module_pcm_pulse.so
  216. #4 0x00007ffff6843708 in alsa_snd_pcm_drop () from /usr/lib/x86_64-linux-gnu/libasound.so.2
  217. #5 0x0000000000812de0 in AlsaStop ()
  218. #6 0x00000000008183e1 in OnExit ()
  219. #7 0x0000000000818483 in CallbackThreadFunc ()
  220. #8 0x00007ffff659fe9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
  221. #9 0x00007ffff5aba3fd in clone () from /lib/x86_64-linux-gnu/libc.so.6
  222. #10 0x0000000000000000 in ?? ()
  223. Thread 12 (Thread 0x7fffdffff700 (LWP 25619)):
  224. #0 0x00007ffff659d9b0 in __pthread_mutex_lock_full () from /lib/x86_64-linux-gnu/libpthread.so.0
  225. #1 0x00007fffdf3d7e1e in pa_mutex_lock () from /usr/lib/x86_64-linux-gnu/libpulsecommon-1.1.so
  226. #2 0x00007fffec0b3369 in ?? () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
  227. #3 0x00007fffec0a476c in pa_mainloop_poll () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
  228. #4 0x00007fffec0a4dd9 in pa_mainloop_iterate () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
  229. #5 0x00007fffec0a4e90 in pa_mainloop_run () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
  230. #6 0x00007fffec0b330f in ?? () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
  231. #7 0x00007fffdf3d8d18 in ?? () from /usr/lib/x86_64-linux-gnu/libpulsecommon-1.1.so
  232. #8 0x00007ffff659fe9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
  233. #9 0x00007ffff5aba3fd in clone () from /lib/x86_64-linux-gnu/libc.so.6
  234. #10 0x0000000000000000 in ?? ()
  235. Thread 3 (Thread 0x7fffefd8b700 (LWP 25610)):
  236. #0 0x00007ffff5aaea43 in poll () from /lib/x86_64-linux-gnu/libc.so.6
  237. #1 0x00007ffff6ae9ff6 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  238. #2 0x00007ffff6aea45a in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  239. #3 0x00007ffff4bb75e6 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
  240. #4 0x00007ffff6b0b9b5 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  241. #5 0x00007ffff659fe9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
  242. ---Type <return> to continue, or q <return> to quit---
  243. #6 0x00007ffff5aba3fd in clone () from /lib/x86_64-linux-gnu/libc.so.6
  244. #7 0x0000000000000000 in ?? ()
  245. Thread 2 (Thread 0x7ffff058c700 (LWP 25609)):
  246. #0 0x00007ffff5aaea43 in poll () from /lib/x86_64-linux-gnu/libc.so.6
  247. #1 0x00007ffff6ae9ff6 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  248. #2 0x00007ffff6aea45a in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  249. #3 0x00007ffff059698b in ?? () from /usr/lib/x86_64-linux-gnu/gio/modules/libdconfsettings.so
  250. #4 0x00007ffff6b0b9b5 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  251. #5 0x00007ffff659fe9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
  252. #6 0x00007ffff5aba3fd in clone () from /lib/x86_64-linux-gnu/libc.so.6
  253. #7 0x0000000000000000 in ?? ()
  254. Thread 1 (Thread 0x7ffff7fce940 (LWP 25608)):
  255. #0 0x00007ffff65a1148 in pthread_join () from /lib/x86_64-linux-gnu/libpthread.so.0
  256. #1 0x000000000081073e in PaUnixThread_Terminate ()
  257. #2 0x0000000000818239 in RealStop ()
  258. #3 0x00000000008182c7 in AbortStream ()
  259. #4 0x0000000000811ce5 in Pa_CloseStream ()
  260. #5 0x0000000000753a6d in flush ()
  261. #6 0x0000000000753dae in MelderAudio_stopPlaying ()
  262. #7 0x00000000004d80e1 in Sound_playPart ()
  263. #8 0x00000000004f7b48 in structSoundEditor::v_play ()
  264. #9 0x00000000004e7197 in gui_drawingarea_cb_click ()
  265. #10 0x00000000007d0d35 in _GuiGtkDrawingArea_clickCallback ()
  266. #11 0x00007ffff78d6e78 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
  267. #12 0x00007ffff6da6ca2 in g_closure_invoke () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
  268. #13 0x00007ffff6db7d71 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
  269. #14 0x00007ffff6dbfd4e in g_signal_emit_valist ()
  270. from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
  271. #15 0x00007ffff6dc0212 in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
  272. #16 0x00007ffff79f1231 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
  273. #17 0x00007ffff78d5003 in gtk_propagate_event () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
  274. #18 0x00007ffff78d5363 in gtk_main_do_event () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
  275. #19 0x00007ffff7549cac in ?? () from /usr/lib/x86_64-linux-gnu/libgdk-x11-2.0.so.0
  276. #20 0x00007ffff6ae9d13 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  277. #21 0x00007ffff6aea060 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  278. ---Type <return> to continue, or q <return> to quit---
  279. #22 0x00007ffff6aea45a in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
  280. #23 0x00007ffff78d4397 in gtk_main () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
  281. #24 0x00000000007909eb in praat_run ()
  282. #25 0x000000000040e009 in main ()
  283. Also see http://sourceforge.net/p/audacity/mailman/audacity-devel/thread/200912181409.49839.businessmanprogrammersteve@gmail.com/
  284. */
  285. #endif
  286. Pa_CloseStream (my stream);
  287. my stream = nullptr;
  288. }
  289. #ifdef HAVE_PULSEAUDIO
  290. } else if (my usePulseAudio) {
  291. if (my pulseAudio.mainloop) {
  292. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  293. if (my pulseAudio.stream) {
  294. pa_operation *operation = pa_stream_flush (my pulseAudio.stream, stream_drain_complete_cb, me);
  295. // wait because of a threaded_mainloop
  296. if (operation) {
  297. while (MelderAudio_isPlaying) {
  298. pa_threaded_mainloop_wait (my pulseAudio.mainloop);
  299. trace (U"wait");
  300. }
  301. pa_operation_unref (operation);
  302. }
  303. }
  304. MelderAudio_isPlaying = false;
  305. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  306. pulseAudio_cleanup ();
  307. }
  308. #endif
  309. } else {
  310. #if defined (macintosh)
  311. #elif defined (linux) && ! defined (NO_AUDIO)
  312. /*
  313. * As on Sun.
  314. */
  315. if (my audio_fd) {
  316. ioctl (my audio_fd, SNDCTL_DSP_RESET, (my val = 0, & my val));
  317. close (my audio_fd), my audio_fd = 0;
  318. }
  319. #elif defined (_WIN32)
  320. /*
  321. * FIX: Do not reset the sound card if played to the end:
  322. * the last 20 milliseconds may be truncated!
  323. * This used to happen on Barbertje's Dell PC, not with SoundBlaster.
  324. */
  325. if (my samplesPlayed != my numberOfSamples || Melder_debug == 2)
  326. waveOutReset (my hWaveOut);
  327. my status = waveOutUnprepareHeader (my hWaveOut, & my waveHeader, sizeof (WAVEHDR));
  328. if (/* Melder_debug == 3 && */ my status == WAVERR_STILLPLAYING) {
  329. waveOutReset (my hWaveOut);
  330. waveOutUnprepareHeader (my hWaveOut, & my waveHeader, sizeof (WAVEHDR));
  331. }
  332. waveOutClose (my hWaveOut), my hWaveOut = 0;
  333. #endif
  334. }
  335. if (my fakeMono) {
  336. NUMvector_free ((short *) my buffer, 0);
  337. my buffer = nullptr;
  338. }
  339. MelderAudio_isPlaying = false;
  340. if (my samplesPlayed >= my numberOfSamples)
  341. my samplesPlayed = my numberOfSamples;
  342. if (my samplesPlayed <= 0)
  343. my samplesPlayed = 1;
  344. /*
  345. * Call the callback for the last time, which is recognizable by the value of MelderAudio_isPlaying.
  346. * In this way, the caller of Melder_play16 can be notified.
  347. * The caller can examine the actual number of samples played by testing MelderAudio_getSamplesPlayed ().
  348. */
  349. if (my callback)
  350. my callback (my closure, my samplesPlayed);
  351. my callback = 0;
  352. my closure = 0;
  353. return true; /* Remove workProc if called from workProc. */
  354. }
  355. bool MelderAudio_stopPlaying (bool explicitStop) {
  356. //Melder_casual (U"stop playing!");
  357. struct MelderPlay *me = & thePlay;
  358. my explicitStop = explicitStop;
  359. trace (U"playing = ", MelderAudio_isPlaying);
  360. if (! MelderAudio_isPlaying || my asynchronicity < kMelder_asynchronicityLevel::ASYNCHRONOUS) return false;
  361. #if gtk
  362. if (thePlay.workProcId_gtk && ! my usePulseAudio) {
  363. g_source_remove (thePlay.workProcId_gtk);
  364. }
  365. thePlay.workProcId_gtk = 0;
  366. #elif motif
  367. XtRemoveWorkProc (thePlay. workProcId_motif);
  368. #elif cocoa
  369. CFRunLoopRemoveTimer (CFRunLoopGetCurrent (), thePlay. cocoaTimer, kCFRunLoopCommonModes);
  370. #endif
  371. (void) flush ();
  372. return true;
  373. }
  374. static bool workProc (void *closure) {
  375. struct MelderPlay *me = & thePlay;
  376. //static integer n = 0;
  377. //n ++;
  378. //Melder_casual (U"workProc ", n);
  379. if (my usePortAudio) {
  380. #if defined (linux)
  381. double timeElapsed = Melder_clock () - theStartingTime - Pa_GetStreamInfo (my stream) -> outputLatency;
  382. integer samplesPlayed = timeElapsed * my sampleRate;
  383. if (my callback && ! my callback (my closure, samplesPlayed)) {
  384. my volatile_interrupted = 1;
  385. return flush ();
  386. }
  387. if (my samplesLeft == 0) {
  388. return flush ();
  389. }
  390. #elif defined (linuxXXX)
  391. /*
  392. * Not all hostApis support paComplete or wait till all buffers have been played in Pa_StopStream.
  393. * Once pa_win_ds implements this, we can simply do:
  394. */
  395. if (Pa_IsStreamActive (my stream)) {
  396. if (my callback && ! my callback (my closure, my samplesPlayed))
  397. return flush ();
  398. } else {
  399. Pa_StopStream (my stream);
  400. my samplesPlayed = my numberOfSamples;
  401. return flush ();
  402. }
  403. /*
  404. * But then we also have to use paComplete in the stream callback.
  405. */
  406. #else
  407. double timeElapsed = Melder_clock () - theStartingTime - Pa_GetStreamInfo (my stream) -> outputLatency;
  408. my samplesPlayed = (integer) floor (timeElapsed * my sampleRate);
  409. if (my supports_paComplete && Pa_IsStreamActive (my stream)) {
  410. if (my callback && ! my callback (my closure, my samplesPlayed)) {
  411. Pa_AbortStream (my stream);
  412. return flush ();
  413. }
  414. } else if (my samplesPlayed < my numberOfSamples + my sampleRate / 20) { // allow the latency estimate to be 50 ms off.
  415. if (my callback && ! my callback (my closure, my samplesPlayed)) {
  416. Pa_AbortStream (my stream);
  417. return flush ();
  418. }
  419. } else {
  420. Pa_AbortStream (my stream);
  421. my samplesPlayed = my numberOfSamples;
  422. return flush ();
  423. }
  424. Pa_Sleep (10);
  425. #endif
  426. #ifdef HAVE_PULSEAUDIO
  427. } else if (my usePulseAudio) {
  428. if (my pulseAudio.mainloop) {
  429. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  430. integer samplesPlayed = 0;
  431. pa_usec_t diff_usec = 0;
  432. if (my pulseAudio.startTime.tv_usec != 0) {
  433. diff_usec = pa_timeval_age (& my pulseAudio.startTime);
  434. double timeElapsed = diff_usec / 1000000.0;
  435. samplesPlayed = timeElapsed * my sampleRate;
  436. }
  437. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  438. trace (U"diff = ", diff_usec, U", samples played = ", samplesPlayed);
  439. if (my callback && ! my callback (my closure, samplesPlayed)) {
  440. my volatile_interrupted = 1;
  441. return flush ();
  442. } else if (my samplesLeft == 0 || samplesPlayed > my numberOfSamples) {
  443. return flush ();
  444. }
  445. }
  446. #endif
  447. } else {
  448. #if defined (macintosh)
  449. #elif defined (linux) && ! defined (NO_AUDIO)
  450. if (my samplesLeft > 0) {
  451. int dsamples = my samplesLeft > 500 ? 500 : my samplesLeft;
  452. write (my audio_fd, (char *) & my buffer [my samplesSent * my numberOfChannels], 2 * dsamples * my numberOfChannels);
  453. my samplesLeft -= dsamples;
  454. my samplesSent += dsamples;
  455. my samplesPlayed = (Melder_clock () - theStartingTime) * my sampleRate;
  456. if (my callback && ! my callback (my closure, my samplesPlayed))
  457. return flush ();
  458. } else /*if (my samplesPlayed >= my numberOfSamples)*/ {
  459. close (my audio_fd), my audio_fd = 0;
  460. my samplesPlayed = my numberOfSamples;
  461. return flush ();
  462. /*} else {
  463. my samplesPlayed = (Melder_clock () - theStartingTime) * my sampleRate;
  464. if (my callback && ! my callback (my closure, my samplesPlayed))
  465. return flush ();*/
  466. }
  467. #elif defined (_WIN32)
  468. if (my waveHeader. dwFlags & WHDR_DONE) {
  469. my samplesPlayed = my numberOfSamples;
  470. return flush ();
  471. } else {
  472. static integer previousTime = 0;
  473. uinteger currentTime = clock ();
  474. if (Melder_debug == 1) {
  475. my samplesPlayed = (Melder_clock () - theStartingTime) * my sampleRate;
  476. } else {
  477. MMTIME mmtime;
  478. mmtime. wType = TIME_BYTES;
  479. waveOutGetPosition (my hWaveOut, & mmtime, sizeof (MMTIME));
  480. my samplesPlayed = mmtime. u.cb / (2 * my numberOfChannels);
  481. }
  482. if (/* Melder_debug != 4 || */ currentTime - previousTime > CLOCKS_PER_SEC / 100) {
  483. previousTime = currentTime;
  484. if (my callback && ! my callback (my closure, my samplesPlayed))
  485. return flush ();
  486. }
  487. Sleep (10);
  488. }
  489. #endif
  490. }
  491. (void) closure;
  492. return false;
  493. }
  494. #if gtk
  495. static gint workProc_gtk (gpointer closure) {
  496. return ! workProc ((void *) closure);
  497. }
  498. #elif motif
  499. static bool workProc_motif (XtPointer closure) {
  500. return workProc ((void *) closure);
  501. }
  502. #elif cocoa
  503. static void workProc_cocoa (CFRunLoopTimerRef timer, void *closure) {
  504. bool result = workProc (closure);
  505. if (result) {
  506. CFRunLoopTimerInvalidate (timer);
  507. //CFRunLoopRemoveTimer (CFRunLoopGetCurrent (), timer);
  508. }
  509. }
  510. #endif
  511. static int thePaStreamCallback (const void *input, void *output,
  512. unsigned long frameCount,
  513. const PaStreamCallbackTimeInfo* timeInfo,
  514. PaStreamCallbackFlags statusFlags,
  515. void *userData)
  516. {
  517. (void) input;
  518. (void) timeInfo;
  519. (void) userData;
  520. struct MelderPlay *me = & thePlay;
  521. if (my volatile_interrupted) {
  522. memset (output, '\0', 2 * frameCount * my numberOfChannels);
  523. my samplesPlayed = my numberOfSamples;
  524. return my supports_paComplete ? paComplete : paContinue;
  525. }
  526. if (statusFlags & paOutputUnderflow) {
  527. if (Melder_debug == 20) Melder_casual (U"output underflow");
  528. }
  529. if (statusFlags & paOutputOverflow) {
  530. if (Melder_debug == 20) Melder_casual (U"output overflow");
  531. }
  532. if (my samplesLeft > 0) {
  533. integer dsamples = my samplesLeft > (integer) frameCount ? (integer) frameCount : my samplesLeft;
  534. if (Melder_debug == 20) Melder_casual (U"play ", dsamples, U" ", Pa_GetStreamCpuLoad (my stream));
  535. memset (output, '\0', 2 * frameCount * my numberOfChannels);
  536. Melder_assert (my buffer);
  537. memcpy (output, (char *) & my buffer [my samplesSent * my numberOfChannels], 2 * dsamples * my numberOfChannels);
  538. my samplesLeft -= dsamples;
  539. my samplesSent += dsamples;
  540. my samplesPlayed = my samplesSent;
  541. } else /*if (my samplesPlayed >= my numberOfSamples)*/ {
  542. memset (output, '\0', 2 * frameCount * my numberOfChannels);
  543. my samplesPlayed = my numberOfSamples;
  544. trace (U"paComplete");
  545. return my supports_paComplete ? paComplete : paContinue;
  546. }
  547. return paContinue;
  548. }
  549. #ifdef HAVE_PULSEAUDIO
  550. void pulseAudio_initialize () {
  551. struct MelderPlay *me = & thePlay;
  552. if (! my pulseAudio.pulseAudioInitialized) {
  553. my pulseAudio.mainloop = pa_threaded_mainloop_new ();
  554. if (! my pulseAudio.mainloop) {
  555. MelderAudio_isPlaying = false;
  556. Melder_throw (U"No connection to pulse audio server.");
  557. }
  558. pa_threaded_mainloop_start (my pulseAudio.mainloop);
  559. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  560. my pulseAudio.mainloop_api = pa_threaded_mainloop_get_api (my pulseAudio.mainloop);
  561. my pulseAudio.context = pa_context_new (my pulseAudio.mainloop_api, "praat");
  562. pa_context_set_state_callback (my pulseAudio.context, context_state_cb, me);
  563. pa_context_connect (my pulseAudio.context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
  564. trace (U"threading");
  565. my pulseAudio.pulseAudioInitialized = true;
  566. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  567. }
  568. }
  569. void pulseAudio_cleanup () {
  570. struct MelderPlay *me = & thePlay;
  571. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  572. trace (U"mainloop to be freed, occupation was ", my pulseAudio.occupation);
  573. if (my pulseAudio.context) {
  574. trace (U"still context");
  575. pa_context_unref (my pulseAudio.context);
  576. my pulseAudio.context = nullptr;
  577. }
  578. if (my pulseAudio.timer_event) {
  579. my pulseAudio.mainloop_api -> time_free (my pulseAudio.timer_event);
  580. my pulseAudio.timer_event = nullptr;
  581. }
  582. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  583. pa_threaded_mainloop_free (my pulseAudio.mainloop); // automatically frees the mainloop_api too!
  584. my pulseAudio.mainloop = nullptr;
  585. my pulseAudio.mainloop_api = nullptr;
  586. my pulseAudio.r_usec = 0;
  587. MelderAudio_isPlaying = false;
  588. my pulseAudio.occupation = 0;
  589. my pulseAudio.startTime = {0, 0};
  590. my pulseAudio.pulseAudioInitialized = false;
  591. }
  592. void pulseAudio_server_info_cb (pa_context *context, const pa_server_info *info, void *userdata) {
  593. struct MelderPlay *me = (struct MelderPlay *) userdata;
  594. if (! info) {
  595. return;
  596. }
  597. const pa_sample_spec *sp = & (info -> sample_spec);
  598. my numberOfChannels = sp -> channels;
  599. Melder_assert (context == my pulseAudio.context);
  600. if ((my pulseAudio.occupation & PA_QUERY_NUMBEROFCHANNELS) != PA_QUERY_NUMBEROFCHANNELS) {
  601. MelderInfo_open ();
  602. MelderInfo_writeLine (U"PulseAudio Server characteristics:");
  603. MelderInfo_writeLine (U"User name: ", Melder_peek8to32 (info -> user_name));
  604. MelderInfo_writeLine (U"Host name: ", Melder_peek8to32 (info -> host_name));
  605. MelderInfo_writeLine (U"Server version: ", Melder_peek8to32 (info -> server_version));
  606. MelderInfo_writeLine (U"Server name: ", Melder_peek8to32 (info -> server_name));
  607. MelderInfo_writeLine (U"Sample specification: ");
  608. MelderInfo_writeLine (U"\tNumber of channels: ", my numberOfChannels);
  609. MelderInfo_writeLine (U"\tSampling frequency: ", sp -> rate);
  610. const char *sample_format_string = pa_sample_format_to_string (sp -> format);
  611. MelderInfo_writeLine (U"\tSample format: ", Melder_peek8to32 (sample_format_string));
  612. MelderInfo_writeLine (U"Default sink name: ", Melder_peek8to32 (info -> default_sink_name));
  613. MelderInfo_writeLine (U"Default source name: ", Melder_peek8to32 (info -> default_source_name));
  614. const pa_channel_map *cm = &(info -> channel_map);
  615. MelderInfo_writeLine (U"Channel specification: ");
  616. for (integer channel = 1; channel <= cm -> channels; channel++) {
  617. const char *channel_text = pa_channel_position_to_pretty_string (cm -> map[channel - 1]); // 0-..
  618. MelderInfo_writeLine (U"\t Channel ", channel, U": ", Melder_peek8to32 (channel_text));
  619. }
  620. MelderInfo_close ();
  621. }
  622. trace (U"before signal");
  623. my pulseAudio.occupation |= PA_GETTINGINFO_DONE;
  624. // We are done, signal it to pulseAudio_serverReport
  625. pa_threaded_mainloop_signal (my pulseAudio.mainloop, 0);
  626. }
  627. void pulseAudio_serverReport () {
  628. // TODO: initiaize context
  629. struct MelderPlay *me = & thePlay;
  630. if (my pulseAudio.mainloop) {
  631. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  632. my pulseAudio.occupation |= PA_GETTINGINFO;
  633. if (my pulseAudio.context) {
  634. pa_operation *operation = pa_context_get_server_info (my pulseAudio.context, pulseAudio_server_info_cb, me);
  635. trace (U"operation started");
  636. if (! operation) {
  637. Melder_throw (U"pulseAudioServer report: ", Melder_peek8to32 (pa_strerror (pa_context_errno (my pulseAudio.context))));
  638. }
  639. while ((my pulseAudio.occupation & PA_GETTINGINFO_DONE) != PA_GETTINGINFO_DONE) {
  640. pa_threaded_mainloop_wait (my pulseAudio.mainloop);
  641. }
  642. // Now it is save to unref because the server info operation has completed
  643. pa_operation_unref (operation);
  644. my pulseAudio.occupation &= ~ PA_GETTINGINFO_DONE;
  645. }
  646. my pulseAudio.occupation &= ~ PA_GETTINGINFO;
  647. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  648. } else {
  649. my pulseAudio.occupation |= PA_GETTINGINFO;
  650. pulseAudio_initialize ();
  651. /*
  652. * First acquire a lock because the operation to get server info (in context_state_cb) may not have started yet.
  653. * We therefore use our own signaling and wait until information has been acquired.
  654. */
  655. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  656. while ((my pulseAudio.occupation & PA_GETTINGINFO_DONE) != PA_GETTINGINFO_DONE) {
  657. pa_threaded_mainloop_wait (my pulseAudio.mainloop);
  658. }
  659. // Now we know that the operation to get server info has succeeded!
  660. pa_operation_unref (my pulseAudio.operation_info);
  661. my pulseAudio.operation_info = nullptr;
  662. my pulseAudio.occupation &= ~ PA_GETTINGINFO;
  663. my pulseAudio.occupation &= ~ PA_GETTINGINFO_DONE;
  664. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  665. if (! MelderAudio_isPlaying) {
  666. my pulseAudio.occupation = 0;
  667. trace (U"before cleanup");
  668. pulseAudio_cleanup ();
  669. }
  670. }
  671. }
  672. void context_drain_complete_cb (pa_context *context, void *userdata) {
  673. struct MelderPlay *me = (struct MelderPlay *) userdata;
  674. Melder_assert (context == my pulseAudio.context);
  675. if (context) {
  676. trace (U"context exists");
  677. pa_context_disconnect (my pulseAudio.context);
  678. pa_context_unref (my pulseAudio.context);
  679. my pulseAudio.context = nullptr;
  680. }
  681. trace (U"after context test");
  682. pulseAudio_cleanup ();
  683. }
  684. void stream_drain_complete_cb (pa_stream *stream, int success, void *userdata) {
  685. (void) stream;
  686. struct MelderPlay *me = (struct MelderPlay *) userdata;
  687. // Melder_assert (stream == my pulseAudio.stream); // not always true
  688. trace (U"succes = ", success);
  689. if (stream == my pulseAudio.stream) {
  690. trace (U"stream exists");
  691. pa_stream_disconnect (my pulseAudio.stream);
  692. pa_stream_unref (my pulseAudio.stream);
  693. my pulseAudio.stream = nullptr;
  694. my pulseAudio.occupation &= ~ PA_WRITING;
  695. my pulseAudio.occupation |= PA_WRITING_DONE;
  696. MelderAudio_isPlaying = false;
  697. if (my pulseAudio.timer_event) {
  698. my pulseAudio.mainloop_api -> time_free (my pulseAudio.timer_event);
  699. my pulseAudio.timer_event = nullptr;
  700. }
  701. pa_threaded_mainloop_signal (my pulseAudio.mainloop, 0);
  702. } else {
  703. trace (U"??");
  704. }
  705. }
  706. static void free_cb(void * /* p */) { // to prevent copying of data
  707. }
  708. // asynchronous version
  709. void stream_write_cb2 (pa_stream *stream, size_t length, void *userdata) {
  710. struct MelderPlay *me = (struct MelderPlay *) userdata;
  711. if (stream == my pulseAudio.stream) {
  712. //length = my pulseAudio.latency; // overrule length given by server
  713. integer writeSize_samples = length / (2 * my numberOfChannels);
  714. my samplesLeft = my numberOfSamples - my samplesSent;
  715. trace (U"length = ", length, U" left = ", my samplesLeft);
  716. MelderAudio_isPlaying = true;
  717. if (my samplesLeft == my numberOfSamples) {
  718. pa_gettimeofday (& my pulseAudio.startTime);
  719. }
  720. if (my samplesLeft > 0) {
  721. if (my volatile_interrupted) {
  722. my samplesPlayed = my numberOfSamples;
  723. my samplesLeft = 0;
  724. flush ();
  725. } else {
  726. writeSize_samples = my samplesLeft < writeSize_samples ? my samplesLeft : writeSize_samples;
  727. if (pa_stream_write (stream, my buffer + my samplesSent * my numberOfChannels, 2 * writeSize_samples * my numberOfChannels, free_cb, 0, PA_SEEK_RELATIVE) < 0) {
  728. Melder_throw (U"pa_stream_write() failed: ", Melder_peek8to32 (pa_strerror (pa_context_errno (my pulseAudio.context))));
  729. }
  730. integer samplesSent = writeSize_samples;
  731. my samplesSent += samplesSent;
  732. my samplesPlayed = my samplesSent; // not true: use timer info
  733. trace (U"written ", samplesSent, U" (samples), total ", my samplesSent);
  734. if (my samplesSent == my numberOfSamples) {
  735. // my samplesLeft = 0; not here because still playing
  736. trace (U"nothing left 1");
  737. //pa_stream_set_write_callback(my pulseAudio.stream, nullptr, nullptr);
  738. my pulseAudio.operation_drain = pa_stream_drain (my pulseAudio.stream, stream_drain_complete_cb, me);
  739. if (! my pulseAudio.operation_drain) {
  740. pa_stream_disconnect (my pulseAudio.stream);
  741. pa_stream_unref (my pulseAudio.stream);
  742. my pulseAudio.stream = nullptr;
  743. trace (U"stream exists");
  744. my pulseAudio.occupation &= ~ PA_WRITING;
  745. my pulseAudio.occupation |= PA_WRITING_DONE;
  746. pa_threaded_mainloop_signal (my pulseAudio.mainloop, 0);
  747. if (my pulseAudio.timer_event) {
  748. my pulseAudio.mainloop_api -> time_free (my pulseAudio.timer_event);
  749. my pulseAudio.timer_event = nullptr;
  750. }
  751. }
  752. }
  753. }
  754. } else {
  755. trace (U"nothing left");
  756. }
  757. } else {
  758. trace (U"stream?");
  759. }
  760. }
  761. void stream_write_cb (pa_stream *stream, size_t length, void *userdata) {
  762. struct MelderPlay *me = (struct MelderPlay *) userdata;
  763. if (stream == my pulseAudio.stream) {
  764. my samplesLeft = my numberOfSamples - my samplesSent;
  765. trace (U"length = ", length, U", left = ", my samplesLeft);
  766. if (my samplesLeft > 0) {
  767. if (my samplesLeft == my numberOfSamples) {
  768. pa_gettimeofday (& my pulseAudio.startTime);
  769. }
  770. if (my volatile_interrupted) {
  771. my samplesPlayed = my numberOfSamples;
  772. my samplesLeft = 0;
  773. flush ();
  774. } else {
  775. int16 *pa_buffer; // an internal pa buffer to minimize the number of memory transfers between client and server
  776. size_t nbytes_left = my samplesLeft * my numberOfChannels * 2; // how many bytes do we still need to write ?
  777. size_t nbytes = nbytes_left;
  778. // returns the address of an internal buffer and the number of bytes that can maximally be written to it.
  779. if (pa_stream_begin_write (stream, (void **) & pa_buffer, & nbytes) < 0) {
  780. trace (U"error: no memory");
  781. Melder_throw (U"Pulseaudio has no internal memory left.");
  782. }
  783. trace (U"buffer size = ", nbytes);
  784. // do we need the full buffer space ?
  785. nbytes = nbytes <= nbytes_left ? nbytes : nbytes_left;
  786. memcpy (pa_buffer, (void *)(my buffer + my samplesSent * my numberOfChannels), nbytes);
  787. //memset (pa_buffer, 0, nbytes);
  788. if (pa_stream_write (stream, pa_buffer, nbytes, nullptr, 0, PA_SEEK_RELATIVE) < 0) {
  789. Melder_throw (U"pa_stream_write() failed: ", Melder_peek8to32 (pa_strerror (pa_context_errno (my pulseAudio.context))));
  790. }
  791. Melder_assert (nbytes % (my numberOfChannels * 2) == 0);
  792. integer samplesSent = nbytes / (my numberOfChannels * 2);
  793. my samplesSent += samplesSent;
  794. my samplesPlayed = my samplesSent; // not true: use timer info
  795. trace (U"written ", samplesSent, U" (samples), total ", my samplesSent, U", address = ", (integer) pa_buffer);
  796. if (my samplesSent == my numberOfSamples) {
  797. // my samplesLeft = 0; not here because still playing
  798. trace (U"nothing left 1");
  799. pa_stream_set_write_callback (my pulseAudio.stream, nullptr, nullptr);
  800. my pulseAudio.operation_drain = pa_stream_drain (my pulseAudio.stream, stream_drain_complete_cb, me);
  801. if (! my pulseAudio.operation_drain) {
  802. pa_stream_disconnect (my pulseAudio.stream);
  803. pa_stream_unref (my pulseAudio.stream);
  804. my pulseAudio.stream = nullptr;
  805. trace (U"stream exists");
  806. my pulseAudio.occupation &= ~ PA_WRITING;
  807. my pulseAudio.occupation |= PA_WRITING_DONE;
  808. pa_threaded_mainloop_signal (my pulseAudio.mainloop, 0);
  809. if (my pulseAudio.timer_event) {
  810. my pulseAudio.mainloop_api -> time_free (my pulseAudio.timer_event);
  811. my pulseAudio.timer_event = nullptr;
  812. }
  813. }
  814. }
  815. }
  816. } else {
  817. trace (U"nothing left");
  818. }
  819. } else {
  820. trace (U"stream?");
  821. }
  822. }
  823. void stream_state_cb (pa_stream *stream, void *userdata) {
  824. struct MelderPlay *me = (struct MelderPlay *) userdata;
  825. if (stream == my pulseAudio.stream) {
  826. switch (pa_stream_get_state (stream)) {
  827. case PA_STREAM_UNCONNECTED:
  828. trace (U"PA_STREAM_UNCONNECTED");
  829. break;
  830. case PA_STREAM_CREATING:
  831. trace (U"PA_STREAM_CREATING");
  832. break;
  833. case PA_STREAM_TERMINATED:
  834. trace (U"PA_STREAM_TERMINATED");
  835. break;
  836. case PA_STREAM_READY: {
  837. const pa_buffer_attr* buffer_attr = pa_stream_get_buffer_attr (my pulseAudio.stream);
  838. trace (U"PA_STREAM_READY : tlength = ", buffer_attr -> tlength, U", prebuf = ", buffer_attr -> prebuf, U", maxlength = ", buffer_attr -> maxlength);
  839. break;
  840. }
  841. default:
  842. trace (U"default");
  843. break;
  844. case PA_STREAM_FAILED:
  845. trace (U"PA_STREAM_FAILED");
  846. break;
  847. }
  848. }
  849. }
  850. static void stream_underflow_callback (pa_stream *s, void *userdata) {
  851. (void) s;
  852. (void) userdata;
  853. trace (U"yes");
  854. }
  855. static void stream_overflow_callback(pa_stream *s, void *userdata) {
  856. (void) s;
  857. (void) userdata;
  858. trace (U"yes");
  859. }
  860. void prepare_and_play (struct MelderPlay *me) {
  861. #if __BYTE_ORDER == __BIG_ENDIAN
  862. my pulseAudio.sample_spec.format = PA_SAMPLE_S16BE;
  863. #else
  864. my pulseAudio.sample_spec.format = PA_SAMPLE_S16LE;
  865. #endif
  866. my samplesPlayed = my samplesSent = 0;
  867. my pulseAudio.sample_spec.rate = my sampleRate;
  868. my pulseAudio.sample_spec.channels = my numberOfChannels;
  869. my pulseAudio.stream = pa_stream_new (my pulseAudio.context, "Praat", &(my pulseAudio.sample_spec), nullptr);
  870. if (! my pulseAudio.stream) {
  871. Melder_throw (U"Cannot connect to sound server: ", Melder_peek8to32 (pa_strerror (pa_context_errno (my pulseAudio.context))));
  872. }
  873. //my pulseAudio.stream_flags = PA_STREAM_NOFLAGS;
  874. my pulseAudio.stream_flags = (pa_stream_flags_t) (PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE);
  875. my pulseAudio.latency = pa_usec_to_bytes (1000 * my pulseAudio.latency_msec, & my pulseAudio.sample_spec);
  876. my pulseAudio.buffer_attr.maxlength = (uint32) -1;
  877. my pulseAudio.buffer_attr.prebuf = (uint32) -1;
  878. my pulseAudio.buffer_attr.minreq = (uint32) -1;
  879. my pulseAudio.buffer_attr.prebuf = (uint32) -1;
  880. my pulseAudio.buffer_attr.tlength = my pulseAudio.latency;
  881. my pulseAudio.buffer_attr.fragsize = (uint32) -1;
  882. pa_stream_set_state_callback (my pulseAudio.stream, stream_state_cb, me);
  883. pa_stream_set_write_callback (my pulseAudio.stream, stream_write_cb, me);
  884. pa_stream_set_underflow_callback (my pulseAudio.stream, stream_underflow_callback, me);
  885. pa_stream_set_overflow_callback (my pulseAudio.stream, stream_overflow_callback, me);
  886. // BUG in pa 5.9 & 6.0: the server doesn't honour our wish for a reasonable tlength. Instead it uses some
  887. // ridiculously low value for tlength that will constantly give underflows.
  888. // audio playback was completely shit if in the stream_write_cb we used pa_stream_write instead of
  889. // first pa_stream_begin_write followed by pa_stream_write.
  890. //
  891. my pulseAudio.stream_flags = PA_STREAM_NOFLAGS;
  892. if (pa_stream_connect_playback (my pulseAudio.stream, nullptr, & my pulseAudio.buffer_attr, my pulseAudio.stream_flags, nullptr, nullptr) < 0) {
  893. Melder_throw (U"pa_stream_connect_playback() failed: ", Melder_peek8to32 (pa_strerror (pa_context_errno (my pulseAudio.context))));
  894. }
  895. trace (U"tlength = ", my pulseAudio.buffer_attr.tlength, U", channels = ", my numberOfChannels);
  896. }
  897. void context_state_cb (pa_context *context, void *userdata) {
  898. struct MelderPlay *me = (struct MelderPlay *) userdata;
  899. pa_context_state context_state = pa_context_get_state (context);
  900. switch (context_state) {
  901. case PA_CONTEXT_UNCONNECTED:
  902. trace (U"PA_CONTEXT_UNCONNECTED");
  903. break;
  904. case PA_CONTEXT_CONNECTING:
  905. trace (U"PA_CONTEXT_CONNECTING");
  906. break;
  907. case PA_CONTEXT_AUTHORIZING:
  908. trace (U"PA_CONTEXT_AUTHORIZING");
  909. break;
  910. case PA_CONTEXT_SETTING_NAME:
  911. trace (U"PA_CONTEXT_SETTING_NAME");
  912. break;
  913. case PA_CONTEXT_FAILED:
  914. trace (U"PA_CONTEXT_FAILED");
  915. break;
  916. case PA_CONTEXT_TERMINATED:
  917. trace (U"PA_CONTEXT_TERMINATED");
  918. break;
  919. case PA_CONTEXT_READY: {
  920. trace (U"PA_CONTEXT_READY");
  921. if ((my pulseAudio.occupation & PA_GETTINGINFO) == PA_GETTINGINFO) {
  922. my pulseAudio.operation_info = pa_context_get_server_info (my pulseAudio.context, pulseAudio_server_info_cb, me);
  923. trace (U"operation started");
  924. if (! my pulseAudio.operation_info) {
  925. Melder_throw (U"pulseAudioServer report: ", Melder_peek8to32 (pa_strerror (pa_context_errno (my pulseAudio.context))));
  926. }
  927. } else if ((my pulseAudio.occupation & PA_WRITING) == PA_WRITING) {
  928. prepare_and_play (me);
  929. } else if ((my pulseAudio.occupation & PA_RECORDING) == PA_RECORDING) {
  930. }
  931. break;
  932. }
  933. default:
  934. trace (U"default");
  935. break;
  936. }
  937. }
  938. #endif
  939. void MelderAudio_play16 (int16 *buffer, integer sampleRate, integer numberOfSamples, int numberOfChannels,
  940. bool (*playCallback) (void *playClosure, integer numberOfSamplesPlayed), void *playClosure)
  941. {
  942. struct MelderPlay *me = & thePlay;
  943. #ifdef _WIN32
  944. bool wasPlaying = MelderAudio_isPlaying;
  945. #endif
  946. if (MelderAudio_isPlaying) MelderAudio_stopPlaying (MelderAudio_IMPLICIT); // otherwise, keep "explicitStop" tag
  947. #ifdef HAVE_PULSEAUDIO
  948. if (my usePulseAudio && my pulseAudio.mainloop) {
  949. pulseAudio_cleanup ();
  950. }
  951. #endif
  952. my buffer = buffer; // 0-based, as all buffers are
  953. my sampleRate = sampleRate;
  954. my numberOfSamples = numberOfSamples;
  955. my numberOfChannels = numberOfChannels;
  956. my callback = playCallback;
  957. my closure = playClosure;
  958. my asynchronicity =
  959. Melder_batch ? kMelder_asynchronicityLevel::SYNCHRONOUS :
  960. (Melder_backgrounding && ! Melder_asynchronous) ? kMelder_asynchronicityLevel::INTERRUPTABLE :
  961. kMelder_asynchronicityLevel::ASYNCHRONOUS;
  962. if (my asynchronicity > preferences. maximumAsynchronicity)
  963. my asynchronicity = preferences. maximumAsynchronicity;
  964. trace (U"asynchronicity ", (int) my asynchronicity);
  965. my usePortAudio =
  966. #if defined (_WIN32)
  967. preferences. outputSoundSystem == kMelder_outputSoundSystem::MME_VIA_PORTAUDIO;
  968. #elif defined (macintosh)
  969. preferences. outputSoundSystem == kMelder_outputSoundSystem::COREAUDIO_VIA_PORTAUDIO;
  970. #else
  971. preferences. outputSoundSystem == kMelder_outputSoundSystem::ALSA_VIA_PORTAUDIO;
  972. #endif
  973. my usePulseAudio = ! my usePortAudio;
  974. my explicitStop = MelderAudio_IMPLICIT;
  975. my fakeMono = false;
  976. my volatile_interrupted = 0;
  977. my samplesLeft = numberOfSamples;
  978. my samplesSent = 0;
  979. my samplesPlayed = 0;
  980. MelderAudio_isPlaying = true;
  981. if (my usePortAudio) {
  982. PaError err;
  983. static bool paInitialized = false;
  984. if (! paInitialized) {
  985. err = Pa_Initialize ();
  986. if (err) Melder_fatal (U"PortAudio does not initialize: ", Melder_peek8to32 (Pa_GetErrorText (err)));
  987. paInitialized = true;
  988. }
  989. my supports_paComplete = Pa_GetHostApiInfo (Pa_GetDefaultHostApi ()) -> type != paDirectSound &&false;
  990. PaStreamParameters outputParameters = { 0 };
  991. outputParameters. device = Pa_GetDefaultOutputDevice ();
  992. const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo (outputParameters. device);
  993. trace (U"the device can handle ", deviceInfo -> maxOutputChannels, U" channels");
  994. if (my numberOfChannels > deviceInfo -> maxOutputChannels) {
  995. my numberOfChannels = deviceInfo -> maxOutputChannels;
  996. }
  997. if (numberOfChannels > my numberOfChannels) {
  998. /*
  999. * Redistribute the in channels over the out channels.
  1000. */
  1001. if (numberOfChannels == 4 && my numberOfChannels == 2) { // a common case
  1002. int16 *in = & my buffer [0], *out = & my buffer [0];
  1003. for (integer isamp = 1; isamp <= numberOfSamples; isamp ++) {
  1004. integer in1 = *in ++, in2 = *in ++, in3 = *in ++, in4 = *in ++;
  1005. *out ++ = (in1 + in2) / 2;
  1006. *out ++ = (in3 + in4) / 2;
  1007. }
  1008. } else {
  1009. int16 *in = & my buffer [0], *out = & my buffer [0];
  1010. for (integer isamp = 1; isamp <= numberOfSamples; isamp ++) {
  1011. for (integer iout = 1; iout <= my numberOfChannels; iout ++) {
  1012. integer outValue = 0;
  1013. integer numberOfIn = numberOfChannels / my numberOfChannels;
  1014. if (iout == my numberOfChannels)
  1015. numberOfIn += numberOfChannels % my numberOfChannels;
  1016. for (integer iin = 1; iin <= numberOfIn; iin ++)
  1017. outValue += *in ++;
  1018. outValue /= numberOfIn;
  1019. *out ++ = outValue;
  1020. }
  1021. }
  1022. }
  1023. }
  1024. outputParameters. channelCount = my numberOfChannels;
  1025. outputParameters. sampleFormat = paInt16;
  1026. if (deviceInfo) outputParameters. suggestedLatency = deviceInfo -> defaultLowOutputLatency;
  1027. outputParameters. hostApiSpecificStreamInfo = nullptr;
  1028. err = Pa_OpenStream (& my stream, nullptr, & outputParameters, my sampleRate, paFramesPerBufferUnspecified,
  1029. paDitherOff, thePaStreamCallback, me);
  1030. if (err) Melder_throw (U"PortAudio cannot open sound output: ", Melder_peek8to32 (Pa_GetErrorText (err)), U".");
  1031. theStartingTime = Melder_clock ();
  1032. err = Pa_StartStream (my stream);
  1033. if (err) Melder_throw (U"PortAudio cannot start sound output: ", Melder_peek8to32 (Pa_GetErrorText (err)), U".");
  1034. my paStartingTime = Pa_GetStreamTime (my stream);
  1035. if (my asynchronicity <= kMelder_asynchronicityLevel::INTERRUPTABLE) {
  1036. for (;;) {
  1037. #if defined (linux)
  1038. /*
  1039. * This is how PortAudio was designed to work.
  1040. */
  1041. if (my samplesLeft == 0) {
  1042. my samplesPlayed = my numberOfSamples;
  1043. break;
  1044. }
  1045. #else
  1046. /*
  1047. * A version that doesn't trust that the stream callback will complete.
  1048. */
  1049. double timeElapsed = Melder_clock () - theStartingTime - Pa_GetStreamInfo (my stream) -> outputLatency;
  1050. integer samplesPlayed = (integer) floor (timeElapsed * my sampleRate);
  1051. if (samplesPlayed >= my numberOfSamples + my sampleRate / 20) {
  1052. my samplesPlayed = my numberOfSamples;
  1053. break;
  1054. }
  1055. #endif
  1056. bool interrupted = false;
  1057. if (my asynchronicity != kMelder_asynchronicityLevel::SYNCHRONOUS && my callback &&
  1058. ! my callback (my closure, my samplesPlayed))
  1059. interrupted = true;
  1060. /*
  1061. * Safe operation: only listen to key-down events.
  1062. * Do this on the lowest level that will work.
  1063. */
  1064. if (my asynchronicity == kMelder_asynchronicityLevel::INTERRUPTABLE && ! interrupted) {
  1065. #if gtk
  1066. // TODO: implement a reaction to the Escape key
  1067. #elif cocoa
  1068. // TODO: implement a reaction to the Escape key
  1069. #elif defined (macintosh)
  1070. EventRecord event;
  1071. if (EventAvail (keyDownMask, & event)) {
  1072. /*
  1073. * Remove the event, even if it was a different key.
  1074. * Otherwise, the key will block the future availability of the Escape key.
  1075. */
  1076. FlushEvents (keyDownMask, 0);
  1077. /*
  1078. * Catch Escape and Command-period.
  1079. */
  1080. if ((event. message & charCodeMask) == 27 ||
  1081. ((event. modifiers & cmdKey) && (event. message & charCodeMask) == '.'))
  1082. {
  1083. my explicitStop = MelderAudio_EXPLICIT;
  1084. interrupted = true;
  1085. }
  1086. }
  1087. #elif defined (_WIN32)
  1088. MSG event;
  1089. if (PeekMessage (& event, 0, 0, 0, PM_REMOVE) && event. message == WM_KEYDOWN) {
  1090. if (LOWORD (event. wParam) == VK_ESCAPE) {
  1091. my explicitStop = MelderAudio_EXPLICIT;
  1092. interrupted = true;
  1093. }
  1094. }
  1095. #endif
  1096. }
  1097. if (interrupted) {
  1098. flush ();
  1099. return;
  1100. }
  1101. Pa_Sleep (10);
  1102. }
  1103. if (my samplesPlayed != my numberOfSamples) {
  1104. Melder_fatal (U"Played ", my samplesPlayed, U" instead of ", my numberOfSamples, U" samples.");
  1105. }
  1106. #ifndef linux
  1107. Pa_AbortStream (my stream);
  1108. #endif
  1109. } else /* my asynchronicity == kMelder_asynchronicityLevel_ASYNCHRONOUS */ {
  1110. #if gtk
  1111. trace (U"g_idle_add");
  1112. my workProcId_gtk = g_idle_add (workProc_gtk, nullptr);
  1113. #elif motif
  1114. my workProcId_motif = GuiAddWorkProc (workProc_motif, nullptr);
  1115. #elif cocoa
  1116. CFRunLoopTimerContext context = { 0, nullptr, nullptr, nullptr, nullptr };
  1117. my cocoaTimer = CFRunLoopTimerCreate (nullptr, CFAbsoluteTimeGetCurrent () + 0.02,
  1118. 0.02, 0, 0, workProc_cocoa, & context);
  1119. CFRunLoopAddTimer (CFRunLoopGetCurrent (), my cocoaTimer, kCFRunLoopCommonModes);
  1120. #endif
  1121. return;
  1122. }
  1123. flush ();
  1124. return;
  1125. #ifdef HAVE_PULSEAUDIO
  1126. } else if (my usePulseAudio) {
  1127. my pulseAudio.occupation |= PA_QUERY_NUMBEROFCHANNELS; // set query bit on
  1128. pulseAudio_serverReport ();
  1129. my pulseAudio.occupation &= ~PA_QUERY_NUMBEROFCHANNELS; // set query bit off
  1130. if (numberOfChannels > my numberOfChannels) {
  1131. /*
  1132. * Redistribute the in channels over the out channels. TODO make channelmap
  1133. */
  1134. if (numberOfChannels == 4 && my numberOfChannels == 2) { // a common case
  1135. int16 *in = & my buffer [0], *out = & my buffer [0];
  1136. for (integer isamp = 1; isamp <= numberOfSamples; isamp ++) {
  1137. integer in1 = *in ++, in2 = *in ++, in3 = *in ++, in4 = *in ++;
  1138. *out ++ = (in1 + in2) / 2;
  1139. *out ++ = (in3 + in4) / 2;
  1140. }
  1141. } else {
  1142. int16 *in = & my buffer [0], *out = & my buffer [0];
  1143. for (integer isamp = 1; isamp <= numberOfSamples; isamp ++) {
  1144. for (integer iout = 1; iout <= my numberOfChannels; iout ++) {
  1145. integer outValue = 0;
  1146. integer numberOfIn = numberOfChannels / my numberOfChannels;
  1147. if (iout == my numberOfChannels)
  1148. numberOfIn += numberOfChannels % my numberOfChannels;
  1149. for (integer iin = 1; iin <= numberOfIn; iin ++)
  1150. outValue += *in ++;
  1151. outValue /= numberOfIn;
  1152. *out ++ = outValue;
  1153. }
  1154. }
  1155. }
  1156. } else if (numberOfChannels < my numberOfChannels) {
  1157. // pulseaudio will divide the input over the output channels
  1158. my numberOfChannels = numberOfChannels;
  1159. }
  1160. my pulseAudio.occupation |= PA_WRITING;
  1161. pulseAudio_initialize ();
  1162. if (pa_context_get_state (my pulseAudio.context) == PA_CONTEXT_READY) {
  1163. prepare_and_play (me);
  1164. }
  1165. if (my asynchronicity < kMelder_asynchronicityLevel::ASYNCHRONOUS) {
  1166. pa_threaded_mainloop_lock (my pulseAudio.mainloop);
  1167. trace (U"occupation ", my pulseAudio.occupation);
  1168. while ((my pulseAudio.occupation & PA_WRITING_DONE) != PA_WRITING_DONE) {
  1169. trace (U"waiting");
  1170. pa_threaded_mainloop_wait (my pulseAudio.mainloop);
  1171. }
  1172. // Now we know that the stream drain operation has succeeded !
  1173. if (my pulseAudio.operation_drain) {
  1174. pa_operation_unref (my pulseAudio.operation_drain);
  1175. }
  1176. my pulseAudio.operation_drain = nullptr;
  1177. my pulseAudio.occupation &= ~PA_WRITING_DONE;
  1178. pa_threaded_mainloop_unlock (my pulseAudio.mainloop);
  1179. //pa_threaded_mainloop_accept (my pulseAudio.mainloop);
  1180. trace (U"before cleanup");
  1181. pulseAudio_cleanup ();
  1182. } else {
  1183. // my workProcId_gtk = g_timeout_add (ms, workProc_gtk, nullptr);
  1184. // without a timer, on my computer the workproc would be called almost once in every sampling period.
  1185. // Such frequent updates are not necessary, some 50 updates a second is fast enough for displaying a runnning cursor
  1186. // the timeout will be automatically stopped if workProc_gtk returns false.
  1187. #if gtk
  1188. #ifndef NO_GRAPHICS
  1189. my workProcId_gtk = g_timeout_add (20, workProc_gtk, nullptr);
  1190. #endif
  1191. #endif
  1192. }
  1193. #endif
  1194. } else {
  1195. #if defined (macintosh)
  1196. #elif defined (linux) && ! defined (NO_AUDIO)
  1197. try {
  1198. /* Big-endian version added by Stefan de Konink, Nov 29, 2007 */
  1199. #if __BYTE_ORDER == __BIG_ENDIAN
  1200. int fmt = AFMT_S16_BE;
  1201. #else
  1202. int fmt = AFMT_S16_LE;
  1203. #endif
  1204. /* O_NDELAY option added by Rafael Laboissiere, May 19, 2005 */
  1205. if ((my audio_fd = open ("/dev/dsp", O_WRONLY | (Melder_debug == 16 ? 0 : O_NDELAY))) == -1) {
  1206. Melder_throw (errno == EBUSY ? U"Audio device already in use." :
  1207. U"Cannot open audio device.\nPlease switch on PortAudio in Praat's Sound Playing Preferences.");
  1208. }
  1209. fcntl (my audio_fd, F_SETFL, 0); /* Added by Rafael Laboissiere, May 19, 2005 */
  1210. if (ioctl (my audio_fd, SNDCTL_DSP_SETFMT, // changed SND_DSP_SAMPLESIZE to SNDCTL_DSP_SETFMT; Stefan de Konink, Nov 29, 2007
  1211. (my val = fmt, & my val)) == -1 || // error?
  1212. my val != fmt) // has sound card overridden our sample size?
  1213. {
  1214. Melder_throw (U"Cannot set sample size to 16 bit.");
  1215. }
  1216. if (ioctl (my audio_fd, SNDCTL_DSP_CHANNELS, (my val = my numberOfChannels, & my val)) == -1 || /* Error? */
  1217. my val != my numberOfChannels) /* Has sound card overridden our number of channels? */
  1218. {
  1219. /*
  1220. * There is one specific case in which we can work around the current failure,
  1221. * namely when we are trying to play in mono but the driver of the sound card supports stereo only
  1222. * and notified us of this by overriding our number of channels.
  1223. */
  1224. if (my numberOfChannels == 1 && my val == 2) {
  1225. my fakeMono = true;
  1226. int16 *newBuffer = NUMvector <int16> (0, 2 * numberOfSamples - 1);
  1227. for (integer isamp = 0; isamp < numberOfSamples; isamp ++) {
  1228. newBuffer [isamp + isamp] = newBuffer [isamp + isamp + 1] = buffer [isamp];
  1229. }
  1230. my buffer = newBuffer;
  1231. my numberOfChannels = 2;
  1232. } else {
  1233. Melder_throw (U"Cannot set number of channels to .", my numberOfChannels, U".");
  1234. }
  1235. }
  1236. if (ioctl (my audio_fd, SNDCTL_DSP_SPEED, (my val = my sampleRate, & my val)) == -1 || // error?
  1237. my val != my sampleRate) // has sound card overridden our sampling frequency?
  1238. {
  1239. Melder_throw (U"Cannot set sampling frequency to ", my sampleRate, U" Hz.");
  1240. }
  1241. theStartingTime = Melder_clock ();
  1242. if (my asynchronicity == kMelder_asynchronicityLevel::SYNCHRONOUS) {
  1243. if (write (my audio_fd, & my buffer [0], 2 * numberOfChannels * numberOfSamples) == -1)
  1244. Melder_throw (U"Cannot write audio output.");
  1245. close (my audio_fd), my audio_fd = 0; // drain; set to zero in order to notify flush ()
  1246. my samplesPlayed = my numberOfSamples;
  1247. } else if (my asynchronicity <= kMelder_asynchronicityLevel::INTERRUPTABLE) {
  1248. bool interrupted = false;
  1249. while (my samplesLeft && ! interrupted) {
  1250. int dsamples = my samplesLeft > 500 ? 500 : my samplesLeft;
  1251. if (write (my audio_fd, (char *) & my buffer [my samplesSent * my numberOfChannels], 2 * dsamples * my numberOfChannels) == -1)
  1252. Melder_throw (U"Cannot write audio output.");
  1253. my samplesLeft -= dsamples;
  1254. my samplesSent += dsamples;
  1255. my samplesPlayed = (Melder_clock () - theStartingTime) * my sampleRate;
  1256. if (my callback && ! my callback (my closure, my samplesPlayed))
  1257. interrupted = true;
  1258. }
  1259. if (! interrupted) {
  1260. /*
  1261. * Wait for playing to end.
  1262. */
  1263. close (my audio_fd), my audio_fd = 0; // BUG: should do a loop
  1264. my samplesPlayed = my numberOfSamples;
  1265. }
  1266. } else /* my asynchronicity == kMelder_asynchronicityLevel_ASYNCHRONOUS */ {
  1267. #ifndef NO_GUI
  1268. my workProcId_gtk = g_idle_add (workProc_gtk, nullptr);
  1269. #endif
  1270. return;
  1271. }
  1272. flush ();
  1273. return;
  1274. } catch (MelderError) {
  1275. //struct MelderPlay *me = & thePlay;
  1276. if (my audio_fd) close (my audio_fd), my audio_fd = 0;
  1277. MelderAudio_isPlaying = false;
  1278. Melder_throw (U"16-bit audio not played.");
  1279. }
  1280. #elif defined (_WIN32)
  1281. try {
  1282. WAVEFORMATEX waveFormat;
  1283. MMRESULT err;
  1284. waveFormat. wFormatTag = WAVE_FORMAT_PCM;
  1285. waveFormat. nChannels = my numberOfChannels;
  1286. waveFormat. nSamplesPerSec = my sampleRate;
  1287. waveFormat. wBitsPerSample = 16;
  1288. waveFormat. nBlockAlign = my numberOfChannels * waveFormat. wBitsPerSample / 8;
  1289. waveFormat. nAvgBytesPerSec = waveFormat. nBlockAlign * waveFormat. nSamplesPerSec;
  1290. waveFormat. cbSize = 0;
  1291. err = waveOutOpen (& my hWaveOut, WAVE_MAPPER, & waveFormat, 0, 0, CALLBACK_NULL | WAVE_ALLOWSYNC);
  1292. if (err != MMSYSERR_NOERROR) {
  1293. MelderAudio_isPlaying = false;
  1294. if (err == MMSYSERR_ALLOCATED)
  1295. Melder_throw (U"Previous sound is still playing? Should not occur!\n"
  1296. U"Report bug to the author: ", err, U"; wasPlaying: ", wasPlaying, U".");
  1297. if (err == MMSYSERR_BADDEVICEID)
  1298. Melder_throw (U"Cannot play a sound. Perhaps another program is playing a sound at the same time?");
  1299. if (err == MMSYSERR_NODRIVER)
  1300. Melder_throw (U"This computer probably has no sound card.");
  1301. if (err == MMSYSERR_NOMEM)
  1302. Melder_throw (U"Not enough free memory to play any sound at all.");
  1303. if (err == WAVERR_BADFORMAT) {
  1304. if (my numberOfChannels > 2) {
  1305. /*
  1306. * Retry with 2 channels.
  1307. */
  1308. my numberOfChannels = 2;
  1309. waveFormat. nChannels = my numberOfChannels;
  1310. waveFormat. nBlockAlign = my numberOfChannels * waveFormat. wBitsPerSample / 8;
  1311. waveFormat. nAvgBytesPerSec = waveFormat. nBlockAlign * waveFormat. nSamplesPerSec;
  1312. err = waveOutOpen (& my hWaveOut, WAVE_MAPPER, & waveFormat, 0, 0, CALLBACK_NULL | WAVE_ALLOWSYNC);
  1313. if (err != MMSYSERR_NOERROR)
  1314. Melder_throw (U"Bad sound format even after reduction to 2 channels? Should not occur! Report bug to the author!");
  1315. MelderAudio_isPlaying = true;
  1316. } else {
  1317. Melder_throw (U"Bad sound format? Should not occur! Report bug to the author!");
  1318. }
  1319. } else {
  1320. Melder_throw (U"Unknown error ", err, U" while trying to play a sound? Report bug to the author!");
  1321. }
  1322. }
  1323. if (numberOfChannels > my numberOfChannels) {
  1324. /*
  1325. * Redistribute the in channels over the out channels.
  1326. */
  1327. if (numberOfChannels == 4 && my numberOfChannels == 2) { // a common case
  1328. int16 *in = & my buffer [0], *out = & my buffer [0];
  1329. for (integer isamp = 1; isamp <= numberOfSamples; isamp ++) {
  1330. integer in1 = *in ++, in2 = *in ++, in3 = *in ++, in4 = *in ++;
  1331. *out ++ = (in1 + in2) / 2;
  1332. *out ++ = (in3 + in4) / 2;
  1333. }
  1334. } else {
  1335. int16 *in = & my buffer [0], *out = & my buffer [0];
  1336. for (integer isamp = 1; isamp <= numberOfSamples; isamp ++) {
  1337. for (integer iout = 1; iout <= my numberOfChannels; iout ++) {
  1338. integer outValue = 0;
  1339. integer numberOfIn = numberOfChannels / my numberOfChannels;
  1340. if (iout == my numberOfChannels)
  1341. numberOfIn += numberOfChannels % my numberOfChannels;
  1342. for (integer iin = 1; iin <= numberOfIn; iin ++)
  1343. outValue += *in ++;
  1344. outValue /= numberOfIn;
  1345. *out ++ = outValue;
  1346. }
  1347. }
  1348. }
  1349. }
  1350. my waveHeader. dwFlags = 0;
  1351. my waveHeader. lpData = (char *) my buffer;
  1352. my waveHeader. dwBufferLength = my numberOfSamples * 2 * my numberOfChannels;
  1353. my waveHeader. dwLoops = 1;
  1354. my waveHeader. lpNext = nullptr;
  1355. my waveHeader. reserved = 0;
  1356. err = waveOutPrepareHeader (my hWaveOut, & my waveHeader, sizeof (WAVEHDR));
  1357. //waveOutReset (my hWaveOut);
  1358. if (err != MMSYSERR_NOERROR) {
  1359. waveOutClose (my hWaveOut), my hWaveOut = 0;
  1360. MelderAudio_isPlaying = false;
  1361. if (err == MMSYSERR_INVALHANDLE)
  1362. Melder_throw (U"No device? Should not occur!");
  1363. if (err == MMSYSERR_NODRIVER)
  1364. Melder_throw (U"No driver? Should not occur!");
  1365. if (err == MMSYSERR_NOMEM)
  1366. Melder_throw (U"Not enough free memory to play this sound.\n"
  1367. U"Remove some objects, play a shorter sound, or buy more memory.");
  1368. Melder_throw (U"Unknown error ", err, U" while preparing header? Should not occur!");
  1369. }
  1370. err = waveOutWrite (my hWaveOut, & my waveHeader, sizeof (WAVEHDR));
  1371. if (err != MMSYSERR_NOERROR) {
  1372. waveOutReset (my hWaveOut);
  1373. waveOutUnprepareHeader (my hWaveOut, & my waveHeader, sizeof (WAVEHDR));
  1374. waveOutClose (my hWaveOut), my hWaveOut = 0;
  1375. MelderAudio_isPlaying = false;
  1376. Melder_throw (U"Error ", err, U" while writing audio output."); // BUG: should flush
  1377. }
  1378. theStartingTime = Melder_clock ();
  1379. if (my asynchronicity == kMelder_asynchronicityLevel::SYNCHRONOUS) {
  1380. while (! (my waveHeader. dwFlags & WHDR_DONE)) {
  1381. Sleep (10);
  1382. }
  1383. my samplesPlayed = my numberOfSamples;
  1384. } else if (my asynchronicity <= kMelder_asynchronicityLevel::INTERRUPTABLE) {
  1385. while (! (my waveHeader. dwFlags & WHDR_DONE)) {
  1386. MSG event;
  1387. Sleep (10);
  1388. my samplesPlayed = (Melder_clock () - theStartingTime) * my sampleRate;
  1389. if (my callback && ! my callback (my closure, my samplesPlayed))
  1390. break;
  1391. if (my asynchronicity == kMelder_asynchronicityLevel::INTERRUPTABLE &&
  1392. PeekMessage (& event, 0, 0, 0, PM_REMOVE) && event. message == WM_KEYDOWN)
  1393. {
  1394. if (LOWORD (event. wParam) == VK_ESCAPE) {
  1395. my explicitStop = MelderAudio_EXPLICIT;
  1396. break;
  1397. }
  1398. }
  1399. }
  1400. } else {
  1401. my workProcId_motif = GuiAddWorkProc (workProc_motif, nullptr);
  1402. return;
  1403. }
  1404. flush ();
  1405. return;
  1406. } catch (MelderError) {
  1407. Melder_throw (U"16-bit audio not played.");
  1408. }
  1409. #else
  1410. Melder_throw (U"Cannot play a sound on this computer.\n16-bit audio not played.");
  1411. #endif
  1412. }
  1413. }
  1414. /* End of file melder_audio.cpp */