1 /*
2   Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
3 
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7 
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely.
11 */
12 
13 /* Program to load a wave file and loop playing it using SDL audio */
14 
15 /* loopwaves.c is much more robust in handling WAVE files --
16     This is only for simple WAVEs
17 */
18 #include "SDL_config.h"
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #ifdef __EMSCRIPTEN__
24 #include <emscripten/emscripten.h>
25 #endif
26 
27 #include "SDL.h"
28 
29 static struct
30 {
31     SDL_AudioSpec spec;
32     Uint8 *sound;               /* Pointer to wave data */
33     Uint32 soundlen;            /* Length of wave data */
34     int soundpos;               /* Current play position */
35 } wave;
36 
37 static SDL_AudioDeviceID device;
38 
39 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
40 static void
quit(int rc)41 quit(int rc)
42 {
43     SDL_Quit();
44     exit(rc);
45 }
46 
47 static void
close_audio()48 close_audio()
49 {
50     if (device != 0) {
51         SDL_CloseAudioDevice(device);
52         device = 0;
53     }
54 }
55 
56 static void
open_audio()57 open_audio()
58 {
59     /* Initialize fillerup() variables */
60     device = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wave.spec, NULL, 0);
61     if (!device) {
62         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError());
63         SDL_FreeWAV(wave.sound);
64         quit(2);
65     }
66 
67 
68     /* Let the audio run */
69     SDL_PauseAudioDevice(device, SDL_FALSE);
70 }
71 
reopen_audio()72 static void reopen_audio()
73 {
74     close_audio();
75     open_audio();
76 }
77 
78 
79 void SDLCALL
fillerup(void * unused,Uint8 * stream,int len)80 fillerup(void *unused, Uint8 * stream, int len)
81 {
82     Uint8 *waveptr;
83     int waveleft;
84 
85     /* Set up the pointers */
86     waveptr = wave.sound + wave.soundpos;
87     waveleft = wave.soundlen - wave.soundpos;
88 
89     /* Go! */
90     while (waveleft <= len) {
91         SDL_memcpy(stream, waveptr, waveleft);
92         stream += waveleft;
93         len -= waveleft;
94         waveptr = wave.sound;
95         waveleft = wave.soundlen;
96         wave.soundpos = 0;
97     }
98     SDL_memcpy(stream, waveptr, len);
99     wave.soundpos += len;
100 }
101 
102 static int done = 0;
103 
104 #ifdef __EMSCRIPTEN__
105 void
loop()106 loop()
107 {
108     if(done || (SDL_GetAudioDeviceStatus(device) != SDL_AUDIO_PLAYING))
109         emscripten_cancel_main_loop();
110 }
111 #endif
112 
113 int
main(int argc,char * argv[])114 main(int argc, char *argv[])
115 {
116     int i;
117     char filename[4096];
118 
119     /* Enable standard application logging */
120     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
121 
122     /* Load the SDL library */
123     if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_EVENTS) < 0) {
124         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
125         return (1);
126     }
127 
128     if (argc > 1) {
129         SDL_strlcpy(filename, argv[1], sizeof(filename));
130     } else {
131         SDL_strlcpy(filename, "sample.wav", sizeof(filename));
132     }
133     /* Load the wave file into memory */
134     if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
135         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError());
136         quit(1);
137     }
138 
139     wave.spec.callback = fillerup;
140 
141     /* Show the list of available drivers */
142     SDL_Log("Available audio drivers:");
143     for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
144         SDL_Log("%i: %s", i, SDL_GetAudioDriver(i));
145     }
146 
147     SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
148 
149     open_audio();
150 
151     SDL_FlushEvents(SDL_AUDIODEVICEADDED, SDL_AUDIODEVICEREMOVED);
152 
153 #ifdef __EMSCRIPTEN__
154     emscripten_set_main_loop(loop, 0, 1);
155 #else
156     while (!done) {
157         SDL_Event event;
158 
159         while (SDL_PollEvent(&event) > 0) {
160             if (event.type == SDL_QUIT) {
161                 done = 1;
162             }
163             if ((event.type == SDL_AUDIODEVICEADDED && !event.adevice.iscapture) ||
164                 (event.type == SDL_AUDIODEVICEREMOVED && !event.adevice.iscapture && event.adevice.which == device)) {
165                 reopen_audio();
166             }
167         }
168         SDL_Delay(100);
169     }
170 #endif
171 
172     /* Clean up on signal */
173     close_audio();
174     SDL_FreeWAV(wave.sound);
175     SDL_Quit();
176     return (0);
177 }
178 
179 /* vi: set ts=4 sw=4 expandtab: */
180