static void punp_sound_load_stbv(Sound *sound, stb_vorbis *stream) { stb_vorbis_info info = stb_vorbis_get_info(stream); sound->volume = PUNP_SOUND_DEFAULT_SOUND_VOLUME; sound->rate = info.sample_rate; sound->samples_count = stb_vorbis_stream_length_in_samples(stream); sound->samples = (i16 *)bank_push(CORE->storage, PUNP_SOUND_SAMPLES_TO_BYTES(sound->samples_count)); { static i16 buffer[1024]; i16 *it = sound->samples; int samples_read_per_channel; for (; ;) { int samples_read_per_channel = stb_vorbis_get_samples_short_interleaved(stream, PUNP_SOUND_CHANNELS, buffer, 1024); if (samples_read_per_channel == 0) { break; } // 2 channels, 16 bits per sample. memcpy(it, buffer, PUNP_SOUND_SAMPLES_TO_BYTES(samples_read_per_channel)); it += samples_read_per_channel * PUNP_SOUND_CHANNELS; } } stb_vorbis_close(stream); }
void bitmap_init(Bitmap *bitmap, i32 width, i32 height, void *pixels, int bpp) { Palette *palette = &CORE->palette; u32 size = width * height; bitmap->width = width; bitmap->height = height; bitmap->pixels = (u8 *)bank_push(CORE->storage, size); if (pixels) { if (bpp == BITMAP_32) { Color pixel; Color *pixels_end = ((Color *)pixels) + size; Color *pixels_it = (Color *)pixels; u8 *it = bitmap->pixels; u8 ix; for (; pixels_it != pixels_end; ++pixels_it) { if (pixels_it->a < 0x7F) { ix = COLOR_TRANSPARENT; // pixels_it->a = 0; goto next; } pixel = *pixels_it; // TODO: This is just for Windows, need to be done a bit better. pixel.b = pixels_it->r; pixel.r = pixels_it->b; pixel.a = 0xFF; for (ix = 1; ix < palette->colors_count; ix++) { if (palette->colors[ix].rgba == pixel.rgba) goto next; } // Add the color. ASSERT(palette->colors_count != 0xFF); if (palette->colors_count != 0xFF) { ix = palette->colors_count; palette->colors[ix] = pixel; palette->colors_count++; // printf("[palette] + #%0.2x %0.2x%0.2x%0.2x%0.2x\n", // ix, pixel.r, pixel.g, pixel.b, pixel.a); } next: // Write the indexed color. *it++ = ix; } } else if (bpp == BITMAP_8) { memcpy(bitmap->pixels, pixels, size); } else { ASSERT_MESSAGE(0, "bitmap_init: Invalid bpp specified."); } } // if pixels }
void sound_play(Sound *sound) { PunPAudioSource *source = NULL; if (punp_audio_source_pool == 0) { // Pool is empty, therefore we must allocate a new source. source = (PunPAudioSource *)bank_push(CORE->storage, sizeof(PunPAudioSource)); // printf("Allocating audio source.\n"); } else { // We have something in the pool. source = punp_audio_source_pool; punp_audio_source_pool = source->next; // printf("Pooling audio source.\n"); } if (source) { memset(source, 0, sizeof(PunPAudioSource)); source->sound = sound; source->rate = (f32)sound->rate / (f32)SOUND_SAMPLE_RATE; source->next = punp_audio_source_playback; punp_audio_source_playback = source; } }
int main (int ac, char **av) { sisy_t sisy; bank_t bank; audio_t audio; int done=0; init_tab(); memset(&sisy, 0, sizeof(sisy)); bank.pos = 0; bank.watches_size = 0; bank.name = "sisy IO"; bank.size = sizeof(sisy_IO_t); bank.data = &sisy.IO; bank.symtab = IO_symtab; bank_push(&bank); sisy_getopt(ac, av); instru_path[instru_path_size] = Malloc(strlen(getenv("HOME")) + strlen("/.sisy/") + 200); strcat(instru_path[instru_path_size], getenv("HOME")); strcat(instru_path[instru_path_size++], "/.sisy/"); instru_path[instru_path_size++] = "/usr/share/sisy/"; sisy.buffer = buffer_create(); printf("Init midi: "); if(sisy_midi_init(&sisy, midi_device) < 0) { fprintf(stderr, "ERROR: got some troubles while opening midi device %s\n", midi_device); goto error; } printf("Ok\nInit audio: "); if(audio_init(&audio, audio_device) < 0) { fprintf(stderr, "ERROR: got some troubles while opening audio device %s\n", audio_device); goto error; } printf("Ok\nEnter in main loop...\n"); while(!done) { int t; done=1; ck_err(buffer_zero(sisy.buffer)<0); // printf("%d\r", midi_timestamp_get()); for(t=0; t<sisy.nb_tracks; t++) { sisy_track_t *track=&sisy.tracks[t]; if(!track->EOT) { done=0;//We are not done ! ck_err(bank_push(&track->midi.bank)); ck_err(buffer_zero(track->buffer) < 0); ck_err(sisy_track_process(track) < 0); ck_err(bank_pop_check(&track->midi.bank)); ck_err(buffer_mix(track->buffer, sisy.buffer)); } } /* if(!is_buffer_flat(sisy.buffer)) */ /* printf("sisy: buffer qui bouge\n"); */ ck_err(audio_write(&audio, sisy.buffer)<0); } /* ck_err(bank_pop_check(&sisy.midi.bank)); */ /* ck_err(bank_pop_check(&bank)); */ audio_quit(&audio); return 0; error: return -1; }
// Called from platform to fill in the audio buffer. // static void punp_sound_mix(i16 *buffer, isize samples_count) { BankState bank_state = bank_begin(CORE->stack); isize size = samples_count * sizeof(f32); f32 *channel0 = (f32 *)bank_push(CORE->stack, size); f32 *channel1 = (f32 *)bank_push(CORE->stack, size); f32 *it0, *it1; isize i; isize sound_samples, sound_samples_remaining; Sound *sound; PunPAudioSource **it, *source; // // Zero the channels. // it0 = channel0; it1 = channel1; memset(it0, 0, size); memset(it1, 0, size); // // Mix the sources. // it = &punp_audio_source_playback; while (*it) { source = *it; ASSERT(source->sound); sound = source->sound; sound_samples = samples_count; sound_samples_remaining = sound->samples_count - source->position; if (sound_samples > sound_samples_remaining) { sound_samples = sound_samples_remaining; } it0 = channel0; it1 = channel1; for (i = 0; i < sound_samples; ++i) { i16 *sample = &sound->samples[(source->position + (isize)((f32)i * source->rate)) * 2]; //sample = punp_audio_source_sample(source, i); *it0++ += sample[0] * sound->volume; *it1++ += sample[1] * sound->volume; } source->position += sound_samples * source->rate; if (source->position == source->sound->samples_count) { *it = source->next; source->next = punp_audio_source_pool; punp_audio_source_pool = source; } else { it = &source->next; } } // // Put to output buffer, clamp and convert to 16-bit. // // #define MIX_CLIP_(in, clip) (0.5 * (abs(in + clip) - abs(in - clip)) * CORE->audio_volume) #if 0 // Make sure sound buffer is not empty if (sound) { i16 *it_buffer = buffer; it0 = channel0; it1 = channel1; for (i = 0; i < samples_count; ++i) { f32 s1 = *it0++ * sound->volume * CORE->audio_volume; f32 s2 = *it1++ * sound->volume * CORE->audio_volume; // *it_buffer++ = (i16)(MIX_CLIP_(s1, 32767)); // *it_buffer++ = (i16)(MIX_CLIP_(s2, 32767)); // *it_buffer++ = (i16)(s1 + 0.5f); // *it_buffer++ = (i16)(s2 + 0.5f); *it_buffer++ = (i16)clamp(s1, -32768, 32767); *it_buffer++ = (i16)clamp(s2, -32768, 32767); } } #endif // #undef MIX_CLIP_ bank_end(&bank_state); }
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR command_line, int show_code) { static Bank s_stack = {0}; static Bank s_storage = {0}; static Core s_core = {0}; static Bitmap s_canvas = {0}; WNDCLASSA window_class = {0}; u32 *window_buffer = NULL; BITMAPINFO window_bmi = {0}; if (align_to(CANVAS_WIDTH, 16) != CANVAS_WIDTH) { printf("CANVAS_WIDTH must be aligned to 16.\n"); return 1; } CORE = &s_core; CORE->running = 1; CORE->stack = &s_stack; CORE->storage = &s_storage; bank_init(CORE->stack, STACK_CAPACITY); bank_init(CORE->storage, STORAGE_CAPACITY); // TODO: Push canvas to storage? Storage is not initialized yet, so we cannot push it there. CORE->canvas = &s_canvas; bitmap_init(CORE->canvas, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0); bitmap_clear(CORE->canvas, COLOR_TRANSPARENT); clip_reset(); CORE->audio_volume = PUNP_SOUND_DEFAULT_MASTER_VOLUME; // // // punp_win32_instance = instance; QueryPerformanceFrequency((LARGE_INTEGER *)&punp_win32_perf_counter_frequency); // b32 sleep_is_granular = (timeBeginPeriod(1 /*ms*/) == TIMERR_NOERROR); #ifndef RELEASE_BUILD printf("Debug build..."); if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()) { freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); } #else printf("Release build..."); #endif window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; window_class.lpfnWndProc = win32_window_callback; window_class.hInstance = punp_win32_instance; // window_class.hIcon = (HICON)LoadImage(0, "icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_SHARED); window_class.hIcon = (HICON)LoadIcon(instance, "icon.ico"); window_class.hCursor = LoadCursor(0, IDC_ARROW); window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); window_class.lpszClassName = "Punity"; if (!RegisterClassA(&window_class)) { printf("RegisterClassA failed.\n"); return 1; } { int screen_width = GetSystemMetrics(SM_CXSCREEN); int screen_height = GetSystemMetrics(SM_CYSCREEN); RECT rc; DWORD style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; rc.left = (screen_width - (PUNP_WINDOW_WIDTH)) / 2; rc.top = (screen_height - (PUNP_WINDOW_HEIGHT)) / 2; rc.right = rc.left + PUNP_WINDOW_WIDTH; rc.bottom = rc.top + PUNP_WINDOW_HEIGHT; ASSERT(AdjustWindowRect(&rc, style, FALSE) != 0); // int window_width = rc.right - rc.left; // int window_height = rc.bottom - rc.top; // rc.left = (screen_width - width) / 2; // rc.top = (screen_height - height) / 2; punp_win32_window = CreateWindowExA( 0, window_class.lpszClassName, WINDOW_TITLE, style, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0, 0, punp_win32_instance, 0); } if (!punp_win32_window) { printf("CreateWindowExA failed.\n"); return 1; } // Canvas window_bmi.bmiHeader.biSize = sizeof(window_bmi.bmiHeader); window_bmi.bmiHeader.biWidth = CANVAS_WIDTH; window_bmi.bmiHeader.biHeight = CANVAS_HEIGHT; window_bmi.bmiHeader.biPlanes = 1; window_bmi.bmiHeader.biBitCount = 32; window_bmi.bmiHeader.biCompression = BI_RGB; window_buffer = (u32 *)bank_push(CORE->stack, (CANVAS_WIDTH * 4) * CANVAS_HEIGHT); ASSERT(window_buffer); // Sound if (punp_win32_sound_init() == 0) { punp_win32_audio_buffer = 0; } init(); // TODO: Center window ShowWindow(punp_win32_window, SW_SHOW); { f64 frame_time_stamp, frame_time_now, frame_time_delta; int x, y; u32 *window_row; u8 *canvas_it; MSG message; perf_from(&CORE->perf_frame); while (CORE->running) { perf_to(&CORE->perf_frame); perf_from(&CORE->perf_frame_inner); memset(&CORE->key_deltas, 0, KEYS_MAX); while (PeekMessage(&message, 0, 0, 0, PM_REMOVE)) { if (message.message == WM_QUIT) { CORE->running = 0; } TranslateMessage(&message); DispatchMessageA(&message); } perf_from(&CORE->perf_step); step(); perf_to(&CORE->perf_step); perf_from(&CORE->perf_audio); if (punp_win32_audio_buffer) { punp_win32_sound_step(); } perf_to(&CORE->perf_audio); perf_from(&CORE->perf_blit); perf_from(&CORE->perf_blit_cvt); canvas_it = CORE->canvas->pixels; for (y = CANVAS_HEIGHT; y != 0; --y) { window_row = window_buffer + ((y - 1) * CANVAS_WIDTH); for (x = 0; x != CANVAS_WIDTH; ++x) { *(window_row++) = CORE->palette.colors[*canvas_it++].rgba; } } perf_to(&CORE->perf_blit_cvt); perf_from(&CORE->perf_blit_gdi); { HDC dc = GetDC(punp_win32_window); #if 1 // TODO: This is sadly slow (50us on my machine), need to find a faster way to do this. StretchDIBits(dc, 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, window_buffer, &window_bmi, DIB_RGB_COLORS, SRCCOPY); #else #endif ReleaseDC(punp_win32_window, dc); } perf_to(&CORE->perf_blit_gdi); perf_to(&CORE->perf_blit); perf_to(&CORE->perf_frame_inner); { f32 frame_delta = perf_delta(&CORE->perf_frame); if (frame_delta < PUNP_FRAME_TIME) { // printf("sleeping ... %.3f\n", (f32)PUNP_FRAME_TIME - frame_delta); Sleep((PUNP_FRAME_TIME - frame_delta) * 1e3); } } CORE->frame++; #if 0 printf("stack %d storage %d\n", CORE->stack->it - CORE->stack->begin, CORE->storage->it - CORE->storage->begin); #endif } } #if PUNP_SOUND_DEBUG_FILE fclose(punp_audio_buf_file); #endif return 0; }