media-sdl.c (3697B)
1 #include <assert.h> 2 #include <string.h> 3 4 #include <SDL2/SDL.h> 5 6 #include "media.h" 7 8 #define PIXEL_RADIUS 16 9 10 #define SCREEN_WIDTH (64*PIXEL_RADIUS) 11 #define SCREEN_HEIGHT (32*PIXEL_RADIUS) 12 13 #define WINDOW_NAME "CHIP-8 emulator" 14 15 #define NUM_PIXELS (SCREEN_WIDTH*SCREEN_HEIGHT) 16 #define SCREEN_RECT ((SDL_Rect){.x=0,.y=0,.w=SCREEN_WIDTH,.h=SCREEN_HEIGHT}) 17 18 #define SOUND_DEV_FREQ 48000 19 #define SOUND_SAMPLES 1024 20 #define BUZZER_FREQ 440 21 #define BUZZER_VOL .05 22 23 unsigned char *pixels; 24 25 SDL_Window *window; 26 SDL_Renderer *renderer; 27 SDL_Texture *texture; 28 29 /* sound state*/ 30 int buzzer_state = 0; 31 32 /* 33 ┌───┬───┬───┬───┐ 34 │ 1 │ 2 │ 3 │ C │ 35 ├───┼───┼───┼───┤ 36 │ 4 │ 5 │ 6 │ D │ 37 ├───┼───┼───┼───┤ 38 │ 7 │ 8 │ 9 │ E │ 39 ├───┼───┼───┼───┤ 40 │ A │ 0 │ B │ F │ 41 └───┴───┴───┴───┘ 42 */ 43 44 SDL_Keycode keys[16] = { 45 SDLK_v, 46 SDLK_3, SDLK_4, SDLK_5, 47 SDLK_e, SDLK_r, SDLK_t, 48 SDLK_d, SDLK_f, SDLK_g, 49 SDLK_c, SDLK_b, 50 SDLK_6, SDLK_y, SDLK_h, SDLK_n 51 }; 52 53 static void buzzer_callback(void* userdata, Uint8* stream, int len){ 54 static long sample_num = 0; 55 (void) userdata; 56 for(int i=0 ; i<len ; i++){ 57 if(buzzer_state == 0) 58 stream[i] = 0; 59 else /* saw waves at the moment */ 60 stream[i] = 61 ((sample_num++*256*BUZZER_FREQ/SOUND_DEV_FREQ) 62 %256)*BUZZER_VOL; 63 } 64 } 65 66 int m_init(int argc, char **argv){ 67 (void)argc, (void)argv; 68 /*TODO: check every init */ 69 70 pixels = calloc(1,NUM_PIXELS); 71 72 SDL_Init( SDL_INIT_EVERYTHING ); 73 window = SDL_CreateWindow( 74 WINDOW_NAME, 75 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 76 SCREEN_WIDTH, SCREEN_HEIGHT, 77 0); 78 79 renderer = SDL_CreateRenderer( 80 window, -1, 81 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 82 83 texture = SDL_CreateTexture( 84 renderer, 85 SDL_PIXELFORMAT_RGB332, SDL_TEXTUREACCESS_STREAMING, 86 SCREEN_WIDTH, SCREEN_HEIGHT); 87 88 SDL_RenderClear(renderer); 89 90 SDL_OpenAudio(&(SDL_AudioSpec){ 91 .freq = SOUND_DEV_FREQ, 92 .format = AUDIO_U8, 93 .channels = 1, 94 .samples = SOUND_SAMPLES, 95 .callback = buzzer_callback, 96 }, NULL); 97 98 SDL_PauseAudio(0); 99 100 return 0; 101 } 102 103 void m_quit(void){ 104 SDL_DestroyTexture(texture); 105 SDL_DestroyRenderer(renderer); 106 SDL_DestroyWindow(window); 107 108 SDL_CloseAudio(); 109 110 SDL_Quit(); 111 112 free(pixels); 113 } 114 115 unsigned short get_input(unsigned short input){ 116 SDL_Event e; 117 118 while(SDL_PollEvent(&e)){ 119 if (e.type == SDL_QUIT) { 120 return -1; 121 } 122 if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP) { 123 for(int i=0;i<16;i++){ 124 if(e.key.keysym.sym == keys[i]){ 125 if(e.type == SDL_KEYDOWN){ 126 input |= 1<<i; 127 } else { 128 input &= ~(1<<i); 129 } 130 break; 131 } 132 } 133 } 134 } 135 136 return input; 137 } 138 unsigned short wait_input(unsigned short input){ 139 /* TODO: better version */ 140 int new_input; 141 142 while((new_input = get_input(input)) == input) 143 SDL_Delay(1); 144 145 return new_input; 146 } 147 148 void clear_screen(void){ 149 memset(pixels,0,NUM_PIXELS); 150 } 151 152 void draw(int x, int y, int value){ 153 assert(0<=x && x<64); 154 assert(0<=y && y<32); 155 156 for(int i=0 ; i<PIXEL_RADIUS ; i++){ 157 for(int j=0 ; j<PIXEL_RADIUS ; j++){ 158 pixels[(y*PIXEL_RADIUS+i)*SCREEN_WIDTH + 159 x*PIXEL_RADIUS+j] = value ? 255 : 0; 160 } 161 } 162 } 163 164 void frame(void){ 165 void *texture_pixels; 166 int pitch; /* we don't actually use this, yolo */ 167 SDL_LockTexture(texture, &SCREEN_RECT, &texture_pixels, &pitch); 168 memcpy(texture_pixels, pixels, NUM_PIXELS); 169 SDL_UnlockTexture(texture); 170 171 SDL_RenderCopy(renderer, texture, &SCREEN_RECT, &SCREEN_RECT); 172 SDL_RenderPresent(renderer); 173 SDL_RenderClear(renderer); 174 } 175 176 void set_buzzer_state(int state){ 177 buzzer_state = state; 178 }