1 /**
2  * Stream a sound to SDL_mixer by abusing Mix_RegisterEffect
3 
4  * Copyright (C) 2007  Sylvain Beucler
5 
6  * This file is part of GNU FreeDink
7 
8  * GNU FreeDink is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 3 of the
11  * License, or (at your option) any later version.
12 
13  * GNU FreeDink is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17 
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see
20  * <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "SDL.h"
24 #include "SDL_mixer.h"
25 #include <math.h>
26 #include <stdbool.h>
27 
28 int global_halt = 0;
29 
30 /**
31  * Display a SDL audio-format in human-readable form
32  **/
format2string(Uint16 format)33 static const char *format2string(Uint16 format) {
34   char *format_str = "Unknown";
35   switch (format)
36     {
37     case AUDIO_U8: format_str = "U8"; break;
38     case AUDIO_S8: format_str = "S8"; break;
39     case AUDIO_U16LSB: format_str = "U16LSB"; break;
40     case AUDIO_S16LSB: format_str = "S16LSB"; break;
41     case AUDIO_U16MSB: format_str = "U16MSB"; break;
42     case AUDIO_S16MSB: format_str = "S16MSB"; break;
43     }
44   return format_str;
45 }
46 
47 
48 /**
49  * Hold the state of the 'effect'
50  */
51 struct sine_state
52 {
53   int x;
54   int loop;
55 };
56 
57 /**
58  * Generate a A-440Hz sine, starting at x coordinate 'udata->x' and lasting
59  * 'len'/2 frames
60  */
gen_sine(int chan,void * stream,int len,void * udata)61 void gen_sine(int chan, void *stream, int len, void *udata)
62 {
63   printf("gen_sine(%d)\n", len);
64   struct sine_state* data = (struct sine_state*)udata;
65   Sint16* pstream = (Sint16*) stream;
66 
67   int max_vol = 1<<(2*8-1) - 1; // 127
68   int vol = max_vol * .75;
69 
70   for (int i = 0; i < len/2/2; i++)
71     {
72       /* Fill 'stream' */
73       Sint16 y = sin(data->x*6.28*440/44100) * vol;
74       *pstream = y;
75       pstream++;
76       *pstream = y; /* stereo */
77       pstream++;
78       data->x++;
79     }
80 
81   data->loop++;
82   if (data->loop == 10)
83     {
84       //Mix_HaltChannel(1);
85       global_halt = 1;
86     }
87 }
gen_sine_cleanup(int chan,void * udata)88 void gen_sine_cleanup(int chan, void *udata)
89 {
90   free(udata);
91 }
92 
93 /**
94  * Free channel resources if any
95  */
channel_cleanup(int channel)96 void channel_cleanup(int channel)
97 {
98 }
99 
100 /**
101  * Work-around a streamed chunk support in SDL_mixer, by running an
102  * effect over a small chunk ran in loop
103  */
main(void)104 int main(void)
105 {
106   /* Init */
107   SDL_Init(SDL_INIT_AUDIO);
108   Mix_OpenAudio(44100, AUDIO_S16LSB,
109 		MIX_DEFAULT_CHANNELS, 4096 /* 4096 */);
110   Mix_AllocateChannels(1);
111 
112   /* Dump audio info */
113   {
114     int hw_freq, hw_channels;
115     Uint16 hw_format;
116     int numtimesopened;
117     numtimesopened = Mix_QuerySpec(&hw_freq, &hw_format, &hw_channels);
118     if (!numtimesopened)
119       printf("Mix_QuerySpec: %s\n", Mix_GetError());
120     else
121       printf("Audio hardware info: frequency=%dHz\tformat=%s\tchannels=%d\topened=%d times\n",
122 	     hw_freq, format2string(hw_format), hw_channels, numtimesopened);
123   }
124 
125   char buf[409600];
126   Mix_Chunk *chunk = Mix_QuickLoad_RAW(buf, 409600);
127   if (chunk == NULL)
128     printf("Mix_QuickLoad_RAW: %s\n", Mix_GetError());
129 
130 
131   /** Play a A-440hz pure sound **/
132   Mix_Pause(0);
133   int channel = Mix_PlayChannel(0, chunk, -1);
134   printf("Using channel %d\n", channel);/* error */
135   if (channel < 0)
136     printf("Error %d\n", channel);/* error */
137 
138   /* Register sound generator */
139   struct sine_state *data = calloc(1, sizeof(struct sine_state));
140   data->x = 0;
141   Mix_RegisterEffect(channel, gen_sine, gen_sine_cleanup, data);
142   Mix_ChannelFinished(channel_cleanup);
143 
144   Mix_Resume(channel);
145 
146   /* Play chunk with looping (infinite play) */
147   while (global_halt == 0)
148     {
149       SDL_Delay(100);
150     }
151 }
152 
153 
154 /**
155  * Local Variables:
156  * compile-command: "gcc test.c -std=c99 `sdl-config --cflags --libs` -lSDL_mixer"
157  * End:
158  */
159