]> git.lizzy.rs Git - nothing.git/blob - src/sound_medium.c
Merge pull request #153 from tsoding/152
[nothing.git] / src / sound_medium.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4
5 #include <SDL2/SDL.h>
6 #include <SDL2/SDL_mixer.h>
7
8 #include "./sound_medium.h"
9 #include "./lt.h"
10 #include "./error.h"
11 #include "./pi.h"
12 #include "./algo.h"
13
14 #define SOUND_THRESHOLD_DISTANCE 1000.0f
15
16 struct sound_medium_t
17 {
18     lt_t *lt;
19     Mix_Chunk **samples;
20     size_t samples_count;
21     point_t *channel_positions;
22     int paused;
23     int lower_channel;
24     int upper_channel;
25     size_t channels_count;
26 };
27
28 static int mix_get_free_channel(int lower_channel,
29                                 int upper_channel)
30 {
31     assert(lower_channel >= 0);
32     assert(upper_channel >= 0);
33     assert(lower_channel <= upper_channel);
34
35     for (int i = lower_channel; i < upper_channel; ++i) {
36         if (!Mix_Playing(i)) {
37             return i;
38         }
39     }
40
41     return -1;
42 }
43
44 static point_t *sound_medium_channel_position(sound_medium_t *sound_medium,
45                                               int channel_number)
46 {
47     assert(sound_medium);
48     assert(sound_medium->lower_channel <= channel_number);
49     assert(channel_number <= sound_medium->upper_channel);
50     return sound_medium->channel_positions + channel_number - sound_medium->lower_channel;
51 }
52
53 sound_medium_t *create_sound_medium(Mix_Chunk **samples,
54                                     size_t samples_count,
55                                     int lower_channel,
56                                     int upper_channel)
57 {
58     assert(samples);
59     assert(samples_count > 0);
60     assert(lower_channel >= 0);
61     assert(upper_channel >= 0);
62     assert(lower_channel <= upper_channel);
63
64     lt_t *lt = create_lt();
65     if (lt == NULL) {
66         return NULL;
67     }
68
69     sound_medium_t *sound_medium = PUSH_LT(lt, malloc(sizeof(sound_medium_t)), free);
70     if (sound_medium == NULL) {
71         throw_error(ERROR_TYPE_LIBC);
72         RETURN_LT(lt, NULL);
73     }
74
75     sound_medium->channels_count = (size_t) (upper_channel - lower_channel + 1);
76     sound_medium->channel_positions = PUSH_LT(
77         lt,
78         malloc(sizeof(point_t) * sound_medium->channels_count),
79         free);
80     if (sound_medium->channel_positions == NULL) {
81         throw_error(ERROR_TYPE_LIBC);
82         RETURN_LT(lt, NULL);
83     }
84
85     sound_medium->samples = samples;
86     sound_medium->samples_count = samples_count;
87     sound_medium->paused = 0;
88     sound_medium->lower_channel = lower_channel;
89     sound_medium->upper_channel = upper_channel;
90
91     sound_medium->lt = lt;
92
93     return sound_medium;
94 }
95
96 void destroy_sound_medium(sound_medium_t *sound_medium)
97 {
98     assert(sound_medium);
99     RETURN_LT0(sound_medium->lt);
100 }
101
102 int sound_medium_play_sound(sound_medium_t *sound_medium,
103                             size_t sound_index,
104                             point_t position,
105                             int loops)
106 {
107     assert(sound_medium);
108     (void) sound_index;
109     (void) position;
110
111     if (sound_index < sound_medium->samples_count) {
112         const int free_channel = mix_get_free_channel(sound_medium->lower_channel,
113                                                       sound_medium->upper_channel);
114
115         printf("Found free channel: %d\n", free_channel);
116
117         if (free_channel >= 0) {
118             *sound_medium_channel_position(sound_medium, free_channel) = position;
119             return Mix_PlayChannel(free_channel, sound_medium->samples[sound_index], loops);
120         }
121     }
122
123     return 0;
124 }
125
126 int sound_medium_listen_sounds(sound_medium_t *sound_medium,
127                                point_t position)
128 {
129     assert(sound_medium);
130
131     for (int i = sound_medium->lower_channel; i <= sound_medium->upper_channel; ++i) {
132         if (Mix_Playing(i)) {
133             const vec_t v = vec_from_ps(position, *sound_medium_channel_position(sound_medium, i));
134             const Sint16 angle = (Sint16) roundf(rad_to_deg(vec_arg(v)));
135             const Uint8 distance = (Uint8) roundf(MIN(vec_mag(v), SOUND_THRESHOLD_DISTANCE) / SOUND_THRESHOLD_DISTANCE * 255.0f);
136             Mix_SetPosition(i, angle, distance);
137         }
138     }
139
140     return 0;
141 }
142
143 int sound_medium_toggle_pause(sound_medium_t *sound_medium)
144 {
145     assert(sound_medium);
146
147     if (sound_medium->paused) {
148         Mix_Resume(-1);
149     } else {
150         Mix_Pause(-1);
151     }
152
153     sound_medium->paused = !sound_medium->paused;
154
155     return 0;
156 }