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 |
41 | quit(int rc) |
42 | { |
43 | SDL_Quit(); |
44 | exit(rc); |
45 | } |
46 | |
47 | static void |
48 | close_audio() |
49 | { |
50 | if (device != 0) { |
51 | SDL_CloseAudioDevice(device); |
52 | device = 0; |
53 | } |
54 | } |
55 | |
56 | static void |
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 | |
72 | static void reopen_audio() |
73 | { |
74 | close_audio(); |
75 | open_audio(); |
76 | } |
77 | |
78 | |
79 | void SDLCALL |
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 |
106 | loop() |
107 | { |
108 | if(done || (SDL_GetAudioDeviceStatus(device) != SDL_AUDIO_PLAYING)) |
109 | emscripten_cancel_main_loop(); |
110 | } |
111 | #endif |
112 | |
113 | int |
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 | |