From 3580bc6ce5ed635eba90edb9d4a795f9a99421db Mon Sep 17 00:00:00 2001 From: grimfang4 Date: Tue, 21 Jul 2009 02:48:46 +0000 Subject: [PATCH] Initial import --- sfxr/ChangeLog | 22 + sfxr/Ideas | 9 + sfxr/Makefile | 21 + sfxr/ddrawkit.h | 371 ++++++++++++ sfxr/font.tga | Bin 0 -> 12332 bytes sfxr/install.txt | 8 + sfxr/ld48.tga | Bin 0 -> 8414 bytes sfxr/main.cpp | 1419 +++++++++++++++++++++++++++++++++++++++++++++ sfxr/readme.txt | 163 ++++++ sfxr/sdlkit.h | 174 ++++++ sfxr/sfxr | Bin 0 -> 75274 bytes sfxr/sfxr.bmp | Bin 0 -> 2102 bytes sfxr/sfxr.desktop | 9 + sfxr/sfxr.png | Bin 0 -> 890 bytes sfxr/tools.h | 134 +++++ 15 files changed, 2330 insertions(+) create mode 100644 sfxr/ChangeLog create mode 100644 sfxr/Ideas create mode 100644 sfxr/Makefile create mode 100644 sfxr/ddrawkit.h create mode 100644 sfxr/font.tga create mode 100644 sfxr/install.txt create mode 100644 sfxr/ld48.tga create mode 100644 sfxr/main.cpp create mode 100644 sfxr/readme.txt create mode 100644 sfxr/sdlkit.h create mode 100755 sfxr/sfxr create mode 100644 sfxr/sfxr.bmp create mode 100644 sfxr/sfxr.desktop create mode 100644 sfxr/sfxr.png create mode 100644 sfxr/tools.h diff --git a/sfxr/ChangeLog b/sfxr/ChangeLog new file mode 100644 index 0000000..843688f --- /dev/null +++ b/sfxr/ChangeLog @@ -0,0 +1,22 @@ +sfxr-sdl-1.0 +------------ +* Initial SDL port of sfxr by mjau/GerryJJ + +sfxr-sdl-1.1 +------------ +* Various small improvements and 1 bugfix by Hans de Goede + : + * Fix a small bug in the audio setup which could cause a quite noticable + delay between pressing a button and hearing the sound + * Add an icon and .desktop file + * Add a make install target, note: hardcoded to /usr but it does understand + the DESTDIR make parameter + +sfxr-sdl-1.2.0 +------------- +* Changed version number convention: .. +* Added checkbox: Drag bars (the old default) + * Clicking sets the value of a slider +* Sound now plays when an attribute is clicked (a more involved change, like looping, would be needed for dragging) +* Sound now plays on waveform change +* Very simple undo (one slider change) with Z \ No newline at end of file diff --git a/sfxr/Ideas b/sfxr/Ideas new file mode 100644 index 0000000..16b5b4a --- /dev/null +++ b/sfxr/Ideas @@ -0,0 +1,9 @@ + +Make the undo into an array or list (very easy the way I have it set up, just plug it into the undo functions) +Make undo use a full state struct, so everything can be restored. +Add redo (push old undos to the redo list, clear redo list when something is changed) +List of open sounds + +What's up with the file save? If I click Save, then Cancel, it creates a messed up file. + +How would I draw the waveform? It'd be nice to see, but probably a hassle to do. \ No newline at end of file diff --git a/sfxr/Makefile b/sfxr/Makefile new file mode 100644 index 0000000..701125f --- /dev/null +++ b/sfxr/Makefile @@ -0,0 +1,21 @@ +CFLAGS=-ggdb +CXXFLAGS=$(CFLAGS) `sdl-config --cflags` `pkg-config gtk+-2.0 --cflags` +LDFLAGS=`sdl-config --libs` `pkg-config gtk+-2.0 --libs` + +sfxr: main.cpp tools.h sdlkit.h + $(CXX) $(CXXFLAGS) $(LDFLAGS) $< -o $@ + +install: sfxr + mkdir -p $(DESTDIR)/usr/bin + mkdir -p $(DESTDIR)/usr/share/sfxr + mkdir -p $(DESTDIR)/usr/share/applications + mkdir -p $(DESTDIR)/usr/share/icons/hicolor/48x48/apps + install -m 755 sfxr $(DESTDIR)/usr/bin + install -m 644 -p *.tga *.bmp $(DESTDIR)/usr/share/sfxr + install -p -m 644 sfxr.png \ + $(DESTDIR)/usr/share/icons/hicolor/48x48/apps + desktop-file-install --vendor "" \ + --dir $(DESTDIR)/usr/share/applications sfxr.desktop + +clean: + rm sfxr diff --git a/sfxr/ddrawkit.h b/sfxr/ddrawkit.h new file mode 100644 index 0000000..5d4ad16 --- /dev/null +++ b/sfxr/ddrawkit.h @@ -0,0 +1,371 @@ + +/* + + Porting notes + ------------- + + Need to provide window/framebuffer setup at program start + + ddkUnlock() is called when the window should be redrawn + + WinMain() at the bottom of this file is the entry point and main loop + which handles messages and calling the app update function ddkCalcFrame() + + ddkscreen32 = pointer to 640x480 DWORD pixel buffer + mouse_* = mouse info, only need x/y/px/py/left/right/leftclick/rightclick + +*/ + + +#define _WIN32_WINDOWS 0xBAD +#include + +extern "C" long _ftol( double ); //defined by VC6 C libs +extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); } + +void ddkInit(); // Will be called on startup +bool ddkCalcFrame(); // Will be called every frame, return true to continue running or false to quit +void ddkFree(); // Will be called on shutdown +bool ddkLock(); // Call immediately before drawing (once per frame) +void ddkUnlock(); // Call immediately after drawing (once per frame) +void ddkDrawPixel(int x, int y, int red, int green, int blue); // Draw a pixel +void ddkSetMode(int width, int height, int bpp, int refreshrate, int fullscreen, char *title); +#define DDK_WINDOW 0 // Run in a normal resizable window (stretch to fit) +#define DDK_FULLSCREEN 1 // Change display mode to the one specified, use vsync +#define DDK_STRETCH 2 // Run in a maximized window, looks like fullscreen +int ddkGetBpp(); // Use this to find out the current color depth +DWORD *ddkscreen32; // Use this for 32 bit modes +WORD *ddkscreen16; // Use this for 16 bit modes +int ddkpitch; // Offset in pixels from the start of one horizontal line to the start of the next + +bool ddrawkit_initialised; +bool ddrawkit_released; +bool ddrawkit_fullscreen; +bool ddrawkit_fullwindow; +int ddrawkit_width; +int ddrawkit_height; +int ddrawkit_bpp; +int ddrawkit_refresh; +bool ddrawkit_timeravailable; + +HWND hWndMain; +HINSTANCE hInstanceMain; + +HCURSOR cursor_arrow; +int mouse_x, mouse_y, mouse_px, mouse_py; +bool mouse_left=false, mouse_right=false, mouse_middle=false; +bool mouse_leftclick=false, mouse_rightclick=false, mouse_middleclick=false; +bool mouse_doubleclick=false; +int mouse_wheel=0; + + +// --- DDB implementation + +struct pBITMAPINFO +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +} BMInfo; + +HBITMAP hBM; + +HDC hDC_comp; +DWORD* image_bitmap; + +void InitImageBuffer() +{ + HPALETTE PalHan; + HWND ActiveWindow; + HDC hDC; + + image_bitmap=(DWORD*)malloc(ddrawkit_width*ddrawkit_height*sizeof(DWORD)); + + ActiveWindow=hWndMain; + hDC=GetDC(ActiveWindow); + + BMInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + BMInfo.bmiHeader.biWidth=ddrawkit_width; + BMInfo.bmiHeader.biHeight=-abs(ddrawkit_height); + BMInfo.bmiHeader.biPlanes=1; + BMInfo.bmiHeader.biBitCount=32; + BMInfo.bmiHeader.biCompression=BI_RGB; + BMInfo.bmiHeader.biSizeImage=ddrawkit_width*ddrawkit_height*4; + BMInfo.bmiHeader.biXPelsPerMeter=0; + BMInfo.bmiHeader.biYPelsPerMeter=0; + + hBM=CreateDIBSection(hDC, (BITMAPINFO*)&BMInfo, DIB_RGB_COLORS, (void**)&image_bitmap, 0, 0); + ReleaseDC(ActiveWindow, hDC); + + ddkscreen32=image_bitmap; + ddkpitch=ddrawkit_width; +} + +void DestroyImageBuffer() +{ + free(image_bitmap); +} + +void ddrawkit_BlitWindowDDB() +{ + HDC hDC; + HBITMAP DefaultBitmap; + + hDC=GetDC(hWndMain); + DefaultBitmap=(HBITMAP)SelectObject(hDC_comp, hBM); +// BitBlt(hDC, x1, y1, x2-x1, y2-y1, hDC_comp, x1, y1, SRCCOPY); + BitBlt(hDC, 0, 0, ddrawkit_width, ddrawkit_height, hDC_comp, 0, 0, SRCCOPY); + SelectObject(hDC_comp, DefaultBitmap); + DeleteDC(hDC); +} + +// --- DDB implementation + + +void ddrawkit_SafeDestroy() +{ + if(!ddrawkit_released) + { + ddrawkit_released=true; + ddkFree(); + DestroyWindow(hWndMain); + DestroyImageBuffer(); + } +} + +LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CLOSE: + ddrawkit_SafeDestroy(); + return 0; + + case WM_SETCURSOR: + if(ddrawkit_fullscreen || ddrawkit_fullwindow) + { + SetCursor(NULL); + return 0; + } + else + SetCursor(cursor_arrow); + break; + + case WM_MOUSEMOVE: + int curwidth, curheight; + RECT rect; + GetClientRect(hWndMain, &rect); + curwidth=rect.right-rect.left; + curheight=rect.bottom-rect.top; + mouse_x=(int)((float)LOWORD(lParam)/curwidth*ddrawkit_width); + mouse_y=(int)((float)HIWORD(lParam)/curheight*ddrawkit_height); + return 0; + case WM_MOUSEWHEEL: + if((wParam>>16)&0x7FFF) + { + if((wParam>>16)&0x8000) + mouse_wheel=-1; + else + mouse_wheel=1; + } + return 0; + case WM_LBUTTONDBLCLK: + mouse_doubleclick=true; + return 0; + case WM_LBUTTONDOWN: + mouse_left=true; + mouse_leftclick=true; + return 0; + case WM_LBUTTONUP: + mouse_left=false; + return 0; + case WM_RBUTTONDOWN: + mouse_right=true; + mouse_rightclick=true; + return 0; + case WM_RBUTTONUP: + mouse_right=false; + return 0; + case WM_MBUTTONDOWN: + mouse_middle=true; + mouse_middleclick=true; + return 0; + case WM_MBUTTONUP: + mouse_middle=false; + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void ddrawkit_RegisterWindowClass() +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(WNDCLASSEX)); + wcx.cbSize=sizeof(WNDCLASSEX); + wcx.lpfnWndProc=MainWindowProc; + wcx.hInstance=GetModuleHandle(NULL); + wcx.hIcon=LoadIcon(NULL, IDI_APPLICATION); + wcx.hCursor=NULL; +// wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); + wcx.hbrBackground=NULL; + wcx.lpszMenuName=NULL; + wcx.lpszClassName="DDrawKitClass"; + RegisterClassEx(&wcx); +} + +bool ddkLock() +{ + return true; +} + +void ddkUnlock() +{ + ddrawkit_BlitWindowDDB(); +} + +void ddkDrawPixel(int x, int y, int red, int green, int blue) +{ + if(x<0 || y<0 || x>=ddrawkit_width || y>=ddrawkit_height) + return; + + if(ddrawkit_bpp==32) + { + DWORD color=(red<<16)|(green<<8)|blue; + ddkscreen32[y*ddkpitch+x]=color; + } + if(ddrawkit_bpp==16) + { + WORD color=((red>>3)<<11)|((green>>2)<<5)|(blue>>3); + ddkscreen16[y*ddkpitch+x]=color; + } +} + +void ddkSetMode(int width, int height, int bpp, int refreshrate, int fullscreen, char *title) +{ + if(!ddrawkit_initialised) + { + ddrawkit_width=width; + ddrawkit_height=height; + ddrawkit_bpp=bpp; + ddrawkit_refresh=refreshrate; + switch(fullscreen) + { + case 0: + ddrawkit_fullscreen=false; + ddrawkit_fullwindow=false; + break; + case 1: + ddrawkit_fullscreen=true; + ddrawkit_fullwindow=false; + break; + case 2: + ddrawkit_fullscreen=false; + ddrawkit_fullwindow=true; + break; + } + + ddrawkit_RegisterWindowClass(); + + if(ddrawkit_fullscreen || ddrawkit_fullwindow) + { + // Screen sized window (possibly stretched) + hWndMain=CreateWindowEx(WS_EX_APPWINDOW, + "DDrawKitClass", title, WS_POPUP, + 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + NULL, NULL, hInstanceMain, NULL); + } + else + { + // Normal window +// hWndMain=CreateWindow("DDrawKitClass", title, WS_OVERLAPPEDWINDOW, + hWndMain=CreateWindow("DDrawKitClass", title, WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, +// 0, 0, ddrawkit_width+GetSystemMetrics(SM_CXSIZEFRAME)*2, +// ddrawkit_height+GetSystemMetrics(SM_CYSIZEFRAME)*2+GetSystemMetrics(SM_CYCAPTION), + GetSystemMetrics(SM_CXSCREEN)/2-320, GetSystemMetrics(SM_CYSCREEN)/2-300, + ddrawkit_width+GetSystemMetrics(SM_CXEDGE)*2, + ddrawkit_height+GetSystemMetrics(SM_CYEDGE)*2+GetSystemMetrics(SM_CYCAPTION), + NULL, NULL, hInstanceMain, NULL); + } + + // init DDB implementation + hDC_comp=CreateCompatibleDC(NULL); + InitImageBuffer(); + + ShowWindow(hWndMain, SW_SHOW); + + ddrawkit_initialised=true; + ddrawkit_released=false; + + // Clear screen + ddkLock(); + for(int y=0;y@AdWd&0mBGUeq8?2d zTo5jfECOM}&4h3vBwP^Az!ZmwKuEYUH1{Bj!=y6j7N%iL$G=Q zVlteBmaYL8n_fh9L|L^aEU{r7@`cK291PBp(%q1!d2quLX<(&z)565 z2%8xHLbT&jk0}l}6QU8~3%DR$JuU`B7p8i+I9v)M0yiIGAVd(thLaFMI0+X=HVRV^ zE(?)@Xos-Tq%gT~5r{4biKZ7#5H1U6z`X`h2_fOKRA&%xK3pZ7L5zPP4u)%iGvIn5 z3hJi$|8#(vmtshMevJ5WHCuJbI`bO^$>A1600m$L9B@ZVj5gMgn=dq;UbgB z$}q)|Wg%<`iL4UBhKM7RSjDjl;)-;LVz_4^hQkHn3^Z{F7e5Kni>U@p9L|L>&`7wm zsU?ofJ-Ez=tA{AS#U}!vSsx zgn_9HA`T&uWg%>25~2o~gvdffaIrCEF-4H|LS!K%R&lI?Sp5r8iJ21M;&2AUI=CU2 zTHsR1D&c|95_j&I9wT=0WkqTmq_;@8-mP+ zTS25b$jZ>nfpg&uh~aP&B92BP8wgPeQ2-H#h(JiVI94u1J)U@hNI?uiWToz(JE)uQ`&cLM-E)G!%=fW+8ix5>Xq^WQaoy zN7e`tfg1~FK*ZrBG2#$45H~~ExU{3mLfiva4B?`ggQf+I3)hP#4(Gxd5S4H)oPl2) zB8%)WhzMLeoPj0|;lfFR%5W(lD2^6f5E~)7AW{$!2ni8~u#riu;#dXYx^T&&iR0(O zO(ULxW*~CZAWK2mXe6>?G#eo*A%e(kWD&IR#8if?7{bORvFd^dLP#_%SOwA4P{Kts zA3qmQ0OFCtG!s)XL=BvT`v@We=VE1`sey1IBwRf*7nzM!0bCH%omfR6>LJD=lMrzT z2@!{|F-f>AJdHs_ASB#U2p3Lb6^9rOQ3GKklW5{_E`$NM9j*nxI9wT=0auUAK$C@Y zF&PkDnEryRge!oHKp1dwh!>E#5D{cE;cSRrWG+M_G6_)w5rMFYQ4d!G(Fk_~!~}>S zgbg9lMBrRF15Ft&aXj`yv_MFRX~-m|IHm|(JxNk<#c&4P95NV~hQLMO42ZFCE}VfZ z4iSWq@IZqoK;z<4gQg6tUbrBf0XGe+2!2_(7V0vPEk$NydJrOuoR}dZ5cd$nMplVt z4nzu#L^c!R9*6=oy>KqFdSciR(;z0p4S@^d5=S-}Surj)R`tl%!4<$65ToE+IDZbITwJ&~gn_IVnGLrKnE}xPC-JL?Cl6$0 z5H_5I7zO9T84z)})o9{yE}Vf&J;V)gWpD;WJ%kHk!|g(5K&0Tx;0!Xvk@Z5@Xe6?k u5GjZVrhDMxa49tPa0L+W!@0N^5bX>MAwi+8VV=RB{(iaz&Fco8p;Bf{XDU!?~Nilhrl4J#@VoVV{&cGu@k~t(PCeKomtiV)^ zDT2otc%(=&ha|=1SxS->n2Iq)@HhjH6iMdbQH&`?k_g;|BvG(T+zk zrW8pca7#(jMT}y&$s{o_O~#`gk77(Il0@K^lBA0m#c-2JVqlt#M>`(Hm{KH(z%3<7 z7cq+ACX>X#G#QU}Jc==;ND_ftN|G*O6vIs>iGgV{9_@G(V@i=E0=JYTUBoDcn@kb| z(_}o_@hHY4g=ruj#dxHMF^44WmhiZMmtib-OS zWDXw1c%(4hgGVtQDPqhaNjs*2a1oNs!J`5LO!weXj7N$Xb4b#TX&_vLBy;d6#v=u{3(ml!7>^WOJDh>37*hnUm?Q?KIV6d| z?ZVUrm%?P=QH&`?p$Mk!#E4MKQcQF3*p5drrWA!Dc$|SpidvRpnnRMMaK)JBP$&X7 znIr~zmSS3gX%40uxCkD_m{Jsqz%3<-L7t_UR$!WgsRk~BM=_=pg(7fENn(&^DW(;e i=3uIUi{Md=DMgk@NKmM2m}ju3zn^Y|o2QSf9s>Zag2~VT literal 0 HcmV?d00001 diff --git a/sfxr/main.cpp b/sfxr/main.cpp new file mode 100644 index 0000000..860a9d9 --- /dev/null +++ b/sfxr/main.cpp @@ -0,0 +1,1419 @@ +/* + + Porting: Search for WIN32 to find windows-specific code + snippets which need to be replaced or removed. + +*/ + +#ifdef WIN32 +#include "ddrawkit.h" +#else +#include "sdlkit.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include "DPInput.h" // WIN32 +#include "pa/portaudio.h" +#include "fileselector.h" // WIN32 +#else +#include "SDL.h" +#endif + +#define rnd(n) (rand()%(n+1)) + +#define PI 3.14159265f + +float frnd(float range) +{ + return (float)rnd(10000)/10000*range; +} + +struct Spriteset +{ + DWORD *data; + int width; + int height; + int pitch; +}; + +Spriteset font; +Spriteset ld48; + +struct Category +{ + char name[32]; +}; + +Category categories[10]; + +int wave_type; + +float p_base_freq; +float p_freq_limit; +float p_freq_ramp; +float p_freq_dramp; +float p_duty; +float p_duty_ramp; + +float p_vib_strength; +float p_vib_speed; +float p_vib_delay; + +float p_env_attack; +float p_env_sustain; +float p_env_decay; +float p_env_punch; + +bool filter_on; +float p_lpf_resonance; +float p_lpf_freq; +float p_lpf_ramp; +float p_hpf_freq; +float p_hpf_ramp; + +float p_pha_offset; +float p_pha_ramp; + +float p_repeat_speed; + +float p_arp_speed; +float p_arp_mod; + +float master_vol=0.05f; + +float sound_vol=0.5f; + + +bool playing_sample=false; +int phase; +double fperiod; +double fmaxperiod; +double fslide; +double fdslide; +int period; +float square_duty; +float square_slide; +int env_stage; +int env_time; +int env_length[3]; +float env_vol; +float fphase; +float fdphase; +int iphase; +float phaser_buffer[1024]; +int ipp; +float noise_buffer[32]; +float fltp; +float fltdp; +float fltw; +float fltw_d; +float fltdmp; +float fltphp; +float flthp; +float flthp_d; +float vib_phase; +float vib_speed; +float vib_amp; +int rep_time; +int rep_limit; +int arp_time; +int arp_limit; +double arp_mod; + +float* vselected=NULL; +int vcurbutton=-1; + +int wav_bits=16; +int wav_freq=44100; + +int file_sampleswritten; +float filesample=0.0f; +int fileacc=0; + +float* lastChanged = NULL; // For undo +float undoValue = 0.0f; + +void SetUndo(float* valueptr, float oldValue) +{ + lastChanged = valueptr; + undoValue = oldValue; +} + +void Undo() +{ + if(lastChanged != NULL) + { + *lastChanged = undoValue; + lastChanged = NULL; + undoValue = 0.0f; + } +} + +void ResetParams() +{ + lastChanged = NULL; + wave_type=0; + + p_base_freq=0.3f; + p_freq_limit=0.0f; + p_freq_ramp=0.0f; + p_freq_dramp=0.0f; + p_duty=0.0f; + p_duty_ramp=0.0f; + + p_vib_strength=0.0f; + p_vib_speed=0.0f; + p_vib_delay=0.0f; + + p_env_attack=0.0f; + p_env_sustain=0.3f; + p_env_decay=0.4f; + p_env_punch=0.0f; + + filter_on=false; + p_lpf_resonance=0.0f; + p_lpf_freq=1.0f; + p_lpf_ramp=0.0f; + p_hpf_freq=0.0f; + p_hpf_ramp=0.0f; + + p_pha_offset=0.0f; + p_pha_ramp=0.0f; + + p_repeat_speed=0.0f; + + p_arp_speed=0.0f; + p_arp_mod=0.0f; +} + +bool LoadSettings(char* filename) +{ + lastChanged = NULL; + FILE* file=fopen(filename, "rb"); + if(!file) + return false; + + int version=0; + fread(&version, 1, sizeof(int), file); + if(version!=100 && version!=101 && version!=102) + return false; + + fread(&wave_type, 1, sizeof(int), file); + + sound_vol=0.5f; + if(version==102) + fread(&sound_vol, 1, sizeof(float), file); + + fread(&p_base_freq, 1, sizeof(float), file); + fread(&p_freq_limit, 1, sizeof(float), file); + fread(&p_freq_ramp, 1, sizeof(float), file); + if(version>=101) + fread(&p_freq_dramp, 1, sizeof(float), file); + fread(&p_duty, 1, sizeof(float), file); + fread(&p_duty_ramp, 1, sizeof(float), file); + + fread(&p_vib_strength, 1, sizeof(float), file); + fread(&p_vib_speed, 1, sizeof(float), file); + fread(&p_vib_delay, 1, sizeof(float), file); + + fread(&p_env_attack, 1, sizeof(float), file); + fread(&p_env_sustain, 1, sizeof(float), file); + fread(&p_env_decay, 1, sizeof(float), file); + fread(&p_env_punch, 1, sizeof(float), file); + + fread(&filter_on, 1, sizeof(bool), file); + fread(&p_lpf_resonance, 1, sizeof(float), file); + fread(&p_lpf_freq, 1, sizeof(float), file); + fread(&p_lpf_ramp, 1, sizeof(float), file); + fread(&p_hpf_freq, 1, sizeof(float), file); + fread(&p_hpf_ramp, 1, sizeof(float), file); + + fread(&p_pha_offset, 1, sizeof(float), file); + fread(&p_pha_ramp, 1, sizeof(float), file); + + fread(&p_repeat_speed, 1, sizeof(float), file); + + if(version>=101) + { + fread(&p_arp_speed, 1, sizeof(float), file); + fread(&p_arp_mod, 1, sizeof(float), file); + } + + fclose(file); + return true; +} + +bool SaveSettings(char* filename) +{ + FILE* file=fopen(filename, "wb"); + if(!file) + return false; + + int version=102; + fwrite(&version, 1, sizeof(int), file); + + fwrite(&wave_type, 1, sizeof(int), file); + + fwrite(&sound_vol, 1, sizeof(float), file); + + fwrite(&p_base_freq, 1, sizeof(float), file); + fwrite(&p_freq_limit, 1, sizeof(float), file); + fwrite(&p_freq_ramp, 1, sizeof(float), file); + fwrite(&p_freq_dramp, 1, sizeof(float), file); + fwrite(&p_duty, 1, sizeof(float), file); + fwrite(&p_duty_ramp, 1, sizeof(float), file); + + fwrite(&p_vib_strength, 1, sizeof(float), file); + fwrite(&p_vib_speed, 1, sizeof(float), file); + fwrite(&p_vib_delay, 1, sizeof(float), file); + + fwrite(&p_env_attack, 1, sizeof(float), file); + fwrite(&p_env_sustain, 1, sizeof(float), file); + fwrite(&p_env_decay, 1, sizeof(float), file); + fwrite(&p_env_punch, 1, sizeof(float), file); + + fwrite(&filter_on, 1, sizeof(bool), file); + fwrite(&p_lpf_resonance, 1, sizeof(float), file); + fwrite(&p_lpf_freq, 1, sizeof(float), file); + fwrite(&p_lpf_ramp, 1, sizeof(float), file); + fwrite(&p_hpf_freq, 1, sizeof(float), file); + fwrite(&p_hpf_ramp, 1, sizeof(float), file); + + fwrite(&p_pha_offset, 1, sizeof(float), file); + fwrite(&p_pha_ramp, 1, sizeof(float), file); + + fwrite(&p_repeat_speed, 1, sizeof(float), file); + + fwrite(&p_arp_speed, 1, sizeof(float), file); + fwrite(&p_arp_mod, 1, sizeof(float), file); + + fclose(file); + return true; +} + +void ResetSample(bool restart) +{ + if(!restart) + phase=0; + fperiod=100.0/(p_base_freq*p_base_freq+0.001); + period=(int)fperiod; + fmaxperiod=100.0/(p_freq_limit*p_freq_limit+0.001); + fslide=1.0-pow((double)p_freq_ramp, 3.0)*0.01; + fdslide=-pow((double)p_freq_dramp, 3.0)*0.000001; + square_duty=0.5f-p_duty*0.5f; + square_slide=-p_duty_ramp*0.00005f; + if(p_arp_mod>=0.0f) + arp_mod=1.0-pow((double)p_arp_mod, 2.0)*0.9; + else + arp_mod=1.0+pow((double)p_arp_mod, 2.0)*10.0; + arp_time=0; + arp_limit=(int)(pow(1.0f-p_arp_speed, 2.0f)*20000+32); + if(p_arp_speed==1.0f) + arp_limit=0; + if(!restart) + { + // reset filter + fltp=0.0f; + fltdp=0.0f; + fltw=pow(p_lpf_freq, 3.0f)*0.1f; + fltw_d=1.0f+p_lpf_ramp*0.0001f; + fltdmp=5.0f/(1.0f+pow(p_lpf_resonance, 2.0f)*20.0f)*(0.01f+fltw); + if(fltdmp>0.8f) fltdmp=0.8f; + fltphp=0.0f; + flthp=pow(p_hpf_freq, 2.0f)*0.1f; + flthp_d=1.0+p_hpf_ramp*0.0003f; + // reset vibrato + vib_phase=0.0f; + vib_speed=pow(p_vib_speed, 2.0f)*0.01f; + vib_amp=p_vib_strength*0.5f; + // reset envelope + env_vol=0.0f; + env_stage=0; + env_time=0; + env_length[0]=(int)(p_env_attack*p_env_attack*100000.0f); + env_length[1]=(int)(p_env_sustain*p_env_sustain*100000.0f); + env_length[2]=(int)(p_env_decay*p_env_decay*100000.0f); + + fphase=pow(p_pha_offset, 2.0f)*1020.0f; + if(p_pha_offset<0.0f) fphase=-fphase; + fdphase=pow(p_pha_ramp, 2.0f)*1.0f; + if(p_pha_ramp<0.0f) fdphase=-fdphase; + iphase=abs((int)fphase); + ipp=0; + for(int i=0;i<1024;i++) + phaser_buffer[i]=0.0f; + + for(int i=0;i<32;i++) + noise_buffer[i]=frnd(2.0f)-1.0f; + + rep_time=0; + rep_limit=(int)(pow(1.0f-p_repeat_speed, 2.0f)*20000+32); + if(p_repeat_speed==0.0f) + rep_limit=0; + } +} + +void PlaySample() +{ + ResetSample(false); + playing_sample=true; +} + +void SynthSample(int length, float* buffer, FILE* file) +{ + for(int i=0;i=rep_limit) + { + rep_time=0; + ResetSample(true); + } + + // frequency envelopes/arpeggios + arp_time++; + if(arp_limit!=0 && arp_time>=arp_limit) + { + arp_limit=0; + fperiod*=arp_mod; + } + fslide+=fdslide; + fperiod*=fslide; + if(fperiod>fmaxperiod) + { + fperiod=fmaxperiod; + if(p_freq_limit>0.0f) + playing_sample=false; + } + float rfperiod=fperiod; + if(vib_amp>0.0f) + { + vib_phase+=vib_speed; + rfperiod=fperiod*(1.0+sin(vib_phase)*vib_amp); + } + period=(int)rfperiod; + if(period<8) period=8; + square_duty+=square_slide; + if(square_duty<0.0f) square_duty=0.0f; + if(square_duty>0.5f) square_duty=0.5f; + // volume envelope + env_time++; + if(env_time>env_length[env_stage]) + { + env_time=0; + env_stage++; + if(env_stage==3) + playing_sample=false; + } + if(env_stage==0) + env_vol=(float)env_time/env_length[0]; + if(env_stage==1) + env_vol=1.0f+pow(1.0f-(float)env_time/env_length[1], 1.0f)*2.0f*p_env_punch; + if(env_stage==2) + env_vol=1.0f-(float)env_time/env_length[2]; + + // phaser step + fphase+=fdphase; + iphase=abs((int)fphase); + if(iphase>1023) iphase=1023; + + if(flthp_d!=0.0f) + { + flthp*=flthp_d; + if(flthp<0.00001f) flthp=0.00001f; + if(flthp>0.1f) flthp=0.1f; + } + + float ssample=0.0f; + for(int si=0;si<8;si++) // 8x supersampling + { + float sample=0.0f; + phase++; + if(phase>=period) + { +// phase=0; + phase%=period; + if(wave_type==3) + for(int i=0;i<32;i++) + noise_buffer[i]=frnd(2.0f)-1.0f; + } + // base waveform + float fp=(float)phase/period; + switch(wave_type) + { + case 0: // square + if(fp0.1f) fltw=0.1f; + if(p_lpf_freq!=1.0f) + { + fltdp+=(sample-fltp)*fltw; + fltdp-=fltdp*fltdmp; + } + else + { + fltp=sample; + fltdp=0.0f; + } + fltp+=fltdp; + // hp filter + fltphp+=fltp-pp; + fltphp-=fltphp*flthp; + sample=fltphp; + // phaser + phaser_buffer[ipp&1023]=sample; + sample+=phaser_buffer[(ipp-iphase+1024)&1023]; + ipp=(ipp+1)&1023; + // final accumulation and envelope application + ssample+=sample*env_vol; + } + ssample=ssample/8*master_vol; + + ssample*=2.0f*sound_vol; + + if(buffer!=NULL) + { + if(ssample>1.0f) ssample=1.0f; + if(ssample<-1.0f) ssample=-1.0f; + *buffer++=ssample; + } + if(file!=NULL) + { + // quantize depending on format + // accumulate/count to accomodate variable sample rate? + ssample*=4.0f; // arbitrary gain to get reasonable output volume... + if(ssample>1.0f) ssample=1.0f; + if(ssample<-1.0f) ssample=-1.0f; + filesample+=ssample; + fileacc++; + if(wav_freq==44100 || fileacc==2) + { + filesample/=fileacc; + fileacc=0; + if(wav_bits==16) + { + short isample=(short)(filesample*32000); + fwrite(&isample, 1, 2, file); + } + else + { + unsigned char isample=(unsigned char)(filesample*127+128); + fwrite(&isample, 1, 1, file); + } + filesample=0.0f; + } + file_sampleswritten++; + } + } +} + +DPInput *input; +#ifdef WIN32 +PortAudioStream *stream; +#endif +bool mute_stream; + +#ifdef WIN32 +//ancient portaudio stuff +static int AudioCallback(void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData) +{ + float *out=(float*)outputBuffer; + float *in=(float*)inputBuffer; + (void)outTime; + + if(playing_sample && !mute_stream) + SynthSample(framesPerBuffer, out, NULL); + else + for(int i=0;i 1.0) f = 1.0; + ((Sint16*)stream)[l] = (Sint16)(f * 32767); + } + } + else memset(stream, 0, len); +} +#endif + +bool ExportWAV(char* filename) +{ + FILE* foutput=fopen(filename, "wb"); + if(!foutput) + return false; + // write wav header + char string[32]; + unsigned int dword=0; + unsigned short word=0; + fwrite("RIFF", 4, 1, foutput); // "RIFF" + dword=0; + fwrite(&dword, 1, 4, foutput); // remaining file size + fwrite("WAVE", 4, 1, foutput); // "WAVE" + + fwrite("fmt ", 4, 1, foutput); // "fmt " + dword=16; + fwrite(&dword, 1, 4, foutput); // chunk size + word=1; + fwrite(&word, 1, 2, foutput); // compression code + word=1; + fwrite(&word, 1, 2, foutput); // channels + dword=wav_freq; + fwrite(&dword, 1, 4, foutput); // sample rate + dword=wav_freq*wav_bits/8; + fwrite(&dword, 1, 4, foutput); // bytes/sec + word=wav_bits/8; + fwrite(&word, 1, 2, foutput); // block align + word=wav_bits; + fwrite(&word, 1, 2, foutput); // bits per sample + + fwrite("data", 4, 1, foutput); // "data" + dword=0; + int foutstream_datasize=ftell(foutput); + fwrite(&dword, 1, 4, foutput); // chunk size + + // write sample data + mute_stream=true; + file_sampleswritten=0; + filesample=0.0f; + fileacc=0; + PlaySample(); + while(playing_sample) + SynthSample(256, NULL, foutput); + mute_stream=false; + + // seek back to header and write size info + fseek(foutput, 4, SEEK_SET); + dword=0; + dword=foutstream_datasize-4+file_sampleswritten*wav_bits/8; + fwrite(&dword, 1, 4, foutput); // remaining file size + fseek(foutput, foutstream_datasize, SEEK_SET); + dword=file_sampleswritten*wav_bits/8; + fwrite(&dword, 1, 4, foutput); // chunk size (data) + fclose(foutput); + + return true; +} + +#include "tools.h" + +bool firstframe=true; +int refresh_counter=0; +bool dragOnLeftClick = false; + +bool Slider(int x, int y, float& value, bool bipolar, const char* text) +{ + bool result = false; + if(MouseInBox(x, y, 100, 10)) + { + if(mouse_rightclick) + { + value=0.0f; + result = true; + } + if(mouse_leftclick) + { + if(dragOnLeftClick) + vselected=&value; + else + { + if(bipolar) + value = (mouse_x - x)/50.0f - 1.0f; + else + value = (mouse_x - x)/100.0f; + result = true; + } + } + } + float mv=(float)(mouse_x-mouse_px); + if(vselected!=&value) + mv=0.0f; + if(bipolar) + { + value+=mv*0.005f; + if(value<-1.0f) value=-1.0f; + if(value>1.0f) value=1.0f; + } + else + { + value+=mv*0.0025f; + if(value<0.0f) value=0.0f; + if(value>1.0f) value=1.0f; + } + DrawBar(x-1, y, 102, 10, 0x000000); + int ival=(int)(value*99); + if(bipolar) + ival=(int)(value*49.5f+49.5f); + DrawBar(x, y+1, ival, 8, 0xF0C090); + DrawBar(x+ival, y+1, 100-ival, 8, 0x807060); + DrawBar(x+ival, y+1, 1, 8, 0xFFFFFF); + if(bipolar) + { + DrawBar(x+50, y-1, 1, 3, 0x000000); + DrawBar(x+50, y+8, 1, 3, 0x000000); + } + DWORD tcol=0x000000; + if(wave_type!=0 && (&value==&p_duty || &value==&p_duty_ramp)) + tcol=0x808080; + DrawText(x-4-strlen(text)*8, y+1, tcol, text); + return result; +} + +bool Button(int x, int y, bool highlight, const char* text, int id) +{ + DWORD color1=0x000000; + DWORD color2=0xA09088; + DWORD color3=0x000000; + bool hover=MouseInBox(x, y, 100, 17); + if(hover && mouse_leftclick) + vcurbutton=id; + bool current=(vcurbutton==id); + if(highlight) + { + color1=0x000000; + color2=0x988070; + color3=0xFFF0E0; + } + if(current && hover) + { + color1=0xA09088; + color2=0xFFF0E0; + color3=0xA09088; + } + DrawBar(x-1, y-1, 102, 19, color1); + DrawBar(x, y, 100, 17, color2); + DrawText(x+5, y+5, color3, text); + if(current && hover && !mouse_left) + return true; + return false; +} + +bool ButtonWH(int x, int y, int w, int h, bool highlight, const char* text, int id) +{ + DWORD color1=0x000000; + DWORD color2=0xA09088; + DWORD color3=0x000000; + bool hover=MouseInBox(x, y, w, h); + if(hover && mouse_leftclick) + vcurbutton=id; + bool current=(vcurbutton==id); + if(highlight) + { + color1=0x000000; + color2=0x988070; + color3=0xFFF0E0; + } + if(current && hover) + { + color1=0xA09088; + color2=0xFFF0E0; + color3=0xA09088; + } + DrawBar(x-1, y-1, w + 2, h + 2, color1); + DrawBar(x, y, w, h, color2); + DrawText(x+5, y+5, color3, text); + if(current && hover && !mouse_left) + return true; + return false; +} + +int drawcount=0; + +void DrawScreen() +{ + bool redraw=true; + if(!firstframe && mouse_x-mouse_px==0 && mouse_y-mouse_py==0 && !mouse_left && !mouse_right) + redraw=false; + if(!mouse_left) + { + if(vselected!=NULL || vcurbutton>-1) + { + redraw=true; + refresh_counter=2; + } + vselected=NULL; + } + if(refresh_counter>0) + { + refresh_counter--; + redraw=true; + } + + if(playing_sample) + redraw=true; + + if(drawcount++>20) + { + redraw=true; + drawcount=0; + } + + if(!redraw) + return; + + firstframe=false; + + ddkLock(); + + ClearScreen(0xC0B090); + + DrawText(10, 10, 0x504030, "GENERATOR"); + for(int i=0;i<7;i++) + { + if(Button(5, 35+i*30, false, categories[i].name, 300+i)) + { + switch(i) + { + case 0: // pickup/coin + ResetParams(); + p_base_freq=0.4f+frnd(0.5f); + p_env_attack=0.0f; + p_env_sustain=frnd(0.1f); + p_env_decay=0.1f+frnd(0.4f); + p_env_punch=0.3f+frnd(0.3f); + if(rnd(1)) + { + p_arp_speed=0.5f+frnd(0.2f); + p_arp_mod=0.2f+frnd(0.4f); + } + break; + case 1: // laser/shoot + ResetParams(); + wave_type=rnd(2); + if(wave_type==2 && rnd(1)) + wave_type=rnd(1); + p_base_freq=0.5f+frnd(0.5f); + p_freq_limit=p_base_freq-0.2f-frnd(0.6f); + if(p_freq_limit<0.2f) p_freq_limit=0.2f; + p_freq_ramp=-0.15f-frnd(0.2f); + if(rnd(2)==0) + { + p_base_freq=0.3f+frnd(0.6f); + p_freq_limit=frnd(0.1f); + p_freq_ramp=-0.35f-frnd(0.3f); + } + if(rnd(1)) + { + p_duty=frnd(0.5f); + p_duty_ramp=frnd(0.2f); + } + else + { + p_duty=0.4f+frnd(0.5f); + p_duty_ramp=-frnd(0.7f); + } + p_env_attack=0.0f; + p_env_sustain=0.1f+frnd(0.2f); + p_env_decay=frnd(0.4f); + if(rnd(1)) + p_env_punch=frnd(0.3f); + if(rnd(2)==0) + { + p_pha_offset=frnd(0.2f); + p_pha_ramp=-frnd(0.2f); + } + if(rnd(1)) + p_hpf_freq=frnd(0.3f); + break; + case 2: // explosion + ResetParams(); + wave_type=3; + if(rnd(1)) + { + p_base_freq=0.1f+frnd(0.4f); + p_freq_ramp=-0.1f+frnd(0.4f); + } + else + { + p_base_freq=0.2f+frnd(0.7f); + p_freq_ramp=-0.2f-frnd(0.2f); + } + p_base_freq*=p_base_freq; + if(rnd(4)==0) + p_freq_ramp=0.0f; + if(rnd(2)==0) + p_repeat_speed=0.3f+frnd(0.5f); + p_env_attack=0.0f; + p_env_sustain=0.1f+frnd(0.3f); + p_env_decay=frnd(0.5f); + if(rnd(1)==0) + { + p_pha_offset=-0.3f+frnd(0.9f); + p_pha_ramp=-frnd(0.3f); + } + p_env_punch=0.2f+frnd(0.6f); + if(rnd(1)) + { + p_vib_strength=frnd(0.7f); + p_vib_speed=frnd(0.6f); + } + if(rnd(2)==0) + { + p_arp_speed=0.6f+frnd(0.3f); + p_arp_mod=0.8f-frnd(1.6f); + } + break; + case 3: // powerup + ResetParams(); + if(rnd(1)) + wave_type=1; + else + p_duty=frnd(0.6f); + if(rnd(1)) + { + p_base_freq=0.2f+frnd(0.3f); + p_freq_ramp=0.1f+frnd(0.4f); + p_repeat_speed=0.4f+frnd(0.4f); + } + else + { + p_base_freq=0.2f+frnd(0.3f); + p_freq_ramp=0.05f+frnd(0.2f); + if(rnd(1)) + { + p_vib_strength=frnd(0.7f); + p_vib_speed=frnd(0.6f); + } + } + p_env_attack=0.0f; + p_env_sustain=frnd(0.4f); + p_env_decay=0.1f+frnd(0.4f); + break; + case 4: // hit/hurt + ResetParams(); + wave_type=rnd(2); + if(wave_type==2) + wave_type=3; + if(wave_type==0) + p_duty=frnd(0.6f); + p_base_freq=0.2f+frnd(0.6f); + p_freq_ramp=-0.3f-frnd(0.4f); + p_env_attack=0.0f; + p_env_sustain=frnd(0.1f); + p_env_decay=0.1f+frnd(0.2f); + if(rnd(1)) + p_hpf_freq=frnd(0.3f); + break; + case 5: // jump + ResetParams(); + wave_type=0; + p_duty=frnd(0.6f); + p_base_freq=0.3f+frnd(0.3f); + p_freq_ramp=0.1f+frnd(0.2f); + p_env_attack=0.0f; + p_env_sustain=0.1f+frnd(0.3f); + p_env_decay=0.1f+frnd(0.2f); + if(rnd(1)) + p_hpf_freq=frnd(0.3f); + if(rnd(1)) + p_lpf_freq=1.0f-frnd(0.6f); + break; + case 6: // blip/select + ResetParams(); + wave_type=rnd(1); + if(wave_type==0) + p_duty=frnd(0.6f); + p_base_freq=0.2f+frnd(0.4f); + p_env_attack=0.0f; + p_env_sustain=0.1f+frnd(0.1f); + p_env_decay=frnd(0.2f); + p_hpf_freq=0.1f; + break; + default: + break; + } + + PlaySample(); + } + } + DrawBar(110, 0, 2, 480, 0x000000); + DrawText(120, 10, 0x504030, "MANUAL SETTINGS"); + DrawSprite(ld48, 8, 440, 0, 0xB0A080); + + + bool do_play=false; + + if(Button(130, 30, wave_type==0, "SQUAREWAVE", 10)) + { + wave_type=0; + do_play=true; + } + if(Button(250, 30, wave_type==1, "SAWTOOTH", 11)) + { + wave_type=1; + do_play=true; + } + if(Button(370, 30, wave_type==2, "SINEWAVE", 12)) + { + wave_type=2; + do_play=true; + } + if(Button(490, 30, wave_type==3, "NOISE", 13)) + { + wave_type=3; + do_play=true; + } + if(dragOnLeftClick) + { + if(ButtonWH(490, 140, 17, 17, dragOnLeftClick, "X", 101)) + dragOnLeftClick = !dragOnLeftClick; + } + else + { + if(ButtonWH(490, 140, 17, 17, dragOnLeftClick, "", 101)) + dragOnLeftClick = !dragOnLeftClick; + } + DrawText(515, 145, 0x000000, "DRAG BARS"); + + DrawBar(5-1-1, 412-1-1, 102+2, 19+2, 0x000000); + if(Button(5, 412, false, "RANDOMIZE", 40)) + { + p_base_freq=pow(frnd(2.0f)-1.0f, 2.0f); + if(rnd(1)) + p_base_freq=pow(frnd(2.0f)-1.0f, 3.0f)+0.5f; + p_freq_limit=0.0f; + p_freq_ramp=pow(frnd(2.0f)-1.0f, 5.0f); + if(p_base_freq>0.7f && p_freq_ramp>0.2f) + p_freq_ramp=-p_freq_ramp; + if(p_base_freq<0.2f && p_freq_ramp<-0.05f) + p_freq_ramp=-p_freq_ramp; + p_freq_dramp=pow(frnd(2.0f)-1.0f, 3.0f); + p_duty=frnd(2.0f)-1.0f; + p_duty_ramp=pow(frnd(2.0f)-1.0f, 3.0f); + p_vib_strength=pow(frnd(2.0f)-1.0f, 3.0f); + p_vib_speed=frnd(2.0f)-1.0f; + p_vib_delay=frnd(2.0f)-1.0f; + p_env_attack=pow(frnd(2.0f)-1.0f, 3.0f); + p_env_sustain=pow(frnd(2.0f)-1.0f, 2.0f); + p_env_decay=frnd(2.0f)-1.0f; + p_env_punch=pow(frnd(0.8f), 2.0f); + if(p_env_attack+p_env_sustain+p_env_decay<0.2f) + { + p_env_sustain+=0.2f+frnd(0.3f); + p_env_decay+=0.2f+frnd(0.3f); + } + p_lpf_resonance=frnd(2.0f)-1.0f; + p_lpf_freq=1.0f-pow(frnd(1.0f), 3.0f); + p_lpf_ramp=pow(frnd(2.0f)-1.0f, 3.0f); + if(p_lpf_freq<0.1f && p_lpf_ramp<-0.05f) + p_lpf_ramp=-p_lpf_ramp; + p_hpf_freq=pow(frnd(1.0f), 5.0f); + p_hpf_ramp=pow(frnd(2.0f)-1.0f, 5.0f); + p_pha_offset=pow(frnd(2.0f)-1.0f, 3.0f); + p_pha_ramp=pow(frnd(2.0f)-1.0f, 3.0f); + p_repeat_speed=frnd(2.0f)-1.0f; + p_arp_speed=frnd(2.0f)-1.0f; + p_arp_mod=frnd(2.0f)-1.0f; + do_play=true; + } + + if(ButtonWH(5, 352, 75, 17, false, "UNDO (Z)", 102)) + { + Undo(); + } + if(Button(5, 382, false, "MUTATE", 30)) + { + if(rnd(1)) p_base_freq+=frnd(0.1f)-0.05f; +// if(rnd(1)) p_freq_limit+=frnd(0.1f)-0.05f; + if(rnd(1)) p_freq_ramp+=frnd(0.1f)-0.05f; + if(rnd(1)) p_freq_dramp+=frnd(0.1f)-0.05f; + if(rnd(1)) p_duty+=frnd(0.1f)-0.05f; + if(rnd(1)) p_duty_ramp+=frnd(0.1f)-0.05f; + if(rnd(1)) p_vib_strength+=frnd(0.1f)-0.05f; + if(rnd(1)) p_vib_speed+=frnd(0.1f)-0.05f; + if(rnd(1)) p_vib_delay+=frnd(0.1f)-0.05f; + if(rnd(1)) p_env_attack+=frnd(0.1f)-0.05f; + if(rnd(1)) p_env_sustain+=frnd(0.1f)-0.05f; + if(rnd(1)) p_env_decay+=frnd(0.1f)-0.05f; + if(rnd(1)) p_env_punch+=frnd(0.1f)-0.05f; + if(rnd(1)) p_lpf_resonance+=frnd(0.1f)-0.05f; + if(rnd(1)) p_lpf_freq+=frnd(0.1f)-0.05f; + if(rnd(1)) p_lpf_ramp+=frnd(0.1f)-0.05f; + if(rnd(1)) p_hpf_freq+=frnd(0.1f)-0.05f; + if(rnd(1)) p_hpf_ramp+=frnd(0.1f)-0.05f; + if(rnd(1)) p_pha_offset+=frnd(0.1f)-0.05f; + if(rnd(1)) p_pha_ramp+=frnd(0.1f)-0.05f; + if(rnd(1)) p_repeat_speed+=frnd(0.1f)-0.05f; + if(rnd(1)) p_arp_speed+=frnd(0.1f)-0.05f; + if(rnd(1)) p_arp_mod+=frnd(0.1f)-0.05f; + do_play=true; + } + + DrawText(515, 170, 0x000000, "VOLUME"); + DrawBar(490-1-1+60, 180-1+5, 70, 2, 0x000000); + DrawBar(490-1-1+60+68, 180-1+5, 2, 205, 0x000000); + DrawBar(490-1-1+60, 180-1, 42+2, 10+2, 0xFF0000); + if(Slider(490, 180, sound_vol, false, " ")) + PlaySample(); + if(Button(490, 200, false, "PLAY SOUND", 20)) + PlaySample(); + + if(Button(490, 290, false, "LOAD SOUND", 14)) + { + char filename[256]; + if(FileSelectorLoad(hWndMain, filename, 1)) // WIN32 + { + ResetParams(); + LoadSettings(filename); + PlaySample(); + } + } + if(Button(490, 320, false, "SAVE SOUND", 15)) + { + char filename[256]; + if(FileSelectorSave(hWndMain, filename, 1)) // WIN32 + SaveSettings(filename); + } + + DrawBar(490-1-1+60, 380-1+9, 70, 2, 0x000000); + DrawBar(490-1-2, 380-1-2, 102+4, 19+4, 0x000000); + if(Button(490, 380, false, "EXPORT .WAV", 16)) + { + char filename[256]; + if(FileSelectorSave(hWndMain, filename, 0)) // WIN32 + ExportWAV(filename); + } + char str[10]; + sprintf(str, "%i HZ", wav_freq); + if(Button(490, 410, false, str, 18)) + { + if(wav_freq==44100) + wav_freq=22050; + else + wav_freq=44100; + } + sprintf(str, "%i-BIT", wav_bits); + if(Button(490, 440, false, str, 19)) + { + if(wav_bits==16) + wav_bits=8; + else + wav_bits=16; + } + + int ypos=4; + + int xpos=350; + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + float oldValue = 0; + + oldValue = p_env_attack; + if(Slider(xpos, (ypos++)*18, p_env_attack, false, "ATTACK TIME")) + { + do_play = true; + SetUndo(&p_env_attack, oldValue); + } + oldValue = p_env_sustain; + if(Slider(xpos, (ypos++)*18, p_env_sustain, false, "SUSTAIN TIME")) + { + do_play = true; + SetUndo(&p_env_sustain, oldValue); + } + oldValue = p_env_punch; + if(Slider(xpos, (ypos++)*18, p_env_punch, false, "SUSTAIN PUNCH")) + { + do_play = true; + SetUndo(&p_env_punch, oldValue); + } + oldValue = p_env_decay; + if(Slider(xpos, (ypos++)*18, p_env_decay, false, "DECAY TIME")) + { + do_play = true; + SetUndo(&p_env_decay, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + oldValue = p_base_freq; + if(Slider(xpos, (ypos++)*18, p_base_freq, false, "START FREQUENCY")) + { + do_play = true; + SetUndo(&p_base_freq, oldValue); + } + oldValue = p_freq_limit; + if(Slider(xpos, (ypos++)*18, p_freq_limit, false, "MIN FREQUENCY")) + { + do_play = true; + SetUndo(&p_freq_limit, oldValue); + } + oldValue = p_freq_ramp; + if(Slider(xpos, (ypos++)*18, p_freq_ramp, true, "SLIDE")) + { + do_play = true; + SetUndo(&p_freq_ramp, oldValue); + } + oldValue = p_freq_dramp; + if(Slider(xpos, (ypos++)*18, p_freq_dramp, true, "DELTA SLIDE")) + { + do_play = true; + SetUndo(&p_freq_dramp, oldValue); + } + + oldValue = p_vib_strength; + if(Slider(xpos, (ypos++)*18, p_vib_strength, false, "VIBRATO DEPTH")) + { + do_play = true; + SetUndo(&p_vib_strength, oldValue); + } + oldValue = p_vib_speed; + if(Slider(xpos, (ypos++)*18, p_vib_speed, false, "VIBRATO SPEED")) + { + do_play = true; + SetUndo(&p_vib_speed, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + oldValue = p_arp_mod; + if(Slider(xpos, (ypos++)*18, p_arp_mod, true, "CHANGE AMOUNT")) + { + do_play = true; + SetUndo(&p_arp_mod, oldValue); + } + oldValue = p_arp_speed; + if(Slider(xpos, (ypos++)*18, p_arp_speed, false, "CHANGE SPEED")) + { + do_play = true; + SetUndo(&p_arp_speed, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + oldValue = p_duty; + if(Slider(xpos, (ypos++)*18, p_duty, false, "SQUARE DUTY")) + { + do_play = true; + SetUndo(&p_duty, oldValue); + } + oldValue = p_duty_ramp; + if(Slider(xpos, (ypos++)*18, p_duty_ramp, true, "DUTY SWEEP")) + { + do_play = true; + SetUndo(&p_duty_ramp, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + oldValue = p_repeat_speed; + if(Slider(xpos, (ypos++)*18, p_repeat_speed, false, "REPEAT SPEED")) + { + do_play = true; + SetUndo(&p_repeat_speed, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + oldValue = p_pha_offset; + if(Slider(xpos, (ypos++)*18, p_pha_offset, true, "PHASER OFFSET")) + { + do_play = true; + SetUndo(&p_pha_offset, oldValue); + } + oldValue = p_pha_ramp; + if(Slider(xpos, (ypos++)*18, p_pha_ramp, true, "PHASER SWEEP")) + { + do_play = true; + SetUndo(&p_pha_ramp, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + oldValue = p_lpf_freq; + if(Slider(xpos, (ypos++)*18, p_lpf_freq, false, "LP FILTER CUTOFF")) + { + do_play = true; + SetUndo(&p_lpf_freq, oldValue); + } + oldValue = p_lpf_ramp; + if(Slider(xpos, (ypos++)*18, p_lpf_ramp, true, "LP FILTER CUTOFF SWEEP")) + { + do_play = true; + SetUndo(&p_lpf_ramp, oldValue); + } + oldValue = p_lpf_resonance; + if(Slider(xpos, (ypos++)*18, p_lpf_resonance, false, "LP FILTER RESONANCE")) + { + do_play = true; + SetUndo(&p_lpf_resonance, oldValue); + } + oldValue = p_hpf_freq; + if(Slider(xpos, (ypos++)*18, p_hpf_freq, false, "HP FILTER CUTOFF")) + { + do_play = true; + SetUndo(&p_hpf_freq, oldValue); + } + oldValue = p_hpf_ramp; + if(Slider(xpos, (ypos++)*18, p_hpf_ramp, true, "HP FILTER CUTOFF SWEEP")) + { + do_play = true; + SetUndo(&p_hpf_ramp, oldValue); + } + + DrawBar(xpos-190, ypos*18-5, 300, 2, 0x0000000); + + DrawBar(xpos-190, 4*18-5, 1, (ypos-4)*18, 0x0000000); + DrawBar(xpos-190+299, 4*18-5, 1, (ypos-4)*18, 0x0000000); + + if(do_play) + PlaySample(); + + ddkUnlock(); + + if(!mouse_left) + vcurbutton=-1; +} + +bool keydown=false; + +bool ddkCalcFrame() +{ + input->Update(); // WIN32 (for keyboard input) + + if(input->KeyPressed(DIK_SPACE) || input->KeyPressed(DIK_RETURN)) // WIN32 (keyboard input only for convenience, ok to remove) + { + if(!keydown) + { + PlaySample(); + keydown=true; + } + } + else if(input->KeyPressed(DIK_Z)) + { + Undo(); + keydown=true; + } + else + keydown=false; + + DrawScreen(); + + Sleep(5); // WIN32 + return true; +} + +void ddkInit() +{ + srand(time(NULL)); + + ddkSetMode(640,480, 32, 60, DDK_WINDOW, "sfxr"); // requests window size etc from ddrawkit + + if (LoadTGA(font, "/usr/share/sfxr/font.tga")) { + /* Try again in cwd */ + if (LoadTGA(font, "font.tga")) { + fprintf(stderr, + "Error could not open /usr/share/sfxr/font.tga" + " nor font.tga\n"); + exit(1); + } + } + + if (LoadTGA(ld48, "/usr/share/sfxr/ld48.tga")) { + /* Try again in cwd */ + if (LoadTGA(ld48, "ld48.tga")) { + fprintf(stderr, + "Error could not open /usr/share/sfxr/ld48.tga" + " nor ld48.tga\n"); + exit(1); + } + } + + ld48.width=ld48.pitch; + + input=new DPInput(hWndMain, hInstanceMain); // WIN32 + + strcpy(categories[0].name, "PICKUP/COIN"); + strcpy(categories[1].name, "LASER/SHOOT"); + strcpy(categories[2].name, "EXPLOSION"); + strcpy(categories[3].name, "POWERUP"); + strcpy(categories[4].name, "HIT/HURT"); + strcpy(categories[5].name, "JUMP"); + strcpy(categories[6].name, "BLIP/SELECT"); + + ResetParams(); + +#ifdef WIN32 + // Init PortAudio + SetEnvironmentVariable("PA_MIN_LATENCY_MSEC", "75"); // WIN32 + Pa_Initialize(); + Pa_OpenDefaultStream( + &stream, + 0, + 1, + paFloat32, // output type + 44100, + 512, // samples per buffer + 0, // # of buffers + AudioCallback, + NULL); + Pa_StartStream(stream); +#else + SDL_AudioSpec des; + des.freq = 44100; + des.format = AUDIO_S16SYS; + des.channels = 1; + des.samples = 512; + des.callback = SDLAudioCallback; + des.userdata = NULL; + VERIFY(!SDL_OpenAudio(&des, NULL)); + SDL_PauseAudio(0); +#endif +} + +void ddkFree() +{ + delete input; + free(ld48.data); + free(font.data); + +#ifdef WIN32 + // Close PortAudio + Pa_StopStream(stream); + Pa_CloseStream(stream); + Pa_Terminate(); +#endif +} + diff --git a/sfxr/readme.txt b/sfxr/readme.txt new file mode 100644 index 0000000..a5b2fd6 --- /dev/null +++ b/sfxr/readme.txt @@ -0,0 +1,163 @@ +----------------------------- +sfxr - sound effect generator +----------------------------- + by DrPetter, 2007-12-14 + developed for LD48#10 +----------------------------- + + +Basic usage: + +Start the application, then hit +some of the buttons on the left +side to generate random sounds +matching the button descriptions. + +Press "Export .WAV" to save the +current sound as a WAV audio file. +Click the buttons below to change +WAV format in terms of bits per +sample and sample rate. + +If you find a sound that is sort +of interesting but not quite what +you want, you can drag some sliders +around until it sounds better. + +The Randomize button generates +something completely random. + +Mutate slightly alters the current +parameters to automatically create +a variation of the sound. + + + +Advanced usage: + +Figure out what each slider does and +use them to adjust particular aspects +of the current sound... + +Press the right mouse button on a slider +to reset it to a value of zero. + +Press Space or Enter to play the current sound. + +The Save/Load sound buttons allow saving +and loading of program parameters to work +on a sound over several sessions. + +Volume setting is saved with the sound and +exported to WAV. If you increase it too much +there's a risk of clipping. + +Some parameters influence the sound during +playback (particularly when using a non-zero +repeat speed), and dragging these sliders +can cause some interesting effects. +To record this you will need to use an external +recording application, for instance Audacity. +Set the recording source in that application +to "Wave", "Stereo Mix", "Mixed Output" or similar. + +Using an external sound editor to capture and edit +sound can also be used to string several sounds +together for more complex results. + +Parameter description: +- The top four buttons select base waveform +- First four parameters control the volume envelope + Attack is the beginning of the sound, + longer attack means a smoother start. + Sustain is how long the volume is held constant + before fading out. + Increase Sustain Punch to cause a popping + effect with increased (and falling) volume + during the sustain phase. + Decay is the fade-out time. +- Next six are for controlling the sound pitch or + frequency. + Start frequency is pretty obvious. Has a large + impact on the overall sound. + Min frequency represents a cutoff that stops all + sound if it's passed during a downward slide. + Slide sets the speed at which the frequency should + be swept (up or down). + Delta slide is the "slide of slide", or rate of change + in the slide speed. + Vibrato depth/speed makes for an oscillating + frequency effect at various strengths and rates. +- Then we have two parameters for causing an abrupt + change in pitch after a ceratin delay. + Amount is pitch change (up or down) + and Speed indicates time to wait before changing + the pitch. +- Following those are two parameters specific to the + squarewave waveform. + The duty cycle of a square describes its shape + in terms of how large the positive vs negative + sections are. It can be swept up or down by + changing the second parameter. +- Repeat speed, when not zero, causes the frequency + and duty parameters to be reset at regular intervals + while the envelope and filter continue unhindered. + This can make for some interesting pulsating effects. +- Phaser offset overlays a delayed copy of the audio + stream on top of itself, resulting in a kind of tight + reverb or sci-fi effect. + This parameter can also be swept like many others. +- Finally, the bottom five sliders control two filters + which are applied after all other effects. + The first one is a resonant lowpass filter which has + a sweepable cutoff frequency. + The other is a highpass filter which can be used to + remove undesired low frequency hum in "light" sounds. + + +---------------------- + + +License +------- + +Basically, I don't care what you do with it, anything goes. + +To please all the troublesome folks who request a formal license, +I attach the "MIT license" as follows: + +-- + +Copyright (c) 2007 Tomas Pettersson + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + + +---------------------- + +http://www.drpetter.se + + drpetter@gmail.com + +---------------------- + diff --git a/sfxr/sdlkit.h b/sfxr/sdlkit.h new file mode 100644 index 0000000..df79f76 --- /dev/null +++ b/sfxr/sdlkit.h @@ -0,0 +1,174 @@ +#ifndef SDLKIT_H +#define SDLKIT_H + +#include "SDL.h" +#define ERROR(x) error(__FILE__, __LINE__, #x) +#define VERIFY(x) do { if (!(x)) ERROR(x); } while (0) +#include +#include + +static void error (const char *file, unsigned int line, const char *msg) +{ + fprintf(stderr, "[!] %s:%u %s\n", file, line, msg); + exit(1); +} + +typedef Uint32 DWORD; +typedef Uint16 WORD; + +#define DIK_SPACE SDLK_SPACE +#define DIK_RETURN SDLK_RETURN +#define DIK_Z SDLK_z +#define DDK_WINDOW 0 + +#define hWndMain 0 +#define hInstanceMain 0 + +#define Sleep(x) SDL_Delay(x) + +static bool keys[SDLK_LAST]; + +void ddkInit(); // Will be called on startup +bool ddkCalcFrame(); // Will be called every frame, return true to continue running or false to quit +void ddkFree(); // Will be called on shutdown + +class DPInput { +public: + DPInput(int,int) {} + ~DPInput() {} + static void Update () {} + + static bool KeyPressed(SDLKey key) + { + bool r = keys[key]; + keys[key] = false; + return r; + } + +}; + +static Uint32 *ddkscreen32; +static Uint16 *ddkscreen16; +static int ddkpitch; +static int mouse_x, mouse_y, mouse_px, mouse_py; +static bool mouse_left = false, mouse_right = false, mouse_middle = false; +static bool mouse_leftclick = false, mouse_rightclick = false, mouse_middleclick = false; + +static SDL_Surface *sdlscreen = NULL; + +static void sdlupdate () +{ + mouse_px = mouse_x; + mouse_py = mouse_y; + Uint8 buttons = SDL_GetMouseState(&mouse_x, &mouse_y); + bool mouse_left_p = mouse_left; + bool mouse_right_p = mouse_right; + bool mouse_middle_p = mouse_middle; + mouse_left = buttons & SDL_BUTTON(1); + mouse_right = buttons & SDL_BUTTON(3); + mouse_middle = buttons & SDL_BUTTON(2); + mouse_leftclick = mouse_left && !mouse_left_p; + mouse_rightclick = mouse_right && !mouse_right_p; + mouse_middleclick = mouse_middle && !mouse_middle_p; +} + +static bool ddkLock () +{ + SDL_LockSurface(sdlscreen); + ddkpitch = sdlscreen->pitch / (sdlscreen->format->BitsPerPixel == 32 ? 4 : 2); + ddkscreen16 = (Uint16*)(sdlscreen->pixels); + ddkscreen32 = (Uint32*)(sdlscreen->pixels); +} + +static void ddkUnlock () +{ + SDL_UnlockSurface(sdlscreen); +} + +static void ddkSetMode (int width, int height, int bpp, int refreshrate, int fullscreen, const char *title) +{ + VERIFY(sdlscreen = SDL_SetVideoMode(width, height, bpp, fullscreen ? SDL_FULLSCREEN : 0)); + SDL_WM_SetCaption(title, title); +} + +#include +#include +#include + +static char *gtkfilename; + +static void selected_file (GtkWidget *button, GtkFileSelection *fs) +{ + strncpy(gtkfilename, gtk_file_selection_get_filename(fs), 255); + gtkfilename[255] = 0; + gtk_widget_destroy(GTK_WIDGET(fs)); + gtk_main_quit(); +} + +static bool select_file (char *buf) +{ + gtkfilename = buf; + GtkWidget *dialog = gtk_file_selection_new("It's file selection time!"); + g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dialog)->ok_button), "clicked", G_CALLBACK(selected_file), G_OBJECT(dialog)); + g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(dialog)->cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(dialog)); + gtk_widget_show(GTK_WIDGET(dialog)); + gtk_main(); + return *gtkfilename; +} + +#define FileSelectorLoad(x,file,y) select_file(file) +#define FileSelectorSave(x,file,y) select_file(file) + +static void sdlquit () +{ + ddkFree(); + SDL_Quit(); +} + +static void sdlinit () +{ + SDL_Surface *icon; + VERIFY(!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)); + icon = SDL_LoadBMP("/usr/share/sfxr/sfxr.bmp"); + if (!icon) + icon = SDL_LoadBMP("sfxr.bmp"); + if (icon) + SDL_WM_SetIcon(icon, NULL); + atexit(sdlquit); + memset(keys, 0, sizeof(keys)); + ddkInit(); +} + +static void loop (void) +{ + SDL_Event e; + while (true) + { + SDL_PollEvent(&e); + switch (e.type) + { + case SDL_QUIT: + return; + + case SDL_KEYDOWN: + keys[e.key.keysym.sym] = true; + + default: break; + } + sdlupdate(); + if (!ddkCalcFrame()) + return; + SDL_Flip(sdlscreen); + } +} + +int main(int argc, char *argv[]) +{ + gtk_init(&argc, &argv); + sdlinit(); + loop(); + return 0; +} + +#endif diff --git a/sfxr/sfxr b/sfxr/sfxr new file mode 100755 index 0000000000000000000000000000000000000000..bb905c972e17662d445b0632e20d2eb25e81811d GIT binary patch literal 75274 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 literal 0 HcmV?d00001 diff --git a/sfxr/sfxr.bmp b/sfxr/sfxr.bmp new file mode 100644 index 0000000000000000000000000000000000000000..55e7d66751f7d1fcba0a85284e7d669baf341f18 GIT binary patch literal 2102 zcmZ?rHRE6a12Yx|1`P%V1_dZ)WPnPrFfa&lLofp)0|N-JU%Q@RYJU&I%`ZO~Iu@;B zuyFBUaPSXhn7s8U!?f+k7&bil%dqh1b%u`R+ZZ<9c+Ifl?0ts02QD&9-*J+mcg-FK zPHrBC3G4SWbg$gO(7j?iL&NM946TbdGZc2sV3@e^5W~z}XBbrVO&O-0{Kb%3*2Yk` z_CAAMXf8w3hKCHkk!fJ}juN9GFd6~_69RmE5+EcYA;FCmNV14YvWT&W@rX#u$jQmc z$w)ECBLfzB78ZFH0Rc{CSt&5!;E_fKOiYqYOp@{fyg20LN` zf2{H>0$c*(ERq7e%#u?Ya5aHovW0L^+56yZOc>z{7K{h_z@yp3Wk^fln`%gxS zQC@&al0|?;K#~)i|2Vku`VXWZum4zy@*gycvBxhz4;we95GOwyAGXxV%F4;YDJjh@ d&C4eu&k9LVs3emBE2{v9BnP_)BQ(LHQUIX!e*ypi literal 0 HcmV?d00001 diff --git a/sfxr/sfxr.desktop b/sfxr/sfxr.desktop new file mode 100644 index 0000000..e87f3b8 --- /dev/null +++ b/sfxr/sfxr.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=sfxr +Comment=Generate sound effects +Exec=sfxr +Icon=sfxr +Terminal=false +StartupNotify=false +Type=Application +Categories=AudioVideo;Audio;AudioVideoEditing; diff --git a/sfxr/sfxr.png b/sfxr/sfxr.png new file mode 100644 index 0000000000000000000000000000000000000000..72091198e4e5be778c6beaeeb667ad9de6396100 GIT binary patch literal 890 zcmeAS@N?(olHy`uVBq!ia0y~yU@&4}V9?-TW?*3GUK3fzz`$@Iz$e6Y{o3_C{ZoH@ zxw&dlhlh(rsK3L}t&@*!pZ533hU-TcZd=~*`o_llXIET2F!$t+>3i1n@^EwRUq4~T z%I@tex>w9@*u1!PMpxmXjT6u8nrW)9`s?JhwzAawYwL1D?H+DuN{jSmpfQjXyM3R5 zfq}EYBeIx*fx!ce-A-oPfdtD69MfSwXJEA5%F4jNc-_;*F~s8Z-l^SrYZL_9R$4EZ zvRYTWC+GC<{i*DwcPGo}AAhoBzohtL;RL&XkzqDhRx6mzyL?r#EVqKYGTeu`je*0` zdqP9x)0`ZQnbU0z7fvzs%G8{@Y~!B=jT;VpKU(#?ifh-`JgIQkT7_%*r`~qn+i)*R zo2Ay(JTbTDONBxAlE{>5{*%Y%+4X9&<+=!*Jk+;?{oJPZo)vQ!X*EBOs9_W?sHw?+ zVYtsRQIB6{fuSj@w{wq_>Y;G+yj8)fn=_4^R$MT*NOrB9GpWESQgBt`v93>LJ2tSU zy8g&~wo&N#?f3w@!ZQ*5-8F(sU(_?E?(F$g&GSd=)W(zHfqt6P1I}^pZrk*S@6@YP zlJToJ7Ox0#y+5zwf2V)f?z;Yu^E}>enSPgV^8@Xzd*0u3*VOQG8D=lnIZ%v+(n7iTF$(T+ri^v(3rZ--2sQ=Z|_`mevx`2QA z&86qrc0ck-Uw6enyleNI!k{mXx9$6%-mhM{PUX0cMRvjZ@NhdbF7ut6e#lrnJR;R{ z?M_&C?t_^zo)XqhQT%613Z4{tl|G%&tGHytk%CPdT>7p=ad_s%IBkFSVEv@cDY>&; zj>a{~U1_XiV6dp~NVL*zXJBB^s|txINiIrFEJ@W(Ni0caV5qodY-F(Ef~mN@iLmu{wEwh&>0TaZgu2mvv4FO#oum BTTB1| literal 0 HcmV?d00001 diff --git a/sfxr/tools.h b/sfxr/tools.h new file mode 100644 index 0000000..6ecf243 --- /dev/null +++ b/sfxr/tools.h @@ -0,0 +1,134 @@ +int LoadTGA(Spriteset& tiles, const char *filename) +{ + FILE *file; + unsigned char byte, crap[16], id_length; + int n, width, height, channels, x, y; + file=fopen(filename, "rb"); + if (!file) + return -1; + fread(&id_length, 1, 1, file); + fread(crap, 1, 11, file); + width=0; + height=0; + fread(&width, 1, 2, file); // width + fread(&height, 1, 2, file); // height + fread(&byte, 1, 1, file); // bits + channels=byte/8; + fread(&byte, 1, 1, file); // image descriptor byte (per-bit info) + for(n=0;n=0;y--) + for(x=0;x8) + for(x1=0;x1=x && mouse_x=y && mouse_y