diff --git a/ampler.c b/ampler.c index 0a52782..e5fc61e 100644 --- a/ampler.c +++ b/ampler.c @@ -67,6 +67,10 @@ int ampler_main(SDL_Window *w, SDL_Renderer *r, Ampler_state **u_data) { state -> played_audio_last_frame = audio_frame(state); draw_frame(w, r, state); + // CLEAR UDP MESSAGES + foreach_ptr(Udp_msg, msg, state -> messages) + msg -> state = MSG_FREE; + SDL_Delay(1); if !remove("reload-trigger") do { diff --git a/ampler.h b/ampler.h index 6832cd7..35c1dda 100644 --- a/ampler.h +++ b/ampler.h @@ -28,6 +28,11 @@ typedef double f64; #define arraylen(a) (sizeof (a) / sizeof ((a)[0])) +#define foreach_ptr(TYPE, N, ARRAY) \ +for int N##_i = 0; N##_i == 0; N##_i = 1 do \ +for TYPE *N = &((ARRAY)[N##_i]); N != NULL; N = NULL do \ +for ; N##_i < arraylen(ARRAY); N##_i += 1, N = &((ARRAY)[N##_i]) do + #define SAMPLE_RATE (44100) #define CHANNELS (2) #define FRAME_SAMPLES (SAMPLE_RATE / 60) @@ -38,7 +43,13 @@ struct Sound_src { s32 len; // in samples f32 pos; // position in samples f32 speed; // in samples, per sample, can be negative - enum { FREE = 0, STOPPED, PLAYING, LOOPING } state; + enum { SND_FREE = 0, SND_STOPPED, SND_PLAYING, SND_LOOPING, } state; +}; + +typedef struct Udp_msg Udp_msg; +struct Udp_msg { + s8 text[32]; // includes null terminator + enum { MSG_FREE = 0, MSG_TRIGGER, } state; }; typedef struct Ampler_state Ampler_state; @@ -47,6 +58,7 @@ struct Ampler_state { SDL_AudioDeviceID playdev; Sound_src sounds[64]; s32 played_audio_last_frame; + Udp_msg messages[64]; }; diff --git a/audio.c b/audio.c index 4fbad99..893eb0b 100644 --- a/audio.c +++ b/audio.c @@ -1,7 +1,10 @@ // audio.c +// TODO: add something to make sure, we KNOW if we've dropped audio +// eg. buffer has gone unfilled for a frame or more + void sound_src_frame(Sound_src *s, s8 *mix[]) { - if s -> state == LOOPING do + if s -> state == SND_LOOPING do for int i = 0; i < FRAME_SAMPLES; i += 1 do { for int c = 0; c < CHANNELS; c += 1 do mix[c][i] += s -> tracks[c][(int) s -> pos]; @@ -27,8 +30,8 @@ int audio_frame(Ampler_state *state) { SDL_memset(mix_r, 0, sizeof mix_r); s8 *mix[] = { mix_l, mix_r }; - for int s = 0; s < arraylen(state -> sounds); s += 1 do - sound_src_frame(&(state -> sounds[s]), mix); + foreach_ptr(Sound_src, snd, state -> sounds) //for int s = 0; s < arraylen(state -> sounds); s += 1 do + sound_src_frame(snd, mix); //sound_src_frame(&(state -> sounds[s]), mix); const int vol = 100; static s16 frame[FRAME_SAMPLES * CHANNELS] = { 0 }; @@ -43,6 +46,17 @@ int audio_frame(Ampler_state *state) { } void load_track(Ampler_state *state) { + Sound_src *snd = NULL; + foreach_ptr(Sound_src, s, state -> sounds) + if s -> state == SND_FREE do { + snd = s; + break; + } + if snd == NULL do { + puts("error: all sound sources in use"); + return; + } + SDL_AudioSpec spec; s16 *buffer = NULL; u32 bytes = 0; @@ -57,18 +71,17 @@ void load_track(Ampler_state *state) { const int chans = spec.channels; const int length = (bytes / sizeof s16) / chans; - // TODO: Actually find free sound_src - Sound_src *snd = &(state -> sounds[0]); snd -> len = length; snd -> speed = 1.0f; snd -> pos = 0.0f; - snd -> state = LOOPING; // TOOD: Should be STOPPED + // snd -> state = SND_LOOPING; + snd -> state = SND_STOPPED; for int i = 0; i < CHANNELS; i += 1 do snd -> tracks[i] = malloc(snd -> len); for int i = 0; i < CHANNELS; i += 1 do - if !snd -> tracks[i] do + if !(snd -> tracks[i]) do puts("fffuuuck"); for int i = 0; i < snd -> len; i += 1 do diff --git a/draw.c b/draw.c index 92af3f5..f89bf8f 100644 --- a/draw.c +++ b/draw.c @@ -5,20 +5,23 @@ void draw_frame(SDL_Window *w, SDL_Renderer *r, Ampler_state *state) { //SDL_SetRenderDrawColor(r, 10, 10, 10, 100); SDL_RenderClear(r); - // TODO: ACTUALLY DRAW ALL SOUNDS, BUT SMOLER + // TODO: DRAW SMOLER SDL_SetRenderDrawColor(r, 0xFF, 0x00, 0x4D, 255); const space = (44100 * 8) / 512; + // TODO: DRAW L / R OVERLAPPED IN DIFF COLORS ? const int t = 0; - for int x = 0; x < 512; x += 1 do { - const int y = 128 + 256 * t; - const int val = state -> sounds[0].tracks[t][x * space]; - SDL_RenderDrawLine(r, x, y + val / 8, x, y + val); - //SDL_RenderDrawPoint(r, x, y + val); - } + foreach_ptr(Sound_src, snd, state -> sounds) + if snd -> state != SND_FREE do + for int x = 0; x < 512; x += 1 do { + const int y = 128 + 256 * snd_i; + const int val = snd -> tracks[t][x * space]; + SDL_RenderDrawLine(r, x, y + val / 8, x, y + val); + //SDL_RenderDrawPoint(r, x, y + val); + } if state -> played_audio_last_frame do - for int i = 0; i < arraylen(state -> sounds); i += 1 do { - const int x = state -> sounds[i].pos / space; + foreach_ptr(Sound_src, snd, state -> sounds) { + const int x = snd -> pos / space; SDL_RenderDrawLine(r, x, 0, x, 512); } diff --git a/udp.c b/udp.c index e9042c3..1e69a22 100644 --- a/udp.c +++ b/udp.c @@ -1,5 +1,13 @@ // udp.c +/* TODO: + * convert error codes to strings and print them, we could just make a table + * option to change port, handle when we cant get gur port + * be able to send packets when sounds / recording starts / ends ? + + * store from ip + port in message ? +*/ + #include #include "ampler.h" @@ -46,6 +54,51 @@ void udp_init(Ampler_state *state) { printf("error: bind returned SOCKET_ERROR, WSAGetLastError() = %i\n" , WSAGetLastError()); } +void udp_quit(Ampler_state *state) { + closesocket(udp_sock); + WSACleanup(); +} + +void recv_packet(Ampler_state *state) { + char discard_buf[32] = { 0 }; // for dropped packets + char *buf = discard_buf; + int buf_len = sizeof discard_buf; + + for (int i = 0; i < arraylen(state -> messages); i += 1) { + Udp_msg *msg = &(state -> messages[i]); + if (msg -> state == MSG_FREE) { + msg -> state = MSG_TRIGGER; + buf = msg -> text; + buf_len = sizeof msg -> text; + SDL_memset(buf, 0, buf_len); + break; + } + } + if (buf == discard_buf) + puts("dropped udp packet."); + + struct sockaddr_in from_addr; + int from_addr_size = sizeof from_addr; + // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom + int recv_len = recvfrom( + udp_sock, // socket to recive on + buf, // buffer for recv'd data + buf_len - 1, // size of buffer in bytes, '- 1' preserves null terminator + 0, // flags + &from_addr, // address struct to recieve source of packet + &from_addr_size // POINTER to size of address struct + ); + if (recv_len == SOCKET_ERROR) + if (WSAGetLastError() != WSAEMSGSIZE) // packet was truncated to fit buffer + printf("error: recvfrom returned SOCKET_ERROR, WSAGetLastError() = %i\n" , WSAGetLastError()); + + // convert to ipv4 address string, stored in static buffer, next call overwrites + const char *from_ip_str = inet_ntoa(from_addr.sin_addr); + int from_port = ntohs(from_addr.sin_port); // convert network to host byte order for short + if (0) // FOR DEBUGGING + printf("%s:%d\t%s\n", from_ip_str, from_port, buf); +} + void udp_frame(Ampler_state *state) { // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select fd_set recv_fd_set; @@ -77,34 +130,10 @@ void udp_frame(Ampler_state *state) { return; } - char buf[16] = { 0 }; - struct sockaddr_in from_addr; - int from_addr_size = sizeof from_addr; - // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom - int recv_len = recvfrom( - udp_sock, // socket to recive on - buf, // buffer for recv'd data - sizeof buf - 1, // size of buffer in bytes, '- 1' preserves null terminator - 0, // flags - &from_addr, // address struct to recieve source of packet - &from_addr_size // POINTER to size of address struct - ); - if (recv_len == SOCKET_ERROR) - if (WSAGetLastError() != WSAEMSGSIZE) // packet was truncated to fit buffer - printf("error: recvfrom returned SOCKET_ERROR, WSAGetLastError() = %i\n" , WSAGetLastError()); - - // convert to ipv4 address string, stored in static buffer, next call overwrites - const char *from_ip_str = inet_ntoa(from_addr.sin_addr); - int from_port = ntohs(from_addr.sin_port); // convert network to host byte order for short - printf("%s\t\t%s:%d\n", buf, from_ip_str, from_port); + recv_packet(state); } } -void udp_quit(Ampler_state *state) { - closesocket(udp_sock); - WSACleanup(); -} -