klystrack-0.20171212/0000755000000000000000000000000013214501362012613 5ustar rootrootklystrack-0.20171212/klystron/0000755000000000000000000000000013214501362014500 5ustar rootrootklystrack-0.20171212/klystron/src/0000755000000000000000000000000013214501362015267 5ustar rootrootklystrack-0.20171212/klystron/src/klystron_version.h0000644000000000000000000000002513214501362021067 0ustar rootroot#include "version.h" klystrack-0.20171212/klystron/src/gui/0000755000000000000000000000000013214501362016053 5ustar rootrootklystrack-0.20171212/klystron/src/gui/slider.c0000644000000000000000000001766013214501362017513 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "slider.h" #include "gui/mouse.h" #include "gui/bevel.h" #include "dialog.h" #include "view.h" int quant(int v, int g) { return v - v % (g); } static void modify_position(void *delta, void *_param, void *unused) { SliderParam *param = _param; *param->position = quant(*param->position + CASTPTR(int,delta), param->granularity); if (*param->position < param->first) *param->position = param->first; if (*param->position > param->last - param->margin) *param->position = param->last - param->margin; } static void drag_motion(int x, int y, void *_param) { SliderParam *param = _param; if ((param->visible_first <= param->first && param->visible_last >= param->last) || param->drag_area_size == 0) return; int delta = (param->orientation == SLIDER_HORIZONTAL ? x : y) - param->drag_begin_coordinate; *param->position = quant(param->drag_begin_position + delta * (param->last - param->first) / param->drag_area_size, param->granularity); if (*param->position > param->last - param->margin) *param->position = param->last - param->margin; if (*param->position < param->first) *param->position = param->first; } static void drag_begin(void *event, void *_param, void *area) { set_motion_target(drag_motion, _param); SliderParam *param = _param; param->drag_begin_coordinate = param->orientation == SLIDER_HORIZONTAL ? ((SDL_Event*)event)->button.x : ((SDL_Event*)event)->button.y; param->drag_begin_position = *param->position; if (param->drag_begin_position > param->last - param->margin) param->drag_begin_position = param->last - param->margin; if (param->drag_begin_position < param->first) param->drag_begin_position = param->first; param->drag_area_size = ((param->orientation == SLIDER_HORIZONTAL) ? ((SDL_Rect*)area)->w : ((SDL_Rect*)area)->h); } void slider(GfxDomain *dest_surface, const SDL_Rect *_area, const SDL_Event *event, void *_param) { SliderParam *param = _param; int button_size = (param->orientation == SLIDER_HORIZONTAL) ? _area->h : _area->w; int area_size = ((param->orientation == SLIDER_HORIZONTAL) ? _area->w : _area->h) - button_size * 2; int area_start = ((param->orientation == SLIDER_HORIZONTAL) ? _area->x : _area->y) + button_size; int bar_size = area_size; int bar_top = area_start; int sbsize = my_min(_area->w, _area->h); bool shrunk = false; if (param->last != param->first) { bar_top = (area_size) * param->visible_first / (param->last - param->first) + area_start; int bar_bottom = (area_size ) * param->visible_last / (param->last - param->first) + area_start; bar_size = my_min(area_size, bar_bottom - bar_top); if (bar_size < sbsize) { bar_top = (area_size - sbsize) * param->visible_first / (param->last - param->first) + area_start; bar_bottom = bar_top + sbsize; bar_size = sbsize; shrunk = true; } } SDL_Rect dragarea = { _area->x, _area->y, _area->w, _area->h }; if (param->orientation == SLIDER_HORIZONTAL) { dragarea.x += button_size; dragarea.w -= button_size * 2; } else { dragarea.y += button_size; dragarea.h -= button_size * 2; } bevel(dest_surface, &dragarea, param->gfx, BEV_SLIDER_BG); { SDL_Rect area = { _area->x, _area->y, _area->w, _area->h }; if (param->orientation == SLIDER_HORIZONTAL) { area.w = bar_top - dragarea.x; area.x = dragarea.x; } else { area.h = bar_top - dragarea.y; area.y = dragarea.y; } check_event(event, &area, modify_position, MAKEPTR(-(param->visible_last - param->visible_first)), param, 0); } { SDL_Rect area = { _area->x, _area->y, _area->w, _area->h }; if (param->orientation == SLIDER_HORIZONTAL) { area.x += bar_top - _area->x; area.w = bar_size; } else { area.y += bar_top - _area->y; area.h = bar_size; } SDL_Rect motion_area; copy_rect(&motion_area, &dragarea); if (param->orientation == SLIDER_HORIZONTAL) { motion_area.w -= bar_size; } else { motion_area.h -= bar_size; } int pressed = check_event(event, &area, drag_begin, MAKEPTR(event), param, MAKEPTR(shrunk ? &motion_area : &dragarea)); pressed |= check_drag_event(event, &area, drag_motion, MAKEPTR(param)); button(dest_surface, &area, param->gfx, pressed ? BEV_SLIDER_HANDLE_ACTIVE : BEV_SLIDER_HANDLE, (param->orientation == SLIDER_HORIZONTAL) ? DECAL_GRAB_HORIZ : DECAL_GRAB_VERT); } { SDL_Rect area = { _area->x, _area->y, _area->w, _area->h }; if (param->orientation == SLIDER_HORIZONTAL) { area.x = bar_top + bar_size; area.w = dragarea.x + dragarea.w - bar_size - bar_top; } else { area.y = bar_top + bar_size; area.h = dragarea.y + dragarea.h - bar_size - bar_top; } check_event(event, &area, modify_position, MAKEPTR(param->visible_last - param->visible_first), param, 0); } { SDL_Rect area = { _area->x, _area->y, sbsize, sbsize }; button_event(dest_surface, event, &area, param->gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, param->orientation == SLIDER_HORIZONTAL ? DECAL_LEFTARROW : DECAL_UPARROW, modify_position, MAKEPTR(-param->granularity), param, 0); if (param->orientation == SLIDER_HORIZONTAL) { area.x += area_size + button_size; } else { area.y += area_size + button_size; } button_event(dest_surface, event, &area, param->gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, param->orientation == SLIDER_HORIZONTAL ? DECAL_RIGHTARROW : DECAL_DOWNARROW, modify_position, MAKEPTR(param->granularity), param, 0); } } void slider_set_params(SliderParam *param, int first, int last, int first_visible, int last_visible, int *position, int granularity, int orientation, GfxSurface *gfx) { param->first = first; param->last = last; param->visible_first = first_visible; param->visible_last = last_visible; param->margin = (last_visible - first_visible); param->orientation = orientation; param->position = position; param->granularity = granularity; param->gfx = gfx; } void check_mouse_wheel_event(const SDL_Event *event, const SDL_Rect *rect, SliderParam *slider) { switch (event->type) { case SDL_MOUSEWHEEL: { int p = (slider->visible_last - slider->visible_first) / 2; if (event->wheel.y > 0) { *slider->position -= p; } else { *slider->position += p; } *slider->position = my_max(my_min(*slider->position, slider->last - (slider->visible_last - slider->visible_first)), slider->first); } break; } } void slider_move_position(int *cursor, int *scroll, SliderParam *param, int d) { if (*cursor + d < param->last) *cursor += d; else *cursor = param->last; if (*cursor < param->first) *cursor = param->first; if (param->visible_first > *cursor) *scroll = *cursor; if (param->visible_last < *cursor) *scroll = *cursor - (param->visible_last - param->visible_first); } klystrack-0.20171212/klystron/src/gui/menu.h0000644000000000000000000000370313214501362017173 0ustar rootroot#pragma once /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ struct menu_t { int flags; const struct menu_t *parent; const char * text; const struct menu_t *submenu; void (*action)(void*, void*, void *); void *p1, *p2, *p3; } menu_t; enum { MENU_BULLET = 1 }; #define MENU_CHECK (void*)1 #define MENU_CHECK_NOSET (void*)2 typedef struct menu_t Menu; #include "SDL.h" #include "shortcuts.h" #include "gfx/font.h" #include "gfx/gfx.h" void open_menu(const Menu *mainmenu, const Menu *action, void (*close_hook)(void), const KeyShortcut *_shortcuts, const Font *headerfont, const Font *headerfont_selected, const Font *menufont, const Font *menufont_selected, const Font *shortcutfont, const Font *shortcutfont_selected, GfxSurface *gfx); void close_menu(); void draw_menu(GfxDomain *dest, const SDL_Event *e); const Menu * get_current_menu_action(); const Menu * get_current_menu(); klystrack-0.20171212/klystron/src/gui/filebox.h0000644000000000000000000000317513214501362017662 0ustar rootroot#ifndef FILEBOX_H #define FILEBOX_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ enum { FB_CANCEL = 1, FB_OK = 2 }; enum { FB_SAVE, FB_OPEN }; #include #include "SDL.h" #include "gfx/gfx.h" #include "gfx/font.h" int filebox(const char *title, int mode, char *buffer, size_t buffer_size, const char *extension, GfxDomain *domain, GfxSurface *gfx, const Font *smallfont, const Font *largefont); void filebox_add_favorite(const char *path); void filebox_remove_favorite(const char *path); void filebox_quit(const char *path); void filebox_init(const char *path); #endif klystrack-0.20171212/klystron/src/gui/shortcuts.h0000644000000000000000000000263713214501362020272 0ustar rootroot#ifndef SHORTCUTS_H #define SHORTCUTS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" typedef struct { int mod, key; void (*action)(void*,void*,void*); void *p1, *p2, *p3; const char *description; } KeyShortcut; void do_shortcuts(SDL_KeyboardEvent *e, const KeyShortcut *shortcuts); const char * get_shortcut_string(const KeyShortcut *sc); #endif klystrack-0.20171212/klystron/src/gui/toolutil.h0000644000000000000000000000346713214501362020111 0ustar rootroot#ifndef TOOLUTIL_H #define TOOLUTIL_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "gfx/gfx.h" #include "gfx/font.h" FILE *open_dialog(const char *mode, const char *title, const char *filter, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont, const char *deffilename); char * open_dialog_fn(const char *mode, const char *title, const char *filter, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont, const char *deffilename, char *filename, int filename_size); int confirm(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *msg); int confirm_ync(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *msg); char * expand_tilde(const char * path); #endif klystrack-0.20171212/klystron/src/gui/msgbox.c0000644000000000000000000001117513214501362017523 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "msgbox.h" #include "gui/bevel.h" #include "dialog.h" #include "gfx/gfx.h" #include "view.h" #include "gui/mouse.h" static int draw_box(GfxDomain *dest, GfxSurface *gfx, const Font *font, const SDL_Event *event, const char *msg, int buttons, int *selected) { int w = 0, max_w = 200, h = font->h; for (const char *c = msg ; *c ; ++c) { w += font->w; max_w = my_max(max_w, w + 16); if (*c == '\n') { w = 0; h += font->h; } } SDL_Rect area = { dest->screen_w / 2 - max_w / 2, dest->screen_h / 2 - h / 2 - 8, max_w, h + 16 + 16 + 4 }; bevel(dest, &area, gfx, BEV_MENU); SDL_Rect content, pos; copy_rect(&content, &area); adjust_rect(&content, 8); copy_rect(&pos, &content); font_write(font, dest, &pos, msg); update_rect(&content, &pos); int b = 0; for (int i = 0 ; i < MB_BUTTON_TYPES ; ++i) if (buttons & (1 << i)) ++b; *selected = (*selected + b) % b; pos.w = 50; pos.h = 14; pos.x = content.x + content.w / 2 - b * (pos.w + ELEMENT_MARGIN) / 2 + ELEMENT_MARGIN / 2; pos.y -= 8 + 4; int r = 0; static const char *label[] = { "YES", "NO", "CANCEL", "OK" }; int idx = 0; for (int i = 0 ; i < MB_BUTTON_TYPES ; ++i) { if (buttons & (1 << i)) { int p = button_text_event(dest, event, &pos, gfx, font, BEV_BUTTON, BEV_BUTTON_ACTIVE, label[i], NULL, 0, 0, 0); if (idx == *selected) { if (event->type == SDL_KEYDOWN && (event->key.keysym.sym == SDLK_SPACE || event->key.keysym.sym == SDLK_RETURN)) p = 1; bevel(dest, &pos, gfx, BEV_CURSOR); } update_rect(&content, &pos); if (p & 1) r = (1 << i); ++idx; } } return r; } int msgbox(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *msg, int buttons) { set_repeat_timer(NULL); int selected = 0; SDL_StopTextInput(); while (1) { SDL_Event e = { 0 }; int got_event = 0; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_KEYDOWN: { switch (e.key.keysym.sym) { case SDLK_ESCAPE: if (buttons & MB_CANCEL) return MB_CANCEL; if (buttons & MB_NO) return MB_NO; return MB_OK; break; case SDLK_SPACE: case SDLK_RETURN: break; case SDLK_LEFT: --selected; break; case SDLK_RIGHT: ++selected; break; default: break; } } break; case SDL_USEREVENT: e.type = SDL_MOUSEBUTTONDOWN; break; case SDL_MOUSEMOTION: gfx_convert_mouse_coordinates(domain, &e.motion.x, &e.motion.y); gfx_convert_mouse_coordinates(domain, &e.motion.xrel, &e.motion.yrel); break; case SDL_MOUSEBUTTONDOWN: gfx_convert_mouse_coordinates(domain, &e.button.x, &e.button.y); break; case SDL_MOUSEBUTTONUP: { if (e.button.button == SDL_BUTTON_LEFT) mouse_released(&e); } break; } if (e.type != SDL_MOUSEMOTION || (e.motion.state)) ++got_event; // ensure the last event is a mouse click so it gets passed to the draw/event code if (e.type == SDL_MOUSEBUTTONDOWN || (e.type == SDL_MOUSEMOTION && e.motion.state)) break; } if (got_event || gfx_domain_is_next_frame(domain)) { int r = draw_box(domain, gfx, font, &e, msg, buttons, &selected); gfx_domain_flip(domain); set_repeat_timer(NULL); if (r) { return r; } } else SDL_Delay(5); } } klystrack-0.20171212/klystron/src/gui/shortcuts.c0000644000000000000000000000510013214501362020251 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "shortcuts.h" #include #include void do_shortcuts(SDL_KeyboardEvent *e, const KeyShortcut *shortcuts) { if (e->type != SDL_KEYDOWN) return; for (int i = 0 ; shortcuts[i].action ; ++i) { if (e->keysym.sym == shortcuts[i].key && (!(e->keysym.mod & KMOD_SHIFT) == !(shortcuts[i].mod & KMOD_SHIFT)) && (!(e->keysym.mod & KMOD_CTRL) == !(shortcuts[i].mod & KMOD_CTRL)) && (!(e->keysym.mod & KMOD_ALT) == !(shortcuts[i].mod & KMOD_ALT)) ) { shortcuts[i].action((void*)shortcuts[i].p1, (void*)shortcuts[i].p2, (void*)shortcuts[i].p3); e->keysym.sym = 0; break; } } } static const char *upcase(char *str) { for (char *c = str ; *c ; ++c) *c = toupper(*c); return str; } const char * get_shortcut_string(const KeyShortcut *sc) { static char buffer[100]; strcpy(buffer, ""); if (sc->mod & KMOD_CTRL) strncat(buffer, "ctrl-", sizeof(buffer)); if (sc->mod & KMOD_ALT) strncat(buffer, "alt-", sizeof(buffer)); if (sc->mod & KMOD_SHIFT) strncat(buffer, "shift-", sizeof(buffer)); char keyname[50] = { 0 }; if (sc->key >= SDLK_KP_DIVIDE && sc->key <= SDLK_KP_EQUALSAS400) { strncpy(keyname, SDL_GetKeyName(sc->key), 50); keyname[2] = ' '; keyname[3] = keyname[7]; keyname[4] = '\0'; keyname[0] = 'K'; keyname[1] = 'P'; } else strncpy(keyname, SDL_GetKeyName(sc->key), 3); strncat(buffer, keyname, sizeof(buffer) - 1); return upcase(buffer); } klystrack-0.20171212/klystron/src/gui/bevdefs.h0000644000000000000000000000317113214501362017644 0ustar rootroot#ifndef BEVDEFS_H #define BEVDEFS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #define BEV_SIZE 16 enum { BEV_SLIDER_BG, BEV_SLIDER_HANDLE, BEV_SLIDER_HANDLE_ACTIVE, BEV_MENUBAR, BEV_MENU, BEV_MENU_SELECTED, BEV_BUTTON, BEV_BUTTON_ACTIVE, BEV_FIELD, BEV_SEPARATOR, BEV_SELECTED_ROW, BEV_CURSOR, BEV_USER }; enum { DECAL_UPARROW, DECAL_DOWNARROW, DECAL_GRAB_VERT, DECAL_GRAB_HORIZ, DECAL_TICK, DECAL_PLUS, DECAL_MINUS, DECAL_RIGHTARROW, DECAL_LEFTARROW, DECAL_CLOSE, DECAL_FAVORITE, DECAL_UNFAVORITE, DECAL_USER, }; #endif klystrack-0.20171212/klystron/src/gui/mouse.h0000644000000000000000000000302713214501362017356 0ustar rootroot#pragma once /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" void mouse_released(const SDL_Event *event); void set_motion_target(void (*action)(int,int,void*), void *param); int check_event(const SDL_Event *event, const SDL_Rect *rect, void (*action)(void*,void*,void*), void *param1, void *param2, void *param3); int check_drag_event(const SDL_Event *event, const SDL_Rect *rect, void (*action)(int,int,void*), void *param); void set_repeat_timer(const SDL_Event *event); klystrack-0.20171212/klystron/src/gui/bevel.c0000644000000000000000000001507613214501362017325 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "bevdefs.h" #include "bevel.h" #include "view.h" #define BORDER 4 #define SIZE_MINUS_BORDER (BEV_SIZE - BORDER) void bevelex(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset, int bevel_flags) { /* Center */ if (!(bevel_flags & BEV_F_DISABLE_CENTER)) { if (!(bevel_flags & BEV_F_STRETCH_CENTER)) { for (int y = BORDER ; y < area->h - BORDER ; y += BEV_SIZE / 2) { for (int x = BORDER ; x < area->w - BORDER ; x += BEV_SIZE / 2) { SDL_Rect src = { BORDER + offset * BEV_SIZE, BORDER, my_min(BEV_SIZE / 2, area->w - x - BORDER), my_min(BEV_SIZE / 2, area->h - y - BORDER) }; SDL_Rect dest = { x + area->x, y + area->y, my_min(BEV_SIZE / 2, area->w - x - BORDER), my_min(BEV_SIZE / 2, area->h - y - BORDER) }; my_BlitSurface(gfx, &src, screen, &dest); } } } else { SDL_Rect src = { BORDER + offset * BEV_SIZE, BORDER, BEV_SIZE - 2 * BORDER, BEV_SIZE - 2 * BORDER }; SDL_Rect dest = { area->x + BORDER, area->y + BORDER, area->w - 2 * BORDER, area->h - 2 * BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } } /* Sides */ if (!(bevel_flags & BEV_F_STRETCH_BORDERS)) { for (int y = BORDER ; y < area->h - BORDER ; y += BEV_SIZE / 2) { { SDL_Rect src = { offset * BEV_SIZE, BORDER, BORDER, my_min(BEV_SIZE / 2, area->h - BORDER - y) }; SDL_Rect dest = { area->x, y + area->y, BORDER, my_min(BEV_SIZE / 2, area->h - BORDER - y) }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { SIZE_MINUS_BORDER + offset * BEV_SIZE, BORDER, BORDER, my_min(BEV_SIZE / 2, area->h - BORDER - y) }; SDL_Rect dest = { area->x + area->w - BORDER, y + area->y, BORDER, my_min(BEV_SIZE / 2, area->h - BORDER - y) }; my_BlitSurface(gfx, &src, screen, &dest); } } for (int x = BORDER ; x < area->w - BORDER ; x += BEV_SIZE / 2) { { SDL_Rect src = { BORDER + offset * BEV_SIZE, 0, my_min(BEV_SIZE / 2, area->w - BORDER - x), BORDER }; SDL_Rect dest = { area->x + x, area->y, my_min(BEV_SIZE / 2, area->w - BORDER - x), BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { BORDER + offset * BEV_SIZE, SIZE_MINUS_BORDER, my_min(BEV_SIZE / 2, area->w - BORDER - x), BORDER }; SDL_Rect dest = { x + area->x, area->y + area->h - BORDER, my_min(BEV_SIZE / 2, area->w - BORDER - x), BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } } } else { { SDL_Rect src = { offset * BEV_SIZE, BORDER, BORDER, BEV_SIZE / 2 }; SDL_Rect dest = { area->x, BORDER + area->y, BORDER, area->h - 2 * BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { SIZE_MINUS_BORDER + offset * BEV_SIZE, BORDER, BORDER, BEV_SIZE / 2 }; SDL_Rect dest = { area->x + area->w - BORDER, BORDER + area->y, BORDER, area->h - 2 * BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { BORDER + offset * BEV_SIZE, 0, BEV_SIZE / 2, BORDER }; SDL_Rect dest = { area->x + BORDER, area->y, area->w - 2 * BORDER, BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { BORDER + offset * BEV_SIZE, SIZE_MINUS_BORDER, BEV_SIZE / 2, BORDER }; SDL_Rect dest = { BORDER + area->x, area->y + area->h - BORDER, area->w - 2 * BORDER, BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } } /* Corners */ { SDL_Rect src = { offset * BEV_SIZE, 0, BORDER, BORDER }; SDL_Rect dest = { area->x, area->y, BORDER, BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { SIZE_MINUS_BORDER + offset * BEV_SIZE, 0, BORDER, BORDER }; SDL_Rect dest = { area->x + area->w - BORDER, area->y, BORDER, BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { SIZE_MINUS_BORDER + offset * BEV_SIZE, SIZE_MINUS_BORDER, BORDER, BORDER }; SDL_Rect dest = { area->x + area->w - BORDER, area->y + area->h - BORDER, BORDER, BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } { SDL_Rect src = { offset * BEV_SIZE, SIZE_MINUS_BORDER, BORDER, BORDER }; SDL_Rect dest = { area->x, area->y + area->h - BORDER, BORDER, BORDER }; my_BlitSurface(gfx, &src, screen, &dest); } } void button(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset, int decal) { bevelex(screen, area, gfx, offset, BEV_F_STRETCH_ALL); if (decal >= 0) { SDL_Rect src = { decal * BEV_SIZE, BEV_SIZE, BEV_SIZE, BEV_SIZE }; SDL_Rect dest = { area->x + area->w / 2 - BEV_SIZE / 2, area->y + area->h / 2 - BEV_SIZE / 2, BEV_SIZE, BEV_SIZE }; my_BlitSurface(gfx, &src, screen, &dest); } } void button_text(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset, const Font *font, const char *label) { bevelex(screen, area, gfx, offset, BEV_F_STRETCH_ALL); SDL_Rect dest = { area->x + area->w / 2 - font_text_width(font, label) / 2, area->y + area->h / 2 - font->h / 2, 1000, 1000 }; font_write(font, screen, &dest, label); } void separator(GfxDomain *dest, const SDL_Rect *parent, SDL_Rect *rect, GfxSurface *gfx, int offset) { while (rect->x > parent->x) update_rect(parent, rect); SDL_Rect r; copy_rect(&r, rect); rect->x = parent->x; rect->y += SEPARATOR_HEIGHT; r.y += SEPARATOR_HEIGHT/3; r.h = SEPARATOR_HEIGHT/2; r.w = parent->w; bevel(dest, &r, gfx, offset); } void bevel(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset) { bevelex(screen, area, gfx, offset, BEV_F_NORMAL); } klystrack-0.20171212/klystron/src/gui/menu.c0000644000000000000000000002077613214501362017177 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "menu.h" #include "gui/bevel.h" #include "gfx/font.h" #include "gui/view.h" #include "shortcuts.h" #include "bevdefs.h" #include #define SC_SIZE 64 enum { ZONE, DRAW }; static void (*menu_close_hook)(void) = NULL; static const Menu *current_menu = NULL; static const Menu *current_menu_action = NULL; static const KeyShortcut *shortcuts = NULL; static GfxSurface *menu_gfx = NULL; static const Font * menu_font, *shortcut_font, *header_font; static const Font * menu_font_selected, *shortcut_font_selected, *header_font_selected; void open_menu(const Menu *mainmenu, const Menu *action, void (*close_hook)(void), const KeyShortcut *_shortcuts, const Font *headerfont, const Font *headerfont_selected, const Font *menufont, const Font *menufont_selected, const Font *shortcutfont, const Font *shortcutfont_selected, GfxSurface *gfx) { current_menu = mainmenu; current_menu_action = action; menu_close_hook = close_hook; shortcuts = _shortcuts; menu_gfx = gfx; header_font = headerfont; header_font_selected = headerfont_selected; menu_font = menufont; menu_font_selected = menufont_selected; shortcut_font = shortcutfont; shortcut_font_selected = shortcutfont_selected; } const Menu * get_current_menu() { return current_menu; } const Menu * get_current_menu_action() { return current_menu_action; } void close_menu() { if (current_menu_action == NULL) { if (menu_close_hook) menu_close_hook(); } else { if (menu_close_hook) menu_close_hook(); if (current_menu_action->action == MENU_CHECK || current_menu_action->action == MENU_CHECK_NOSET) { if (current_menu_action->action == MENU_CHECK) *(int*)(current_menu_action->p1) ^= CASTPTR(int,current_menu_action->p2); if (current_menu_action->p3) ((void *(*)(void*,void*,void*))(current_menu_action->p3))(0,0,0); } else { current_menu_action->action(current_menu_action->p1, current_menu_action->p2, current_menu_action->p3); } current_menu = NULL; current_menu_action = NULL; } } static int get_menu_item_width(const Menu *item) { return strlen(item->text) + 1; } static const char * get_shortcut_key(const Menu *item) { if (!shortcuts) return NULL; for (int i = 0 ; shortcuts[i].action ; ++i) { if (((item->action == MENU_CHECK || item->action == MENU_CHECK_NOSET) && (void*)shortcuts[i].action == item->p3) || (shortcuts[i].action == item->action && (void*)shortcuts[i].p1 == item->p1 && (void*)shortcuts[i].p2 == item->p2 && (void*)shortcuts[i].p3 == item->p3)) { return get_shortcut_string(&shortcuts[i]); } else if (item->submenu) { return ""; } } return NULL; } // Below is a two-pass combined event and drawing menu routine. It is two-pass (as opposed to other combined drawing // handlers otherwhere in the project) so it can handle overlapping zones correctly. Otherwhere in the app there simply // are no overlapping zones, menus however can overlap because of the cascading submenus etc. static void draw_submenu(GfxDomain *menu_dest, const SDL_Event *event, const Menu *items, const Menu *child, SDL_Rect *child_position, int pass) { SDL_Rect area = { 0, 0, menu_dest->screen_w, shortcut_font->h + 4 + 1 }; SDL_Rect r; const Font *font = NULL; int horiz = 0; /* In short: this first iterates upwards the tree until it finds the main menu (FILE, SHOW etc.) Then it goes back level by level updating the collision/draw zones */ if (items) { if (items[0].parent != NULL) { draw_submenu(menu_dest, event, items[0].parent, items, &area, pass); font = menu_font; area.w = area.h = 0; const Menu * item = items; for (; item->text ; ++item) { area.w = my_max(get_menu_item_width(item), area.w); if (item->text[0]) area.h += font->h + 1; else area.h += SEPARATOR_HEIGHT; } area.w = area.w * font->w; area.x += 3; area.y += 4; area.w += SC_SIZE; if (area.w + area.x > menu_dest->screen_w) area.x -= area.w + area.x - menu_dest->screen_w + 2; copy_rect(&r, &area); SDL_Rect bev; copy_rect(&bev, &area); adjust_rect(&bev, -6); if (pass == DRAW) bevel(menu_dest, &bev, menu_gfx, BEV_MENU); r.h = font->h + 1; } else { if (pass == DRAW) bevel(menu_dest, &area, menu_gfx, BEV_MENUBAR); copy_rect(&r, &area); adjust_rect(&r, 2); font = header_font; horiz = 1; r.h = font->h; } const Menu * item = items; for (; item->text ; ++item) { if (item->text[0]) { if (horiz) font = header_font; else font = menu_font; const char * sc_text = get_shortcut_key(item); int bg = 0; if (horiz) r.w = font->w * get_menu_item_width(item) + 8; if (event->type == SDL_MOUSEMOTION && pass == ZONE) { if ((event->button.x >= r.x) && (event->button.y >= r.y) && (event->button.x < r.x + r.w) && (event->button.y < r.y + r.h)) { if (item->submenu) { current_menu = item->submenu; current_menu_action = NULL; bg = 1; } else if (item->action) { current_menu_action = item; current_menu = items; bg = 1; } } else if (current_menu_action && item == current_menu_action) { current_menu_action = NULL; } } if (item->submenu == child && child) { copy_rect(child_position, &r); if (horiz) child_position->y += r.h; else { child_position->x += r.w + 4; child_position->y -= 4; } bg = 1; } int selected = 0; if ((pass == DRAW) && (bg || (current_menu_action == item && current_menu_action))) { SDL_Rect bar; copy_rect(&bar, &r); adjust_rect(&bar, -1); bar.h --; bevel(menu_dest, &bar, menu_gfx, BEV_MENU_SELECTED); font = horiz ? header_font_selected : menu_font_selected; selected = 1; } if (pass == DRAW) { SDL_Rect text; copy_rect(&text, &r); text.x += font->w; text.w -= font->w; font_write(font, menu_dest, &text, item->text); char tick_char[2] = { 0 }; if ((item->action == MENU_CHECK || item->action == MENU_CHECK_NOSET) && (*(int*)item->p1 & CASTPTR(int,item->p2))) *tick_char = ''; else if (item->flags & MENU_BULLET) *tick_char = '^'; if (tick_char[0] != 0) { SDL_Rect tick; copy_rect(&tick, &r); tick.y = r.h / 2 + r.y - shortcut_font->h / 2; font_write(selected ? shortcut_font_selected : shortcut_font, menu_dest, &tick, tick_char); } } if (pass == DRAW && !horiz && sc_text) { r.x += r.w; int tmpw = r.w, tmpx = r.x, tmpy = r.y; r.w = SC_SIZE; r.x -= strlen(sc_text) * shortcut_font->w; r.y = r.h / 2 + r.y - shortcut_font->h / 2; font_write(selected ? shortcut_font_selected : shortcut_font, menu_dest, &r, sc_text); r.x = tmpx; r.y = tmpy; update_rect(&area, &r); r.w = tmpw; } else update_rect(&area, &r); } else { separator(menu_dest, &area, &r, menu_gfx, BEV_SEPARATOR); } } } } void draw_menu(GfxDomain *dest, const SDL_Event *e) { draw_submenu(dest, e, current_menu, NULL, NULL, ZONE); draw_submenu(dest, e, current_menu, NULL, NULL, DRAW); } klystrack-0.20171212/klystron/src/gui/toolutil.c0000644000000000000000000000657213214501362020104 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "toolutil.h" #include "msgbox.h" #include "filebox.h" #include #include "macros.h" #ifndef WIN32 #include #include #include #endif char * open_dialog_fn(const char *mode, const char *title, const char *filter, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont, const char *deffilename, char *filename, int filename_size) { if (deffilename) strncpy(filename, deffilename, filename_size - 1); else strcpy(filename, ""); if (filebox(title, mode[0] == 'w' ? FB_SAVE : FB_OPEN, filename, filename_size - 1, filter, domain, gfx, largefont, smallfont) == FB_OK) { return filename; } else return NULL; } FILE *open_dialog(const char *mode, const char *title, const char *filter, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont, const char *deffilename) { char filename[5000]; if (open_dialog_fn(mode, title, filter, domain, gfx, largefont, smallfont, deffilename, filename, sizeof(filename))) { FILE * f = fopen(filename, mode); if (!f) msgbox(domain, gfx, largefont, "Could not open file", MB_OK); return f; } else return NULL; } int confirm(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *msg) { return msgbox(domain, gfx, font, msg, MB_YES|MB_NO) == MB_YES; // MessageBox(0, msg, "Confirm", MB_YESNO) == IDYES; } int confirm_ync(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *msg) { int r = msgbox(domain, gfx, font, msg, MB_YES|MB_NO|MB_CANCEL); if (r == MB_YES) { return 1; } if (r == MB_NO) { return -1; } return 0; } char * expand_tilde(const char * path) { if (path[0] != '~') return NULL; #ifndef WIN32 const char *rest = strchr(path, '/'); #else const char *rest = strchr(path, '/'); if (!rest) rest = strchr(path, '\\'); #endif size_t rest_len = 0; if (rest != NULL) { rest_len = strlen(rest); } const char *homedir = NULL; #ifndef WIN32 struct passwd *pw = getpwuid(getuid()); if (pw) homedir = pw->pw_dir; #else homedir = getenv("USERPROFILE"); #endif char * final = malloc(strlen(homedir) + rest_len + 2); strcpy(final, homedir); if (rest) strcat(final, rest); return final; } klystrack-0.20171212/klystron/src/gui/filebox.c0000644000000000000000000005420113214501362017651 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "filebox.h" #include "msgbox.h" #include "gui/bevel.h" #include "gui/bevdefs.h" #include "dialog.h" #include "gfx/gfx.h" #include "gui/view.h" #include "gui/mouse.h" #include "toolutil.h" #include "slider.h" #include #include #include #include #ifdef WIN32 #include #endif #define SCROLLBAR 10 #define TOP_LEFT 0 #define TOP_RIGHT 0 #define MARGIN 8 #define SCREENMARGIN 32 #define TITLE 14 #define FIELD 14 #define CLOSE_BUTTON 12 #define PATH 10 #define ELEMWIDTH data.elemwidth #define LIST_WIDTH data.list_width #define BUTTONS 16 enum { FB_DIRECTORY, FB_FILE }; enum { FOCUS_LIST, FOCUS_FIELD }; static GfxDomain *domain; typedef struct { int type; char *name; char *display_name; } File; static struct { int mode; const char *title; File *files; int n_files; SliderParam scrollbar; int list_position, selected_file; File * picked_file; int focus; char field[256]; int editpos; int quit; char path[1024], fullpath[2048]; const Font *largefont, *smallfont; GfxSurface *gfx; int elemwidth, list_width; bool selected; } data; static char **favorites = NULL; static int n_favorites = 0; static char last_picked_file[250] = {0}; static void file_list_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void field_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void path_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static const View filebox_view[] = { {{ SCREENMARGIN, SCREENMARGIN, -SCREENMARGIN, -SCREENMARGIN }, window_view, &data, -1}, {{ MARGIN+SCREENMARGIN, SCREENMARGIN+MARGIN, -MARGIN-SCREENMARGIN, TITLE - 2 }, title_view, &data, -1}, {{ MARGIN+SCREENMARGIN, SCREENMARGIN+MARGIN + TITLE, -MARGIN-SCREENMARGIN, PATH - 2 }, path_view, &data, -1}, {{ MARGIN+SCREENMARGIN, SCREENMARGIN+MARGIN + TITLE + PATH, -MARGIN-SCREENMARGIN, FIELD - 2 }, field_view, &data, -1}, {{ -SCROLLBAR-MARGIN-SCREENMARGIN, SCREENMARGIN+MARGIN + TITLE + PATH + FIELD, SCROLLBAR, -MARGIN-SCREENMARGIN-BUTTONS }, slider, &data.scrollbar, -1}, {{ SCREENMARGIN+MARGIN, SCREENMARGIN+MARGIN + TITLE + PATH + FIELD, -SCROLLBAR-MARGIN-1-SCREENMARGIN, -MARGIN-SCREENMARGIN-BUTTONS }, file_list_view, &data, -1}, {{ SCREENMARGIN+MARGIN, -SCREENMARGIN-MARGIN-BUTTONS+2, -MARGIN-SCREENMARGIN, BUTTONS-2 }, buttons_view, &data, -1}, {{0, 0, 0, 0}, NULL} }; static void setfocus(int focus) { data.focus = focus; if (focus == FOCUS_FIELD) { SDL_StartTextInput(); } else SDL_StopTextInput(); } static void add_file(int type, const char *name) { const int block_size = 256; if ((data.n_files & (block_size - 1)) == 0) { data.files = realloc(data.files, sizeof(*data.files) * (data.n_files + block_size)); } data.files[data.n_files].type = type; data.files[data.n_files].name = strdup(name); data.files[data.n_files].display_name = malloc(strlen(name) + 4); // TODO: figure out how much this goes past strcpy(data.files[data.n_files].display_name, name); if (strlen(data.files[data.n_files].display_name) > LIST_WIDTH / data.largefont->w - 4) { strcpy(&data.files[data.n_files].display_name[LIST_WIDTH / data.largefont->w - 4], "..."); } ++data.n_files; } static void free_files() { if (data.files) { for (int i = 0 ; i < data.n_files ; ++i) { free(data.files[i].name); free(data.files[i].display_name); } free(data.files); } data.files = NULL; data.n_files = 0; data.list_position = 0; } static int file_sorter(const void *_left, const void *_right) { // directories come before files, otherwise case-insensitive name sorting const File *left = _left; const File *right = _right; if (left->type == right->type) { return strcasecmp(left->name, right->name); } else { return left->type > right->type ? 1 : -1; } } #ifdef WIN32 static void enumerate_drives() { char buffer[1024] = {0}; if (GetLogicalDriveStrings(sizeof(buffer)-1, buffer)) { free_files(); char *p = buffer; while (*p) { add_file(FB_DIRECTORY, p); p = &p[strlen(p) + 1]; } debug("Got %d drives", data.n_files); data.selected_file = -1; data.list_position = 0; data.editpos = 0; qsort(data.files, data.n_files, sizeof(*data.files), file_sorter); } } static void show_drives_action(void *unused0, void *unused1, void *unused2) { enumerate_drives(); } #endif static void parent_action(void *unused0, void *unused1, void *unused2) { static File parent = {FB_DIRECTORY, "..", ".."}; data.picked_file = &parent; } static void show_favorites_action(void *unused0, void *unused1, void *unused2) { free_files(); for (int i = 0 ; i < n_favorites ;++i) add_file(FB_DIRECTORY, favorites[i]); } bool filebox_is_favorite(const char *path) { for (int i = 0 ; i < n_favorites ;++i) if (strcmp(favorites[i], path) == 0) return true; return false; } void filebox_add_favorite(const char *path) { if (filebox_is_favorite(path)) return; favorites = realloc(favorites, (n_favorites + 1) * sizeof(char*)); favorites[n_favorites] = strdup(path); ++n_favorites; } void filebox_remove_favorite(const char *path) { for (int i = 0 ; i < n_favorites ;++i) if (strcmp(favorites[i], path) == 0) { free(favorites[i]); if (n_favorites > 1) { memmove(favorites + i, favorites + i + 1, sizeof(char*) * (n_favorites - i - 1)); } --n_favorites; return; } } void filebox_init(const char *path) { debug("Loading filebox favorites (%s)", path); FILE *f = fopen(path, "rt"); if (f) { while (!feof(f)) { char ln[1024]; if (fgets(ln, sizeof(ln), f)) { strtok(ln, "\n"); if (strlen(ln) > 0) filebox_add_favorite(ln); } else break; } fclose(f); } } void filebox_quit(const char *path) { debug("Saving filebox favorites (%s)", path); FILE *f = fopen(path, "wt"); if (f) { for (int i = 0 ; i < n_favorites ; ++i) { fprintf(f, "%s\n", favorites[i]); free(favorites[i]); } fclose(f); } else { warning("Could not write favorites (%s)", path); } n_favorites = 0; free(favorites); favorites = NULL; } static void add_favorite_action(void *_path, void *unused1, void *unused2) { char *path = _path; filebox_add_favorite(path); } static void remove_favorite_action(void *_path, void *unused1, void *unused2) { char *path = _path; filebox_remove_favorite(path); } static void ok_action(void *unused0, void *unused1, void *unused2) { // Fake return keypress when field focused :) data.selected = true; } static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect button; copy_rect(&button, area); button.w = strlen("Parent") * data.smallfont->w + 12; button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "Parent", parent_action, 0, 0, 0); button.x += button.w + 1; #ifdef WIN32 button.w = strlen("Drives") * data.smallfont->w + 12; button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "Drives", show_drives_action, 0, 0, 0); button.x += button.w + 1; #endif button.w = strlen("Favorites") * data.smallfont->w + 12; button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "Favorites", show_favorites_action, 0, 0, 0); button.x += button.w + 1; button.w = strlen("OK") * data.largefont->w + 24; button.x = area->w + area->x - button.w; button_text_event(dest_surface, event, &button, data.gfx, data.largefont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "OK", ok_action, 0, 0, 0); button.x += button.w + 1; } static void pick_file_action(void *file, void *unused1, void *unused2) { if (data.focus == FOCUS_LIST && data.selected_file == CASTPTR(int,file)) data.picked_file = &data.files[CASTPTR(int,file)]; data.selected_file = CASTPTR(int,file); setfocus(FOCUS_LIST); if (data.files[data.selected_file].type == FB_FILE) { strncpy(data.field, data.files[CASTPTR(int,file)].name, sizeof(data.field)); data.editpos = strlen(data.field); } } void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { bevel(dest_surface, area, data.gfx, BEV_MENU); } void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { const char* title = data.title; SDL_Rect titlearea, button; copy_rect(&titlearea, area); titlearea.w -= CLOSE_BUTTON - 4; copy_rect(&button, area); adjust_rect(&button, titlearea.h - CLOSE_BUTTON); button.w = CLOSE_BUTTON; button.x = area->w + area->x - CLOSE_BUTTON; font_write(data.largefont, dest_surface, &titlearea, title); if (button_event(dest_surface, event, &button, data.gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_CLOSE, NULL, MAKEPTR(1), 0, 0) & 1) data.quit = 1; } void file_list_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect content, pos; copy_rect(&content, area); adjust_rect(&content, 1); copy_rect(&pos, &content); pos.h = data.largefont->h; bevel(dest_surface,area, data.gfx, BEV_FIELD); gfx_domain_set_clip(dest_surface, &content); for (int i = data.list_position ; i < data.n_files && pos.y < content.h + content.y ; ++i) { if (data.selected_file == i && data.focus == FOCUS_LIST) { bevel(dest_surface,&pos, data.gfx, BEV_SELECTED_ROW); } if (data.files[i].type == FB_FILE) font_write(data.largefont, dest_surface, &pos, data.files[i].display_name); else font_write_args(data.largefont, dest_surface, &pos, "%s", data.files[i].display_name); if (pos.y + pos.h <= content.h + content.y) slider_set_params(&data.scrollbar, 0, data.n_files - 1, data.list_position, i, &data.list_position, 1, SLIDER_VERTICAL, data.gfx); check_event(event, &pos, pick_file_action, MAKEPTR(i), 0, 0); update_rect(&content, &pos); } gfx_domain_set_clip(dest_surface, NULL); if (data.focus == FOCUS_LIST) check_mouse_wheel_event(event, area, &data.scrollbar); } void field_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect content, pos; copy_rect(&content, area); adjust_rect(&content, 1); copy_rect(&pos, &content); pos.w = data.largefont->w; pos.h = data.largefont->h; bevel(dest_surface,area, data.gfx, BEV_FIELD); if (data.focus == FOCUS_FIELD) { int i = my_max(0, data.editpos - content.w / data.largefont->w); size_t length = strlen(data.field); for ( ; data.field[i] && i < length ; ++i) { font_write_args(data.largefont, dest_surface, &pos, "%c", data.editpos == i ? '' : data.field[i]); if (check_event(event, &pos, NULL, NULL, NULL, NULL)) data.editpos = i; pos.x += pos.w; } if (data.editpos == i && i < length + 1) font_write(data.largefont, dest_surface, &pos, ""); } else { char temp[100] = ""; strncat(temp, data.field, my_min(sizeof(temp) - 1, content.w / data.largefont->w)); font_write(data.largefont, dest_surface, &content, temp); } if (check_event(event, area, NULL, 0, 0, 0)) setfocus(FOCUS_FIELD); } static void path_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect button; copy_rect(&button, area); button.w = button.h = 14; button.x = area->x; button.y -= 5; if (filebox_is_favorite(data.fullpath)) { button_event(dest_surface, event, &button, data.gfx, BEV_BUTTON_ACTIVE, BEV_BUTTON, DECAL_FAVORITE, remove_favorite_action, data.fullpath, 0, 0); } else { button_event(dest_surface, event, &button, data.gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_UNFAVORITE, add_favorite_action, data.fullpath, 0, 0); } SDL_Rect text; copy_rect(&text, area); text.x += button.w + 2; text.w -= button.w + 2; font_write(data.smallfont, dest_surface, &text, data.path); } static int checkext(const char * filename, const char *extension) { if (extension[0] == '\0') return 1; int i = strlen(filename); while (i > 0) { if (filename[i] == '.') break; --i; } if (i < 0) return 0; if (strcasecmp(&filename[i + 1], extension) == 0) return 1; #ifdef __amigaos4__ // check for old amiga-style file extensions (e.g. mod.amegas) if (i == strlen(extension) && strncasecmp(filename, extension, strlen(extension)) == 0) { return 1; } #endif return 0; } static int populate_files(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *dirname, const char *extension) { debug("Opening directory %s", dirname); char * expanded = expand_tilde(dirname); int r = chdir(expanded == NULL ? dirname : expanded); if (expanded) free(expanded); if (r) { warning("chdir failed"); return 0; } getcwd(data.fullpath, sizeof(data.fullpath) - 1); getcwd(data.path, sizeof(data.path) - 1); size_t l; if ((l = strlen(data.path)) > ELEMWIDTH / data.smallfont->w) { memmove(&data.path[3], &data.path[l - ELEMWIDTH / data.smallfont->w + 3], l + 1); memcpy(data.path, "...", 3); } DIR * dir = opendir("."); if (!dir) { msgbox(domain, gfx, font, "Could not open directory", MB_OK); return 0; } struct dirent *de = NULL; free_files(); slider_set_params(&data.scrollbar, 0, 0, 0, 0, &data.list_position, 1, SLIDER_VERTICAL, gfx); while ((de = readdir(dir)) != NULL) { struct stat attribute; if (stat(de->d_name, &attribute) != -1) { if (de->d_name[0] != '.' || strcmp(de->d_name, "..") == 0) { if ((attribute.st_mode & S_IFDIR) || checkext(de->d_name, extension)) { add_file(( attribute.st_mode & S_IFDIR ) ? FB_DIRECTORY : FB_FILE, de->d_name); } } } else { warning("stat failed for '%s'", de->d_name); } } closedir(dir); debug("Got %d files", data.n_files); data.selected_file = -1; data.list_position = 0; data.editpos = 0; qsort(data.files, data.n_files, sizeof(*data.files), file_sorter); return 1; } int filebox(const char *title, int mode, char *buffer, size_t buffer_size, const char *extension, GfxDomain *_domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont) { domain = _domain; set_repeat_timer(NULL); memset(&data, 0, sizeof(data)); data.title = title; data.mode = mode; data.picked_file = NULL; data.largefont = largefont; data.smallfont = smallfont; data.gfx = gfx; data.elemwidth = domain->screen_w - SCREENMARGIN * 2 - MARGIN * 2 - 16 - 2; data.list_width = domain->screen_w - SCREENMARGIN * 2 - MARGIN * 2 - SCROLLBAR - 2; strncpy(data.field, buffer, sizeof(data.field)); if (!populate_files(domain, gfx, largefont, ".", extension)) return FB_CANCEL; for (int i = 0 ; i < data.n_files ; ++i) { if (strcmp(data.files[i].name, last_picked_file) == 0) { data.selected_file = i; // We need to draw the view once so the slider gets visibility info SDL_Event e = {0}; draw_view(domain, filebox_view, &e); slider_move_position(&data.selected_file, &data.list_position, &data.scrollbar, 0); break; } } while (!data.quit) { if (data.picked_file) { set_repeat_timer(NULL); if (data.picked_file->type == FB_FILE) { if (mode == FB_OPEN || (mode == FB_SAVE && msgbox(domain, gfx, largefont, "Overwrite?", MB_YES|MB_NO) == MB_YES)) { strncpy(buffer, data.picked_file->name, buffer_size); strncpy(last_picked_file, data.picked_file->name, sizeof(last_picked_file)); free_files(); SDL_StopTextInput(); return FB_OK; } // note that after the populate_files() picked_file will point to some other file! // thus we need to check this before the FB_DIRECTORY handling below } else if (data.picked_file->type == FB_DIRECTORY && !populate_files(domain, gfx, largefont, data.picked_file->name, extension)) { } } data.picked_file = NULL; SDL_Event e = { 0 }; int got_event = 0; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_QUIT: set_repeat_timer(NULL); SDL_PushEvent(&e); free_files(); SDL_StopTextInput(); return FB_CANCEL; break; case SDL_KEYDOWN: { if (data.focus == FOCUS_LIST) { switch (e.key.keysym.sym) { case SDLK_ESCAPE: set_repeat_timer(NULL); free_files(); SDL_StopTextInput(); return FB_CANCEL; break; case SDLK_KP_ENTER: case SDLK_RETURN: if (data.selected_file != -1) data.picked_file = &data.files[data.selected_file]; else goto enter_pressed; break; case SDLK_DOWN: slider_move_position(&data.selected_file, &data.list_position, &data.scrollbar, 1); strncpy(data.field, data.files[data.selected_file].name, sizeof(data.field)); data.editpos = strlen(data.field); break; case SDLK_UP: slider_move_position(&data.selected_file, &data.list_position, &data.scrollbar, -1); strncpy(data.field, data.files[data.selected_file].name, sizeof(data.field)); data.editpos = strlen(data.field); break; case SDLK_TAB: setfocus(FOCUS_FIELD); break; default: break; } } else { switch (e.key.keysym.sym) { case SDLK_TAB: setfocus(FOCUS_LIST); break; } } } // fallthru case SDL_TEXTINPUT: case SDL_TEXTEDITING: if (data.focus != FOCUS_LIST) { int r = generic_edit_text(&e, data.field, sizeof(data.field) - 1, &data.editpos); if (r == 1) { data.selected = true; } else if (r == -1) { free_files(); SDL_StopTextInput(); return FB_CANCEL; } } break; case SDL_USEREVENT: e.type = SDL_MOUSEBUTTONDOWN; break; case SDL_MOUSEMOTION: if (domain) { gfx_convert_mouse_coordinates(domain, &e.motion.x, &e.motion.y); gfx_convert_mouse_coordinates(domain, &e.motion.xrel, &e.motion.yrel); } break; case SDL_MOUSEBUTTONDOWN: if (domain) { gfx_convert_mouse_coordinates(domain, &e.button.x, &e.button.y); } break; case SDL_MOUSEBUTTONUP: { if (e.button.button == SDL_BUTTON_LEFT) mouse_released(&e); } break; } if (e.type != SDL_MOUSEMOTION || (e.motion.state)) ++got_event; // ensure the last event is a mouse click so it gets passed to the draw/event code if (e.type == SDL_MOUSEBUTTONDOWN || (e.type == SDL_MOUSEMOTION && e.motion.state)) break; } if (data.selected) { enter_pressed:; struct stat attribute; char * exp = expand_tilde(data.field); int s = stat(exp ? exp : data.field, &attribute); if (s != -1) { if (!(attribute.st_mode & S_IFDIR) && mode == FB_SAVE) { if (msgbox(domain, gfx, largefont, "Overwrite?", MB_YES|MB_NO) == MB_YES) { goto exit_ok; } else data.selected = false; } else { if (attribute.st_mode & S_IFDIR) populate_files(domain, gfx, largefont, data.field, extension); else { goto exit_ok; } } } else { if (mode == FB_SAVE) { goto exit_ok; } } if (0) { exit_ok:; set_repeat_timer(NULL); strncpy(buffer, exp ? exp : data.field, buffer_size); strncpy(last_picked_file, "", sizeof(last_picked_file)); if (mode == FB_SAVE && strchr(buffer, '.') == NULL) { strncat(buffer, ".", buffer_size); strncat(buffer, extension, buffer_size); char * exp = expand_tilde(buffer); int s = stat(exp ? exp : buffer, &attribute); if (exp) free(exp); if (s != -1 && mode == FB_SAVE) { if (msgbox(domain, gfx, largefont, "Overwrite?", MB_YES|MB_NO) == MB_NO) { data.selected = false; break; } } } free_files(); if (exp) free(exp); SDL_StopTextInput(); return FB_OK; } if (exp) free(exp); } if (got_event || gfx_domain_is_next_frame(domain)) { draw_view(domain, filebox_view, &e); gfx_domain_flip(domain); } else SDL_Delay(5); } free_files(); SDL_StopTextInput(); return FB_CANCEL; } klystrack-0.20171212/klystron/src/gui/slider.h0000644000000000000000000000435513214501362017515 0ustar rootroot#ifndef SLIDER_H #define SLIDER_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gfx/gfx.h" typedef struct { // Total elements (bounds) of target int first, last; // First and last visible elements int visible_first, visible_last; // Ye int that shall be modified by the slider int *position; // Snap to this resolution int granularity; // Fixes issues with combined curson position + scroll position // I don't like this either -- but it works (in this situation) int margin; // Direction int orientation; /* internal */ int drag_begin_coordinate, drag_begin_position, drag_area_size; GfxSurface *gfx; } SliderParam; enum { SLIDER_VERTICAL, SLIDER_HORIZONTAL }; int quant(int v, int g); void slider(GfxDomain * domain, const SDL_Rect *area, const SDL_Event *event, void *param); void slider_set_params(SliderParam *param, int first, int last, int first_visible, int last_visible, int *position, int granularity, int orientation, GfxSurface *gfx); void check_mouse_wheel_event(const SDL_Event *event, const SDL_Rect *area, SliderParam *slider); void slider_move_position(int *cursor, int *scroll, SliderParam *param, int d); #endif klystrack-0.20171212/klystron/src/gui/msgbox.h0000644000000000000000000000257413214501362017533 0ustar rootroot#ifndef MSGBOX_H #define MSGBOX_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ enum { MB_YES = 1, MB_NO = 2, MB_CANCEL = 4, MB_OK = 8 }; #define MB_BUTTON_TYPES 4 #include "SDL.h" #include "gfx/gfx.h" #include "gfx/font.h" int msgbox(GfxDomain *domain, GfxSurface *gfx, const Font *font, const char *msg, int buttons); #endif klystrack-0.20171212/klystron/src/gui/view.c0000644000000000000000000000624513214501362017200 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "view.h" #include "macros.h" #include extern int event_hit; void update_rect(const SDL_Rect *parent, SDL_Rect *rect) { rect->x += rect->w + ELEMENT_MARGIN; if (rect->x + rect->w - ELEMENT_MARGIN >= parent->x + parent->w) { rect->x = parent->x; rect->y += rect->h; } } void adjust_rect(SDL_Rect *rect, int margin) { rect->x += margin; rect->y += margin; rect->w -= margin * 2; rect->h -= margin * 2; } void copy_rect(SDL_Rect *dest, const SDL_Rect *src) { memcpy(dest, src, sizeof(*dest)); } void clip_rect(SDL_Rect *rect, const SDL_Rect *limits) { int w = rect->w, h = rect->h; if (rect->x < limits->x) { w -= limits->x - rect->x; rect->x = limits->x; } if (rect->y < limits->y) { h -= limits->y - rect->y; rect->y = limits->y; } if (w + rect->x > limits->w + limits->x) { w = limits->w + limits->x - rect->x; } if (h + rect->y > limits->h + limits->y) { h = limits->h + limits->y - rect->y; } rect->w = my_max(0, w); rect->h = my_max(0, h); } void draw_view(GfxDomain *dest, const View* views, const SDL_Event *_event) { SDL_Event event; memcpy(&event, _event, sizeof(event)); for (int i = 0 ; views[i].handler ; ++i) { const View *view = &views[i]; SDL_Rect area; area.x = view->position.x >= 0 ? view->position.x : dest->screen_w + view->position.x; area.y = view->position.y >= 0 ? view->position.y : dest->screen_h + view->position.y; area.w = *(Sint16*)&view->position.w > 0 ? *(Sint16*)&view->position.w : dest->screen_w + *(Sint16*)&view->position.w - view->position.x; area.h = *(Sint16*)&view->position.h > 0 ? *(Sint16*)&view->position.h : dest->screen_h + *(Sint16*)&view->position.h - view->position.y; int iter = 0; do { event_hit = 0; view->handler(dest, &area, &event, view->param); if (event_hit) { event.type = SDL_USEREVENT + 1; ++iter; } } while (event_hit && iter <= 1); } } void center_rect(const SDL_Rect *parent, SDL_Rect *rect) { rect->x = (parent->w - rect->w) / 2; rect->y = (parent->h - rect->h) / 2; } klystrack-0.20171212/klystron/src/gui/dialog.c0000644000000000000000000001247313214501362017465 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "dialog.h" #include "gui/bevel.h" #include "gui/mouse.h" #include "gui/view.h" #include "gfx/font.h" #include "gui/bevdefs.h" #include static void flip(void *bits, void *mask, void *unused) { *CASTTOPTR(Uint32,bits) ^= CASTPTR(Uint32,mask); } int checkbox(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, const Font * font, int offset, int offset_pressed, int decal, const char* _label, Uint32 *flags, Uint32 mask) { SDL_Rect tick, label; copy_rect(&tick, area); copy_rect(&label, area); tick.h = tick.w = 8; label.w -= tick.w + 4; label.x += tick.w + 4; label.y += 1; label.h -= 1; int pressed = button_event(dest, event, &tick, gfx, offset, offset_pressed, (*flags & mask) ? decal : -1, flip, flags, MAKEPTR(mask), 0); font_write(font, dest, &label, _label); pressed |= check_event(event, &label, flip, flags, MAKEPTR(mask), 0); return pressed; } static void delegate(void *p1, void *p2, void *p3) { set_motion_target(NULL, p3); if (p1) { ((void(*)(void*,void*,void*))p1)(((void **)p2)[0], ((void **)p2)[1], ((void **)p2)[2]); } } int button_event(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, int offset, int offset_pressed, int decal, void (*action)(void*,void*,void*), void *param1, void *param2, void *param3) { Uint32 mask = ((Uint32)area->x << 16) | (Uint32)area->y | 0x80000000; void *p[3] = { param1, param2, param3 }; int pressed = check_event(event, area, delegate, action, p, MAKEPTR(mask)); pressed |= check_drag_event(event, area, NULL, MAKEPTR(mask)) << 1; button(dest, area, gfx, pressed ? offset_pressed : offset, decal); return pressed; } int button_text_event(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, const Font *font, int offset, int offset_pressed, const char * label, void (*action)(void*,void*,void*), void *param1, void *param2, void *param3) { Uint32 mask = ((Uint32)area->x << 16) | (Uint32)area->y | 0x80000000; void *p[3] = { param1, param2, param3 }; int pressed = check_event(event, area, delegate, action, p, MAKEPTR(mask)); pressed |= check_drag_event(event, area, NULL, MAKEPTR(mask)) << 1; button_text(dest, area, gfx, pressed ? offset_pressed : offset, font, label); return pressed; } int spinner(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *_area, GfxSurface *gfx, int param) { int plus, minus; SDL_Rect area; copy_rect(&area, _area); area.w /= 2; minus = button_event(dest, event, &area, gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_MINUS, NULL, MAKEPTR(0x80000000 | ((Uint32)area.x << 16 | area.y)), 0, NULL) & 1; area.x += area.w; plus = button_event(dest, event, &area, gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_PLUS, NULL, MAKEPTR(0x81000000 | ((Uint32)area.x << 16 | area.y)), 0, NULL) & 1; return plus ? +1 : (minus ? -1 : 0); } int generic_edit_text(SDL_Event *e, char *edit_buffer, size_t edit_buffer_size, int *editpos) { switch (e->type) { case SDL_TEXTINPUT: if (*editpos < (edit_buffer_size - 1) && strlen(edit_buffer) < edit_buffer_size - 1) { memmove(&edit_buffer[*editpos + 1], &edit_buffer[*editpos], edit_buffer_size - *editpos - 1); edit_buffer[*editpos] = e->text.text[0]; clamp(*editpos, +1, 0,edit_buffer_size-1); } break; case SDL_TEXTEDITING: break; case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_ESCAPE: return -1; break; case SDLK_HOME: *editpos = 0; break; case SDLK_END: *editpos = strlen(edit_buffer); break; case SDLK_KP_ENTER: case SDLK_RETURN: return 1; break; case SDLK_BACKSPACE: if (*editpos > 0) --*editpos; /* Fallthru */ case SDLK_DELETE: memmove(&edit_buffer[*editpos], &edit_buffer[*editpos + 1], edit_buffer_size - *editpos); edit_buffer[edit_buffer_size - 1] = '\0'; break; case SDLK_LEFT: { if (*editpos > 0) --*editpos; } break; case SDLK_RIGHT: { if (*editpos < strlen(edit_buffer) && *editpos < edit_buffer_size - 1) ++*editpos; } break; default: { /**/ } break; } break; } return 0; } klystrack-0.20171212/klystron/src/gui/bevel.h0000644000000000000000000000357113214501362017327 0ustar rootroot#ifndef BEVEL_H #define BEVEL_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gfx/gfx.h" #include "gfx/font.h" enum { BEV_F_NORMAL = 0, BEV_F_STRETCH_BORDERS = 1, BEV_F_STRETCH_CENTER = 2, BEV_F_DISABLE_CENTER = 4, BEV_F_STRETCH_ALL = BEV_F_STRETCH_BORDERS|BEV_F_STRETCH_CENTER }; void bevel(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset); void bevelex(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset, int bevel_flags); void button(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset, int decal); void button_text(GfxDomain *screen, const SDL_Rect *area, GfxSurface *gfx, int offset, const Font *font, const char *label); void separator(GfxDomain *dest, const SDL_Rect *parent, SDL_Rect *rect, GfxSurface *gfx, int offset); #endif klystrack-0.20171212/klystron/src/gui/view.h0000644000000000000000000000362413214501362017203 0ustar rootroot#pragma once /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #define SEPARATOR_HEIGHT 6 #define ELEMENT_MARGIN 4 #include "gfx/gfx.h" typedef struct { const SDL_Rect position; /* This is a combined drawing and mouse event handler. */ void (*handler)(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void *param; /* When clicked the focus set to the following or if the param equals -1 it will leave as it is */ int focus; } View; void draw_view(GfxDomain *dest, const View* views, const SDL_Event *event); void adjust_rect(SDL_Rect *rect, int margin); void copy_rect(SDL_Rect *dest, const SDL_Rect *src); void update_rect(const SDL_Rect *parent, SDL_Rect *rect); void clip_rect(SDL_Rect *rect, const SDL_Rect *limits); void center_rect(const SDL_Rect *parent, SDL_Rect *rect); klystrack-0.20171212/klystron/src/gui/mouse.c0000644000000000000000000000723413214501362017355 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "mouse.h" #include "macros.h" #include static void (*motion_target)(int,int,void*) = NULL; static void *motion_param = NULL; static SDL_TimerID repeat_timer_id = 0; static SDL_Event repeat_event; int event_hit = 0; Uint32 repeat_timer(Uint32 interval, void *param) { SDL_PushEvent(&repeat_event); return 0; } void set_repeat_timer(const SDL_Event *event) { if (repeat_timer_id != 0) { SDL_RemoveTimer(repeat_timer_id); } if (event) { memcpy(&repeat_event, event, sizeof(repeat_event)); repeat_event.type = SDL_USEREVENT; if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_LEFT)) repeat_timer_id = SDL_AddTimer(repeat_timer_id ? 50 : 500, repeat_timer, NULL); else set_repeat_timer(NULL); } else { repeat_timer_id = 0; } } void mouse_released(const SDL_Event *event) { if (event->button.button == SDL_BUTTON_LEFT) { set_repeat_timer(NULL); motion_target = NULL; motion_param = NULL; } } int check_event(const SDL_Event *event, const SDL_Rect *rect, void (*action)(void*,void*,void*), void *param1, void *param2, void *param3) { switch (event->type) { case SDL_MOUSEBUTTONDOWN: { if (event->button.button == SDL_BUTTON_LEFT) { if ((event->button.x >= rect->x) && (event->button.y >= rect->y) && (event->button.x < rect->x + rect->w) && (event->button.y < rect->y + rect->h)) { if (action) { event_hit = 1; set_repeat_timer(event); action(param1, param2, param3); } return 1; } } } break; } return 0; } void set_motion_target(void (*action)(int,int,void*), void *param) { motion_target = action; motion_param = param; } int check_drag_event(const SDL_Event *event, const SDL_Rect *rect, void (*action)(int,int,void*), void *param) { switch (event->type) { case SDL_MOUSEMOTION: { if (event->motion.state & (SDL_BUTTON(SDL_BUTTON_LEFT)|SDL_BUTTON(SDL_BUTTON_RIGHT))) { if (!motion_target) { int x = event->motion.x - event->motion.xrel; int y = event->motion.y - event->motion.yrel; if ((x >= rect->x) && (y >= rect->y) && (x < rect->x + rect->w) && (y < rect->y + rect->h)) { if (action) set_repeat_timer(NULL); set_motion_target(action, param); } } if (motion_target) { set_repeat_timer(NULL); motion_target(event->motion.x, event->motion.y, motion_param); } } } break; } return motion_param == param; // For identifying individual elements } klystrack-0.20171212/klystron/src/gui/dialog.h0000644000000000000000000000402113214501362017460 0ustar rootroot#pragma once /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gui/bevdefs.h" #include "gfx/font.h" int checkbox(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, const Font * font, int offset, int offset_pressed, int decal, const char* label, Uint32 *flags, Uint32 mask); int spinner(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, int param); int button_event(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, int offset, int offset_pressed, int decal, void (*action)(void*,void*,void*), void *param1, void *param2, void *param3); int button_text_event(GfxDomain *dest, const SDL_Event *event, const SDL_Rect *area, GfxSurface *gfx, const Font *font, int offset, int offset_pressed, const char *label, void (*action)(void*,void*,void*), void *param1, void *param2, void *param3); int generic_edit_text(SDL_Event *e, char *edit_buffer, size_t edit_buffer_size, int *editpos); klystrack-0.20171212/klystron/src/lib/0000755000000000000000000000000013214501362016035 5ustar rootrootklystrack-0.20171212/klystron/src/lib/ksnd.h0000644000000000000000000001610113214501362017144 0ustar rootroot#ifndef KSND_DLL_H #define KSND_DLL_H /** * @file ksnd.h * @author Tero Lindeman * @brief This is a wrapper library for simple klystrack music playback. */ #ifdef __cplusplus extern "C" { #endif /** * Song instance created by KSND_LoadSong() and KSND_LoadSongFromMemory() * * Use KSND_FreeSong() to free. */ typedef struct KSong_t KSong; /** * Player context created by KSND_CreatePlayer() and KSND_CreatePlayerUnregistered() * * Use KSND_FreePlayer() to free. */ typedef struct KPlayer_t KPlayer; /** * Song information returned by KSND_GetSongInfo() */ typedef struct { char *song_title; /**< Song title as a null-terminated string */ char *instrument_name[128]; /**< Instrument names as an array */ int n_instruments; /**< Number of instruments used by the song */ int n_channels; /**< Number of channels used by the song */ } KSongInfo; #ifdef WIN32 #ifdef DLLEXPORT #define KLYSAPI _cdecl __declspec(dllexport) #else #define KLYSAPI #endif #else #define KLYSAPI #endif /** * Loads a klystrack song file * * @param player the @c KPlayer context you will use to play the song * @param path path to the klystrack song to be loaded * @return @c KSong or @c NULL if there was an error. */ KLYSAPI extern KSong * KSND_LoadSong(KPlayer* player, const char *path); /** * Loads a klystrack song from memory * * @param player the @c KPlayer context you will use to play the song * @param[in] data pointer to data containing the song * @param data_size size of data pointed by @a data * @return @c KSong or @c NULL if there was an error. */ KLYSAPI extern KSong * KSND_LoadSongFromMemory(KPlayer* player, void *data, int data_size); /** * Free memory reserved for a @c KSong instance * * @param song song to be freed */ KLYSAPI extern void KSND_FreeSong(KSong *song); /** * Get song length measured in pattern rows */ KLYSAPI extern int KSND_GetSongLength(const KSong *song); /** * Get song information from a @c KSong. * * If @c NULL is passed as the @a data pointer, an internal, thread-unsafe buffer will * be used to store the data. This internal buffer will also change every time this * function is called, thus it is preferable to supply your own @c KSongInfo or * otherwise copy the returned data before a new call. * * If @c song is freed using KSND_FreeSong(), the corresponding @c KSongInfo may be * invalidated and point to unallocated memory. * * @param song @c KSong whose information is queried * @param[out] data pointer to a @c KSongInfo structure, or @c NULL * @return pointer to the @c KSongInfo structure passed as @a data or the internal buffer */ KLYSAPI extern const KSongInfo * KSND_GetSongInfo(KSong *song, KSongInfo *data); /** * Returns the amount of milliseconds that would need to elapse if the song was played * from the beginning to pattern row @a position. * * Use this in conjunction with KSND_GetPlayPosition() to find out the current playback * time. Or, use with KSND_GetSongLength() to get the song duration. * * @param song song whose play time is polled * @param position * @return @c position measured in milliseconds */ KLYSAPI extern int KSND_GetPlayTime(KSong *song, int position); /** * Create a @c KPlayer context and playback thread. * * After setting a @c KSong to be played with KSND_PlaySong() the song will start playing * automatically. * * @param sample_rate sample rate in Hz * @return @c KPlayer context or @c NULL if there was an error */ KLYSAPI extern KPlayer* KSND_CreatePlayer(int sample_rate); /** * Create a @c KPlayer context but don't create a playback thread. * * You will need to use KSND_FillBuffer() to request audio data manually. * * @param sample_rate sample rate in Hz * @return @c KPlayer context or @c NULL if there was an error */ KLYSAPI extern KPlayer* KSND_CreatePlayerUnregistered(int sample_rate); /** * Free a @c KPlayer context and associated memory. */ KLYSAPI extern void KSND_FreePlayer(KPlayer *player); /** * Start playing song @c song from position @c start_position (measured in pattern rows) */ KLYSAPI extern void KSND_PlaySong(KPlayer *player, KSong *song, int start_position); /** * Stop playback on a player context. */ KLYSAPI extern void KSND_Stop(KPlayer* player); /** * Pause or continue playback on a player context. * * This will pause the actual player thread so it has no effect on players created with KSND_CreatePlayerUnregistered(). * * @param player player context * @param state set pause state, value of @c 1 pauses the song and @c 0 continues playback * */ KLYSAPI extern void KSND_Pause(KPlayer *player, int state); /** * Fill a buffer of 16-bit signed integers with audio. Data will be interleaved for stereo audio. * * Use only with a @c KPlayer context created with KSND_CreatePlayerUnregistered(). * * @param player player context * @param[out] buffer buffer to be filled * @param buffer_length size of @a buffer in bytes * @return number of samples output */ KLYSAPI extern int KSND_FillBuffer(KPlayer *player, short int *buffer, int buffer_length); /** * Set player oversampling quality. * * Oversample range is [0..4]. 0 implies no oversampling and 4 implies 16-fold oversampling. * The less oversampling the less CPU intensive the playback is but the sound quality will suffer * for very high frequencies. Can be adjusted realtime. * * @param player @c KPlayer context * @param oversample oversample rate */ KLYSAPI extern void KSND_SetPlayerQuality(KPlayer *player, int oversample); /** * Set playback volume. * * @param player player context which is currently playing a song set with KSND_PlaySong() * @param volume volume [0..128] */ KLYSAPI extern void KSND_SetVolume(KPlayer *player, int volume); /** * Enable or disable song looping. * * If a non-zero value is passed via @c looping, the playback routine will exit KSND_FillBuffer() * if it encounters the song end. This is useful if you want to detect song end and avoid extra * audio data in the buffer after the song end. * * @param player player context * @param looping looping enabled */ KLYSAPI extern void KSND_SetLooping(KPlayer *player, int looping); /** * Returns current position in the song. * * @param player player context which is currently playing a song set with KSND_PlaySong() * @return current playback position measured in pattern rows */ KLYSAPI extern int KSND_GetPlayPosition(KPlayer* player); /** * Get the current envelope values for each player channel. * * Envelope values range from 0 (no audio) to 128 (full volume). * * @param player player context which is currently playing a song set with KSND_PlaySong() * @param[out] envelope array of 32-bit signed integers, should contain @c n_channel items * @param[in] n_channels get envelope values for @c n_channel first channels */ KLYSAPI extern void KSND_GetVUMeters(KPlayer *player, int *envelope, int n_channels); #ifdef __cplusplus } #endif #endif klystrack-0.20171212/klystron/src/lib/ksnd.def0000644000000000000000000000052213214501362017453 0ustar rootrootEXPORTS KSND_LoadSong KSND_LoadSongFromMemory KSND_FreeSong KSND_GetSongLength KSND_CreatePlayer KSND_CreatePlayerUnregistered KSND_SetPlayerQuality KSND_FreePlayer KSND_PlaySong KSND_FillBuffer KSND_Stop KSND_Pause KSND_GetPlayPosition KSND_SetVolume KSND_GetVUMeters KSND_GetSongInfo KSND_SetLooping KSND_GetPlayTime klystrack-0.20171212/klystron/src/lib/ksnd.c0000644000000000000000000001267013214501362017146 0ustar rootroot#include "ksnd.h" #include "snd/music.h" #include "snd/cyd.h" #include "macros.h" #include #include #include struct KSong_t { MusSong song; CydWavetableEntry wavetable_entries[CYD_WAVE_MAX_ENTRIES]; }; struct KPlayer_t { CydEngine cyd; MusEngine mus; bool cyd_registered; }; KLYSAPI KSong* KSND_LoadSong(KPlayer* player, const char *path) { KSong *song = calloc(sizeof(*song), 1); int i = 0; for (i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { cyd_wave_entry_init(&song->wavetable_entries[i], NULL, 0, 0, 0, 0, 0); } if (mus_load_song(path, &song->song, song->wavetable_entries)) { return song; } else { free(song); return NULL; } } #ifndef USESDL_RWOPS static int RWread(struct RWops *context, void *ptr, int size, int maxnum) { const int len = my_min(size * maxnum, context->mem.length - context->mem.ptr); memcpy(ptr, context->mem.base + context->mem.ptr, len); context->mem.ptr += len; return len; } static int RWclose(struct RWops *context) { free(context); return 1; } #endif KLYSAPI KSong* KSND_LoadSongFromMemory(KPlayer* player, void *data, int data_size) { #ifndef USESDL_RWOPS RWops *ops = calloc(sizeof(*ops), 1); ops->read = RWread; ops->close = RWclose; ops->mem.base = data; ops->mem.length = data_size; #else RWops *ops = SDL_RWFromMem(data, data_size); #endif KSong *song = calloc(sizeof(*song), 1); int i = 0; for (i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { cyd_wave_entry_init(&song->wavetable_entries[i], NULL, 0, 0, 0, 0, 0); } if (mus_load_song_RW(ops, &song->song, song->wavetable_entries)) { return song; } else { free(song); #ifndef USESDL_RWOPS RWclose(ops); #else SDL_RWclose(ops); #endif return NULL; } } KLYSAPI void KSND_FreeSong(KSong *song) { int i = 0; for (i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { cyd_wave_entry_init(&song->wavetable_entries[i], NULL, 0, 0, 0, 0, 0); } mus_free_song(&song->song); free(song); } KLYSAPI int KSND_GetSongLength(const KSong *song) { return song->song.song_length; } KLYSAPI KPlayer* KSND_CreatePlayer(int sample_rate) { KPlayer *player = KSND_CreatePlayerUnregistered(sample_rate); player->cyd_registered = true; #ifdef NOSDL_MIXER cyd_register(&player->cyd, 4096); #else cyd_register(&player->cyd); #endif return player; } KLYSAPI KPlayer* KSND_CreatePlayerUnregistered(int sample_rate) { KPlayer *player = malloc(sizeof(*player)); player->cyd_registered = false; cyd_init(&player->cyd, sample_rate, 1); mus_init_engine(&player->mus, &player->cyd); // Each song has its own wavetable array so let's free this free(player->cyd.wavetable_entries); player->cyd.wavetable_entries = NULL; return player; } KLYSAPI void KSND_SetPlayerQuality(KPlayer *player, int oversample) { cyd_set_oversampling(&player->cyd, oversample); } KLYSAPI void KSND_FreePlayer(KPlayer *player) { KSND_Stop(player); if (player->cyd_registered) cyd_unregister(&player->cyd); cyd_deinit(&player->cyd); free(player); } KLYSAPI void KSND_PlaySong(KPlayer *player, KSong *song, int start_position) { player->cyd.wavetable_entries = song->wavetable_entries; cyd_set_callback(&player->cyd, mus_advance_tick, &player->mus, song->song.song_rate); mus_set_fx(&player->mus, &song->song); if (song->song.num_channels > player->cyd.n_channels) cyd_reserve_channels(&player->cyd, song->song.num_channels); mus_set_song(&player->mus, &song->song, start_position); } KLYSAPI int KSND_FillBuffer(KPlayer *player, short int *buffer, int buffer_length) { #ifdef NOSDL_MIXER cyd_output_buffer_stereo(&player->cyd, (void*)buffer, buffer_length); #else cyd_output_buffer_stereo(0, buffer, buffer_length, &player->cyd); #endif return player->cyd.samples_output; } KLYSAPI void KSND_Stop(KPlayer *player) { mus_set_song(&player->mus, NULL, 0); cyd_set_callback(&player->cyd, NULL, NULL, 1); player->cyd.wavetable_entries = NULL; } KLYSAPI void KSND_Pause(KPlayer *player, int state) { cyd_pause(&player->cyd, state); } KLYSAPI int KSND_GetPlayPosition(KPlayer *player) { int song_position = 0; mus_poll_status(&player->mus, &song_position, NULL, NULL, NULL, NULL, NULL, NULL); return song_position; } KLYSAPI void KSND_SetVolume(KPlayer *player, int volume) { cyd_lock(&player->cyd, 1); player->mus.volume = volume; cyd_lock(&player->cyd, 0); } KLYSAPI void KSND_GetVUMeters(KPlayer *player, int *dest, int n_channels) { int temp[MUS_MAX_CHANNELS]; mus_poll_status(&player->mus, NULL, NULL, NULL, NULL, temp, NULL, NULL); memcpy(dest, temp, sizeof(dest[0]) * n_channels); } KLYSAPI const KSongInfo * KSND_GetSongInfo(KSong *song, KSongInfo *data) { static KSongInfo buffer; if (data == NULL) data = &buffer; data->song_title = song->song.title; data->n_instruments = song->song.num_instruments; data->n_channels = song->song.num_channels; for (int i = 0 ; i < data->n_instruments ; ++i) data->instrument_name[i] = song->song.instrument[i].name; return data; } KLYSAPI void KSND_SetLooping(KPlayer *player, int looping) { if (looping) player->mus.flags |= MUS_NO_REPEAT; else player->mus.flags &= ~MUS_NO_REPEAT; } KLYSAPI int KSND_GetPlayTime(KSong *song, int position) { return mus_get_playtime_at(&song->song, position); } klystrack-0.20171212/klystron/src/gfx/0000755000000000000000000000000013214501362016053 5ustar rootrootklystrack-0.20171212/klystron/src/gfx/gfx.c0000644000000000000000000006175313214501362017017 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include #include "gfx.h" #include #include #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #ifdef USESDL_IMAGE #include "SDL_image.h" #endif // gives the optimizer an opportunity to vectorize the second loop #define vechelper(width, block)\ {\ const int w = width & 0xffffff00;\ int x;\ for (x = 0 ; x < w ; ++x)\ {\ block;\ }\ for ( ; x < width ; ++x)\ {\ block;\ }\ } int * gfx_build_collision_mask(SDL_Surface *s) { int * mask = malloc(sizeof(int) * s->w * s->h); #if SDL_VERSION_ATLEAST(1,3,0) Uint32 key; SDL_GetColorKey(s, &key); #else const Uint32 key = s->format->colorkey; #endif my_lock(s); for (int y = 0 ; y < s->h ; ++y) { Uint8 *pa = (Uint8 *)s->pixels + y * s->pitch; for (int x = 0 ; x < s->w ; ++x) { int p = 0; switch (s->format->BytesPerPixel) { default: case 1: p = ((*((Uint8*)pa))) != key; break; case 2: p = ((*((Uint16*)pa))&0xffff) != key; break; case 3: p = ((*((Uint32*)pa))&0xffffff) != key; break; case 4: p = ((*((Uint32*)pa))&0xffffff) != key; break; } mask[x + y * s->w] = p; pa += s->format->BytesPerPixel; } } my_unlock(s); return mask; } GfxSurface* gfx_load_surface(GfxDomain *domain, const char* filename, const int flags) { SDL_RWops * rw = SDL_RWFromFile(filename, "rb"); if (rw) { GfxSurface * s = gfx_load_surface_RW(domain, rw, flags); return s; } else { warning("Opening image '%s' failed", filename); return NULL; } } GfxSurface* gfx_load_surface_RW(GfxDomain *domain, SDL_RWops *rw, const int flags) { #ifdef USESDL_IMAGE SDL_Surface* loaded = IMG_Load_RW(rw, 1); #else SDL_Surface* loaded = SDL_LoadBMP_RW(rw, 1); #endif if (!loaded) { warning("Loading surface failed: %s", SDL_GetError()); return NULL; } GfxSurface *gs = calloc(1, sizeof(GfxSurface)); if (flags & GFX_KEYED) { Uint32 c = SDL_MapRGB(loaded->format, 255, 0, 255); Uint8 r, g, b; SDL_GetRGB(c, loaded->format, &r, &g, &b); if (r == 255 && g == 0 && b == 255) SDL_SetColorKey(loaded, SDL_TRUE, c); #ifdef USESDL_GPU SDL_Surface *conv = SDL_ConvertSurfaceFormat(loaded, SDL_PIXELFORMAT_ARGB8888, 0); SDL_FreeSurface(loaded); loaded = conv; #endif } gs->surface = loaded; if (flags & GFX_COL_MASK) gs->mask = gfx_build_collision_mask(gs->surface); gs->flags = flags; gfx_update_texture(domain, gs); return gs; } void gfx_blit_2x(SDL_Surface *dest, SDL_Surface *src) { for (int y = 0 ; y < src->h ; y ++) { unsigned int *dptr1 = dest->pixels+dest->pitch*(y*2); unsigned int *dptr2 = dest->pixels+dest->pitch*(y*2+1); unsigned int *sptr = src->pixels+src->pitch*y; for (int x = src->w ; x != 0 ; --x) { *(dptr1++) = *sptr; *(dptr1++) = *sptr; *(dptr2++) = *sptr; *(dptr2++) = *(sptr++); } } } void gfx_blit_3x(SDL_Surface *dest, SDL_Surface *src) { for (int y = 0 ; y < src->h ; y ++) { unsigned int *dptr1 = dest->pixels+dest->pitch*(y*3); unsigned int *dptr2 = dest->pixels+dest->pitch*(y*3+1); unsigned int *dptr3 = dest->pixels+dest->pitch*(y*3+2); unsigned int *sptr = src->pixels+src->pitch*y; for (int x = src->w ; x != 0 ; --x) { *(dptr1++) = *sptr; *(dptr1++) = *sptr; *(dptr1++) = *sptr; *(dptr2++) = *sptr; *(dptr2++) = *sptr; *(dptr2++) = *sptr; *(dptr3++) = *sptr; *(dptr3++) = *sptr; *(dptr3++) = *(sptr++); } } } void gfx_blit_4x(SDL_Surface *dest, SDL_Surface *src) { for (int y = 0 ; y < src->h ; y ++) { unsigned int *dptr1 = dest->pixels+dest->pitch*(y*4); unsigned int *dptr2 = dest->pixels+dest->pitch*(y*4+1); unsigned int *dptr3 = dest->pixels+dest->pitch*(y*4+2); unsigned int *dptr4 = dest->pixels+dest->pitch*(y*4+3); unsigned int *sptr = src->pixels+src->pitch*y; for (int x = src->w ; x != 0 ; --x) { *(dptr1++) = *sptr; *(dptr1++) = *sptr; *(dptr1++) = *sptr; *(dptr1++) = *sptr; *(dptr2++) = *sptr; *(dptr2++) = *sptr; *(dptr2++) = *sptr; *(dptr2++) = *sptr; *(dptr3++) = *sptr; *(dptr3++) = *sptr; *(dptr3++) = *sptr; *(dptr3++) = *sptr; *(dptr4++) = *sptr; *(dptr4++) = *sptr; *(dptr4++) = *sptr; *(dptr4++) = *(sptr++); } } } void gfx_raster(SDL_Surface *dest, const SDL_Rect *rect, const Uint32 *colors, int len) { for (int y = rect ? rect->y : 0, i = 0 ; y < (rect ? rect->h+rect->y : dest->h) && i < len ; ++i, ++y) { SDL_Rect r = {rect ? rect->x : 0, y, rect ? rect->w : dest->w, 1}; SDL_FillRect(dest, &r, colors[i]); } } void gfx_generate_raster(Uint32 *dest, const Uint32 from, const Uint32 to, int len) { for (int i = 0 ; i < len ; ++i) { int from_r = ((Uint8*)&from)[0]; int from_g = ((Uint8*)&from)[1]; int from_b = ((Uint8*)&from)[2]; int to_r = ((Uint8*)&to)[0]; int to_g = ((Uint8*)&to)[1]; int to_b = ((Uint8*)&to)[2]; *(dest++) = ((from_r + (to_r-from_r) * i / len) & 0xff) | (((from_g + (to_g-from_g) * i / len) & 0xff) << 8) | (((from_b + (to_b-from_b) * i / len) & 0xff) << 16) ; } } static int has_pixels(TileDescriptor *desc) { #if SDL_VERSION_ATLEAST(1,3,0) Uint32 key; SDL_GetColorKey(desc->surface->surface, &key); #else const Uint32 key = desc->surface->surface->format->colorkey; #endif my_lock(desc->surface->surface); int result = 0; for (int y = 0 ; y < desc->rect.h && y + desc->rect.y < desc->surface->surface->h ; ++y) { Uint8 *p = (Uint8 *)desc->surface->surface->pixels + ((int)desc->rect.y + y) * desc->surface->surface->pitch + (int)desc->rect.x * desc->surface->surface->format->BytesPerPixel; for (int x = 0 ; x < desc->rect.w && x + desc->rect.x < desc->surface->surface->w ; ++x) { Uint32 c = 0; switch (desc->surface->surface->format->BytesPerPixel) { case 1: c = *((Uint8*)p); break; case 2: c = *((Uint16*)p); break; case 3: c = *((Uint8*)p) | (*((Uint16*)&p[1]) << 8); break; default: case 4: c = *((Uint32*)p); break; } if ((c & 0xffffff) != key) { ++result; } p+=desc->surface->surface->format->BytesPerPixel; } } my_unlock(desc->surface->surface); return result; } TileDescriptor *gfx_build_tiledescriptor(GfxSurface *tiles, const int cellwidth, const int cellheight, int *out_n_tiles) { TileDescriptor *descriptor = calloc(sizeof(*descriptor), (tiles->surface->w/cellwidth)*(tiles->surface->h/cellheight)); int n_tiles = 0; for (int i = 0 ; i < (tiles->surface->w/cellwidth)*(tiles->surface->h/cellheight) ; ++i) { descriptor[i].rect.x = i*cellwidth; descriptor[i].rect.y = 0; while (descriptor[i].rect.x >= tiles->surface->w) { descriptor[i].rect.y += cellheight; descriptor[i].rect.x -= tiles->surface->w; } descriptor[i].rect.w = cellwidth; descriptor[i].rect.h = cellheight; descriptor[i].surface = tiles; int pixels = has_pixels(&descriptor[i]); if (pixels == CELLSIZE*CELLSIZE || !(tiles->flags & GFX_COL_MASK)) descriptor[i].flags = TILE_COL_NORMAL; else if (pixels > 0) descriptor[i].flags = TILE_COL_PIXEL; else descriptor[i].flags = TILE_COL_DISABLE; n_tiles++; } if (out_n_tiles) *out_n_tiles = n_tiles; return descriptor; } #define SWAP(x,y) {int t = x; x = y; y=t;} static inline int delta(int e, int x, int y) { if (y == 0) return 0; return e * x / y; } void gfx_line(GfxDomain *dest, int x0, int y0, int x1, int y1, Uint32 color) { #ifdef USESDL_GPU SDL_Color c = {(color >> 16) & 255, (color >> 8) & 255, color & 255, 255}; GPU_Line(dest->screen, x0, y0, x1, y1, c); #else SDL_SetRenderDrawColor(dest->renderer, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255); SDL_RenderDrawLine(dest->renderer, x0, y0, x1, y1); #endif } static void scale2x(SDL_Surface *src, SDL_Surface *dst) { int looph, loopw; Uint8* srcpix = (Uint8*)src->pixels; Uint8* dstpix = (Uint8*)dst->pixels; const int srcpitch = src->pitch; const int dstpitch = dst->pitch; const int width = src->w; const int height = src->h; Uint32 *E0, *E1, *E2, *E3; Uint32 B, D, E, F, H; for(looph = 0; looph < height; ++looph) { E0 = (Uint32*)(dstpix + looph*2*dstpitch + 0*2*4); E1 = (Uint32*)(dstpix + looph*2*dstpitch + (0*2+1)*4); E2 = (Uint32*)(dstpix + (looph*2+1)*dstpitch + 0*2*4); E3 = (Uint32*)(dstpix + (looph*2+1)*dstpitch + (0*2+1)*4); for(loopw = 0; loopw < width; ++ loopw) { B = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*loopw)); D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_max(0,loopw-1))); E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw)); F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_min(width-1,loopw+1))); H = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*loopw)); if (B != H && D != F) { *E0 = D == B ? D : E; *E1 = B == F ? F : E; *E2 = D == H ? D : E; *E3 = H == F ? F : E; } else { *E0 = E; *E1 = E; *E2 = E; *E3 = E; } E0 += 2; E1 += 2; E2 += 2; E3 += 2; } } } static void scale3x(SDL_Surface *src, SDL_Surface *dst) { int looph, loopw; Uint8* srcpix = (Uint8*)src->pixels; Uint8* dstpix = (Uint8*)dst->pixels; const int srcpitch = src->pitch; const int dstpitch = dst->pitch; const int width = src->w; const int height = src->h; Uint32 *E0, *E1, *E2, *E3, *E4, *E5, *E6, *E7, *E8, A, B, C, D, E, F, G, H, I; for(looph = 0; looph < height; ++looph) { E0 = (Uint32*)(dstpix + looph*3*dstpitch + 0*3*4); E1 = (Uint32*)(dstpix + looph*3*dstpitch + (0*3+1)*4); E2 = (Uint32*)(dstpix + looph*3*dstpitch + (0*3+2)*4); E3 = (Uint32*)(dstpix + (looph*3+1)*dstpitch + 0*3*4); E4 = (Uint32*)(dstpix + (looph*3+1)*dstpitch + (0*3+1)*4); E5 = (Uint32*)(dstpix + (looph*3+1)*dstpitch + (0*3+2)*4); E6 = (Uint32*)(dstpix + (looph*3+2)*dstpitch + 0*3*4); E7 = (Uint32*)(dstpix + (looph*3+2)*dstpitch + (0*3+1)*4); E8 = (Uint32*)(dstpix + (looph*3+2)*dstpitch + (0*3+2)*4); for(loopw = 0; loopw < width; ++ loopw) { A = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*my_max(0,loopw-1))); B = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*loopw)); C = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*my_min(width-1,loopw+1))); D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_max(0,loopw-1))); E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw)); F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_min(width-1,loopw+1))); G = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*my_max(0,loopw-1))); H = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*loopw)); I = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*my_min(width-1,loopw+1))); if (B != H && D != F) { *E0 = D == B ? D : E; *E1 = (D == B && E != C) || (B == F && E != A) ? B : E; *E2 = B == F ? F : E; *E3 = (D == B && E != G) || (D == H && E != A) ? D : E; *E4 = E; *E5 = (B == F && E != I) || (H == F && E != C) ? F : E; *E6 = D == H ? D : E; *E7 = (D == H && E != I) || (H == F && E != G) ? H : E; *E8 = H == F ? F : E; } else { *E0 = E; *E1 = E; *E2 = E; *E3 = E; *E4 = E; *E5 = E; *E6 = E; *E7 = E; *E8 = E; } E0 += 3; E1 += 3; E2 += 3; E3 += 3; E4 += 3; E5 += 3; E6 += 3; E7 += 3; E8 += 3; } } } void gfx_blit_2x_resample(SDL_Surface *dest, SDL_Surface *src) { scale2x(src,dest); } void gfx_blit_3x_resample(SDL_Surface *dest, SDL_Surface *src) { scale3x(src,dest); } void gfx_circle(SDL_Surface *dest, const int xc, const int yc, const int r, const Uint32 color) { const int h = my_min(yc+r+1, dest->h); for (int y=my_max(0,yc-r); yh); for (int y=my_max(0,yc-r); yclock_resolution); QueryPerformanceCounter((LARGE_INTEGER*)&d->start_time); #else d->clock_resolution = 1000; d->start_time = SDL_GetTicks(); #endif d->dt = d->clock_resolution / d->fps; d->accumulator = 0; } #ifndef USESDL_GPU static void create_scanlines_texture(GfxDomain *domain) { if (domain->scanlines_texture) SDL_DestroyTexture(domain->scanlines_texture); SDL_Surface *temp = SDL_CreateRGBSurface(0, 8, domain->screen_h * domain->scale, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000); // alpha = 1.0 SDL_FillRect(temp, NULL, 0x00ffffff); debug("%d", domain->scale); const int depth = 32 * domain->scale; for (int y = 0 ; y < domain->screen_h * domain->scale ; ++y) { SDL_Rect r = {0, y, 8, 1}; Uint8 c = fabs(sin((float)y * M_PI / domain->scale)) * depth + (255 - depth); SDL_FillRect(temp, &r, (c << 8) | (c << 16) | c); } domain->scanlines_texture = SDL_CreateTextureFromSurface(domain->renderer, temp); SDL_SetTextureBlendMode(domain->scanlines_texture, SDL_BLENDMODE_MOD); SDL_FreeSurface(temp); } #endif void gfx_domain_update(GfxDomain *domain, bool resize_window) { debug("Setting screen mode (scale = %d%s)", domain->scale, domain->fullscreen ? ", fullscreen" : ""); #ifdef USESDL_GPU GPU_SetWindowResolution(domain->screen_w * domain->scale, domain->screen_h * domain->scale); GPU_SetVirtualResolution(domain->screen, domain->screen_w, domain->screen_h); domain->window_w = domain->screen_w * domain->scale; domain->window_h = domain->screen_h * domain->scale; #else if (resize_window) SDL_SetWindowSize(domain->window, domain->screen_w * domain->scale, domain->screen_h * domain->scale); if (domain->fullscreen) { debug("Setting fullscreen"); if (SDL_SetWindowFullscreen(domain->window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) { warning("Fullscreen failed: %s", SDL_GetError()); if (SDL_SetWindowFullscreen(domain->window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) warning("Fake fullscreen failed: %s", SDL_GetError()); } } else SDL_SetWindowFullscreen(domain->window, 0); if (domain->render_to_texture && !(domain->flags & GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE) /* && domain->scale > 1*/) { debug("Rendering to texture enabled"); SDL_SetRenderTarget(domain->renderer, NULL); if (domain->scale_texture) SDL_DestroyTexture(domain->scale_texture); domain->scale_texture = SDL_CreateTexture(domain->renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, domain->screen_w, domain->screen_h); if (!domain->scale_texture) { warning("Could not create texture: %s", SDL_GetError()); } else { SDL_SetRenderTarget(domain->renderer, domain->scale_texture); } } else { debug("Rendering to texture disabled"); SDL_SetRenderTarget(domain->renderer, NULL); SDL_RenderSetScale(domain->renderer, domain->scale, domain->scale); } if (domain->scale_type == GFX_SCALE_SCANLINES && domain->scale > 1) create_scanlines_texture(domain); SDL_RenderSetViewport(domain->renderer, NULL); SDL_SetWindowMinimumSize(domain->window, domain->window_min_w * domain->scale, domain->window_min_h * domain->scale); SDL_GetWindowSize(domain->window, &domain->window_w, &domain->window_h); #endif debug("Screen size is %dx%d", domain->screen_w, domain->screen_h); debug("Window size is %dx%d", domain->window_w, domain->window_h); gfx_domain_set_framerate(domain); } void gfx_domain_flip(GfxDomain *domain) { #ifdef USESDL_GPU GPU_Flip(domain->screen); #else if (domain->render_to_texture && !(domain->flags & GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE) /*&& domain->scale > 1*/) { SDL_RenderPresent(domain->renderer); SDL_SetRenderTarget(domain->renderer, NULL); SDL_RenderSetViewport(domain->renderer, NULL); SDL_RenderCopy(domain->renderer, domain->scale_texture, NULL, NULL); if (domain->scale_type == GFX_SCALE_SCANLINES && domain->scale > 1) { SDL_RenderCopy(domain->renderer, domain->scanlines_texture, NULL, NULL); } SDL_RenderPresent(domain->renderer); SDL_SetRenderTarget(domain->renderer, domain->scale_texture); SDL_RenderSetViewport(domain->renderer, NULL); } else { if (domain->scale_type == GFX_SCALE_SCANLINES && domain->scale > 1) { SDL_RenderCopy(domain->renderer, domain->scanlines_texture, NULL, NULL); } SDL_RenderPresent(domain->renderer); } #endif #ifdef DEBUG domain->calls_per_frame = 0; #endif } void gfx_domain_free(GfxDomain *domain) { #ifdef USESDL_GPU GPU_Quit(); #else if (domain->scale_texture) SDL_DestroyTexture(domain->scale_texture); if (domain->scanlines_texture) SDL_DestroyTexture(domain->scanlines_texture); SDL_DestroyRenderer(domain->renderer); SDL_DestroyWindow(domain->window); #endif free(domain); } GfxDomain * gfx_create_domain(const char *title, Uint32 window_flags, int window_w, int window_h, int scale) { GfxDomain *d = malloc(sizeof(GfxDomain)); d->screen_w = window_w / scale; d->screen_h = window_h / scale; d->scale = scale; d->scale_type = GFX_SCALE_NEAREST; d->fullscreen = 0; d->fps = 50; d->flags = 0; d->window_min_w = d->screen_w; d->window_min_h = d->screen_h; #ifdef USESDL_GPU d->screen = GPU_Init(window_w, window_h, GPU_DEFAULT_INIT_FLAGS); #else d->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, window_flags); d->renderer = SDL_CreateRenderer(d->window, -1, SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE); SDL_RendererInfo info; SDL_GetRendererInfo(d->renderer, &info); if (!(info.flags & SDL_RENDERER_TARGETTEXTURE)) { warning("Renderer doesn't support rendering to texture"); d->render_to_texture = false; } else { d->render_to_texture = true; } d->scale_texture = NULL; d->scanlines_texture = NULL; #endif #ifdef DEBUG d->calls_per_frame = 0; #ifndef USESDL_GPU { SDL_RendererInfo info; SDL_GetRendererInfo(d->renderer, &info); debug("Renderer: %s (%s)", info.name, (info.flags & SDL_RENDERER_ACCELERATED) ? "Accelerated" : "Not accelerated"); } #endif #endif gfx_domain_set_framerate(d); return d; } int gfx_domain_is_next_frame(GfxDomain *domain) { #ifdef WIN32 Uint64 ticks; QueryPerformanceCounter((LARGE_INTEGER*)&ticks); #else Uint32 ticks = SDL_GetTicks(); #endif FramerateTimer frameTime = ticks - domain->start_time; domain->start_time = ticks; domain->accumulator += frameTime; int frames = 0; while ( domain->accumulator > domain->dt ) { domain->accumulator -= domain->dt; ++frames; } return frames; } GfxSurface * gfx_create_surface(GfxDomain *domain, int w, int h) { GfxSurface *gs = calloc(1, sizeof(GfxSurface)); gs->surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); return gs; } void gfx_update_texture(GfxDomain *domain, GfxSurface *surface) { #ifdef USESDL_GPU if (!surface->texture) surface->texture = GPU_CreateImage(surface->surface->w, surface->surface->h, GPU_FORMAT_RGBA); GPU_UpdateImage(surface->texture, surface->surface, NULL); GPU_SetImageFilter(surface->texture, GPU_FILTER_NEAREST); GPU_SetSnapMode(surface->texture, GPU_SNAP_POSITION_AND_DIMENSIONS); GPU_SetBlending(surface->texture, 1); GPU_SetBlendMode(surface->texture, GPU_BLEND_NORMAL); #else if (surface->texture) SDL_DestroyTexture(surface->texture); surface->texture = SDL_CreateTextureFromSurface(domain->renderer, surface->surface); #endif } void gfx_free_surface(GfxSurface *surface) { #ifdef USESDL_GPU if (surface->texture) GPU_FreeImage(surface->texture); #else if (surface->texture) SDL_DestroyTexture(surface->texture); #endif if (surface->surface) SDL_FreeSurface(surface->surface); if (surface->mask) free(surface->mask); free(surface); } void gfx_clear(GfxDomain *domain, Uint32 color) { #ifdef USESDL_GPU GPU_ClearRGBA(domain->screen, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255); #else SDL_SetRenderDrawColor(domain->renderer, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255); SDL_RenderClear(domain->renderer); #endif } #define SCALEHELPER(test) do {\ for (int dy = dest_rect->y, sy = 256 * (int)src_rect->y ; dy < dest_rect->h + dest_rect->y ; ++dy, sy += yspd)\ {\ Uint32 * dptr = (Uint32*)((Uint8*)dest->pixels + dy * dest->pitch) + dest_rect->x;\ Uint32 * sptr = (Uint32*)((Uint8*)src->pixels + sy/256 * src->pitch);\ \ for (int dx = dest_rect->w, sx = 256 * (int)src_rect->x ; dx > 0 ; --dx, sx += xspd)\ {\ if (test) *dptr = sptr[sx / 256];\ ++dptr;\ }\ }\ } while(0) void gfx_blit(GfxSurface *_src, SDL_Rect *_src_rect, GfxDomain *domain, SDL_Rect *_dest_rect) { #ifdef USESDL_GPU GPU_Rect rect; if (_src_rect) rect = GPU_MakeRect(_src_rect->x, _src_rect->y, _src_rect->w, _src_rect->h); else rect = GPU_MakeRect(0, 0, _src->surface->w, _src->surface->h); GPU_BlitScale(_src->texture, &rect, domain->screen, _dest_rect->x + (float)_dest_rect->w / 2, _dest_rect->y + (float)_dest_rect->h / 2, (float)_dest_rect->w / rect.w, (float)_dest_rect->h / rect.h); #else SDL_RenderCopy(domain->renderer, _src->texture, _src_rect, _dest_rect); #endif #ifdef DEBUG domain->calls_per_frame++; #endif } void gfx_rect(GfxDomain *domain, SDL_Rect *dest, Uint32 color) { #ifdef USESDL_GPU SDL_Color rgb = { (color >> 16) & 255, (color >> 8) & 255, color & 255, 255 }; if (dest) GPU_RectangleFilled(domain->screen, dest->x, dest->y, dest->w + dest->x - 1, dest->y + dest->h - 1, rgb); else GPU_RectangleFilled(domain->screen, 0, 0, domain->screen_w, domain->screen_h, rgb); #else SDL_SetRenderDrawColor(domain->renderer, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255); SDL_RenderFillRect(domain->renderer, dest); #endif } void my_BlitSurface(GfxSurface *src, SDL_Rect *src_rect, GfxDomain *dest, SDL_Rect *dest_rect) { gfx_blit(src, src_rect, dest, dest_rect); } void gfx_domain_set_clip(GfxDomain *domain, const SDL_Rect *rect) { #ifdef USESDL_GPU if (rect) memcpy(&domain->clip, rect, sizeof(*rect)); else { domain->clip.x = 0; domain->clip.y = 0; domain->clip.w = domain->screen_w; domain->clip.h = domain->screen_h; } GPU_SetClip(domain->screen, domain->clip.x, domain->clip.y, domain->clip.w, domain->clip.h); #else SDL_RenderSetClipRect(domain->renderer, rect); #endif } void gfx_domain_get_clip(GfxDomain *domain, SDL_Rect *rect) { #ifdef USESDL_GPU memcpy(rect, &domain->clip, sizeof(*rect)); #else SDL_RenderGetClipRect(domain->renderer, rect); #endif } void gfx_surface_set_color(GfxSurface *surf, Uint32 color) { #ifdef USESDL_GPU GPU_SetRGB(surf->texture, (color >> 16) & 255, (color >> 8) & 255, color & 255); #else SDL_SetTextureColorMod(surf->texture, (color >> 16) & 255, (color >> 8) & 255, color & 255); #endif } void gfx_convert_mouse_coordinates(GfxDomain *domain, int *x, int *y) { if (domain->window_w) *x = *x * domain->screen_w / domain->window_w; if (domain->window_h) *y = *y * domain->screen_h / domain->window_h; } klystrack-0.20171212/klystron/src/gfx/background.h0000644000000000000000000000375313214501362020353 0ustar rootroot#ifndef BACKGROUND_H #define BACKGROUND_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "bgcell.h" #include "objhdr.h" #include "tiledescriptor.h" #include "SDL.h" enum { BG_REPEAT_X = 1, BG_REPEAT_Y = 2, BG_PARALLAX = 4 }; typedef struct { int flags; int w, h; int prx_mlt_x, prx_mlt_y; int off_x, off_y; TileDescriptor *tiles; BgCell *data; } Background; struct GfxDomain_t; int bg_check_collision(const Background *bg, const ObjHdr *object, ObjHdr *collided_tile); const ObjHdr * bg_check_collision_chained(const Background *bg, const ObjHdr *head, ObjHdr *collided_tile); void bg_draw(struct GfxDomain_t *surface, const SDL_Rect * dest, const Background *bg, int xofs, int yofs); int bg_create_tile_objhdr(ObjHdr* object_array, const Background *bg, int x, int y, int w, int h, int zero_src, TileDescriptor *tiles); void bg_create(Background *bg, int w, int h); void bg_destroy(Background *bg); #endif klystrack-0.20171212/klystron/src/gfx/bgcell.c0000644000000000000000000000256013214501362017452 0ustar rootroot#include "bgcell.h" /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ int bgcell_check_collision(const int x, const int y, const BgCell *bg, const ObjHdr *object) { ObjHdr hdr; hdr.objflags = bg->flags; hdr.x = x; hdr.y = y; hdr.w = CELLSIZE; hdr.h = CELLSIZE; return objhdr_check_collision(&hdr, object); } klystrack-0.20171212/klystron/src/gfx/gfx.h0000644000000000000000000001041513214501362017011 0ustar rootroot#ifndef GFX_H #define GFX_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "SDL_rwops.h" #include "tiledescriptor.h" #include "gfxsurf.h" #include #ifdef USESDL_GPU #include "SDL_gpu.h" #endif enum { GFX_KEYED = 1, GFX_ALPHA = 2, GFX_TRANS_HALF = 4, GFX_COL_MASK = 8 }; enum { GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE = 1 }; typedef enum { GFX_SCALE_NEAREST, GFX_SCALE_SCANLINES } GfxScaleType; #ifdef WIN32 typedef Uint64 FramerateTimer; #else typedef Uint32 FramerateTimer; #endif struct GfxDomain_t { #ifdef USESDL_GPU GPU_Target *screen; SDL_Rect clip; #else SDL_Window *window; SDL_Renderer *renderer; SDL_Texture *scale_texture, *scanlines_texture; bool render_to_texture; #endif int screen_w, screen_h; int window_w, window_h, window_min_w, window_min_h; int scale, fullscreen, fps; GfxScaleType scale_type; FramerateTimer start_time, dt, clock_resolution, accumulator; int flags; Uint8 texmod_r, texmod_g, texmod_b; #ifdef DEBUG int calls_per_frame; #endif }; typedef struct GfxDomain_t GfxDomain; GfxSurface* gfx_load_surface(GfxDomain *domain, const char* filename, const int flags); GfxSurface* gfx_load_surface_RW(GfxDomain *domain, SDL_RWops *rw, const int flags); int * gfx_build_collision_mask(SDL_Surface *s); GfxSurface * gfx_create_surface(GfxDomain *domain, int w, int h); void gfx_free_surface(GfxSurface *surface); void gfx_blit_2x(SDL_Surface *dest, SDL_Surface *src); void gfx_blit_2x_resample(SDL_Surface *dest, SDL_Surface *src); void gfx_blit_3x(SDL_Surface *dest, SDL_Surface *src); void gfx_blit_3x_resample(SDL_Surface *dest, SDL_Surface *src); void gfx_blit_4x(SDL_Surface *dest, SDL_Surface *src); void gfx_raster(SDL_Surface *dest, const SDL_Rect *rect, const Uint32 *colors, int len); void gfx_generate_raster(Uint32 *dest, const Uint32 from, const Uint32 to, int len); TileDescriptor *gfx_build_tiledescriptor(GfxSurface *tiles, const int cellwidth, const int cellheight, int *out_n_tiles); void gfx_line(GfxDomain *dest, int x0, int y0, int x1, int y1, Uint32 color); void gfx_circle_inverted(SDL_Surface *dest, const int xc, const int yc, const int r, const Uint32 color); void gfx_circle(SDL_Surface *dest, const int xc, const int yc, const int r, const Uint32 color); void gfx_clear(GfxDomain *domain, Uint32 color); void gfx_blit(GfxSurface *src, SDL_Rect *srcrect, GfxDomain *domain, SDL_Rect *dest); void gfx_rect(GfxDomain *domain, SDL_Rect *dest, Uint32 rgb); void gfx_surface_set_color(GfxSurface *surf, Uint32 color); void gfx_update_texture(GfxDomain *domain, GfxSurface *surface); void gfx_convert_mouse_coordinates(GfxDomain *domain, int *x, int *y); GfxDomain * gfx_create_domain(const char *title, Uint32 window_flags, int window_w, int window_h, int scale); void gfx_domain_update(GfxDomain *domain, bool resize_window); void gfx_domain_flip(GfxDomain *domain); void gfx_domain_free(GfxDomain *domain); int gfx_domain_is_next_frame(GfxDomain *domain); void gfx_domain_set_clip(GfxDomain *domain, const SDL_Rect *rect); void gfx_domain_get_clip(GfxDomain *domain, SDL_Rect *rect); // void my_BlitSurface(GfxSurface *src, SDL_Rect *src_rect, GfxDomain *dest, SDL_Rect *dest_rect); #endif klystrack-0.20171212/klystron/src/gfx/font.h0000644000000000000000000000506213214501362017175 0ustar rootroot#ifndef FONT_H #define FONT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "tiledescriptor.h" #include "../util/bundle.h" #include "gfx.h" #include typedef struct { char *charmap; TileDescriptor *tiledescriptor; const TileDescriptor *ordered_tiles[256]; GfxSurface * surface; int w, h; int char_spacing, space_width; } Font; int font_load(GfxDomain *domain, Font *font, Bundle *b, char *name); int font_load_file(GfxDomain *domain, Font *font, char *filename); int font_load_RW(GfxDomain *domain, Font *font, SDL_RWops *rw); void font_create(Font *font, GfxSurface *tiles, const int w, const int h, const int char_spacing, const int space_width, char *charmap); void font_destroy(Font *font); void font_set_color(Font *font, Uint32 rgb); void font_write_cursor(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 *cursor, SDL_Rect *bounds, const char * text); void font_write_va(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 * cursor, SDL_Rect *bounds, const char * text, va_list va); void font_write_cursor_args(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 *cursor, SDL_Rect *bounds, const char * text, ...) __attribute__ ((format (printf, 6, 7))); void font_write(const Font *font, GfxDomain *dest, const SDL_Rect *r, const char * text); void font_write_args(const Font *font, GfxDomain *dest, const SDL_Rect *r, const char * text, ...) __attribute__ ((format (printf, 4, 5))); int font_text_width(const Font *font, const char *text); #endif klystrack-0.20171212/klystron/src/gfx/bgcell.h0000644000000000000000000000301713214501362017455 0ustar rootroot#ifndef BGCELL_H #define BGCELL_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "objhdr.h" #define CELLSIZE 8 enum // tile flags { TILE_COL_NORMAL = OBJ_COL_NORMAL, TILE_COL_PIXEL = OBJ_COL_PIXEL, TILE_COL_RECT = OBJ_COL_RECT, TILE_COL_DISABLE = OBJ_COL_DISABLE }; typedef struct { unsigned short int tile; unsigned short int flags; } BgCell; int bgcell_check_collision(const int x, const int y, const BgCell *bg, const ObjHdr *object); #endif klystrack-0.20171212/klystron/src/gfx/gfxsurf.h0000644000000000000000000000264413214501362017716 0ustar rootroot#ifndef GFXSURF_H #define GFXSURF_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #ifdef USESDL_GPU #include "SDL_gpu.h" #endif typedef struct { SDL_Surface *surface; // this can now be a hw surface int *mask; // collision mask int flags; #ifdef USESDL_GPU GPU_Image *texture; #else SDL_Texture *texture; #endif } GfxSurface; #endif klystrack-0.20171212/klystron/src/gfx/objhdr.h0000644000000000000000000000600013214501362017470 0ustar rootroot#ifndef OBJHDR_H #define OBJHDR_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "sllhdr.h" #include "gfxsurf.h" #include "macros.h" enum // OBJFLAGS { OBJ_COL_NORMAL = 0, OBJ_COL_PIXEL = 1, OBJ_COL_RECT = 2, OBJ_DRAW_RECT = 4, OBJ_ANIM_FINISHED = 8, OBJ_RELATIVE_CHILDREN = 16, OBJ_COL_DISABLE = 32, OBJ_ANIM_LOOPED = 64, OBJ_ANIM_NEXT_FRAME = 128 }; #define OBJ_COL_FLAGS (OBJ_COL_NORMAL|OBJ_COL_PIXEL|OBJ_COL_RECT|OBJ_COL_DISABLE) enum // ANIM { ANIM_JUMP = -1, ANIM_END = -2 }; typedef struct { int frame; int delay; } AnimFrame; #define OBJHDR_ANIM_SPEED_NORMAL 256 #define OBJHDR \ SLLHDR;\ Uint32 objid; \ Uint32 objflags;\ Sint32 x, y;\ Sint32 w, h;\ Sint32 _yofs;\ SDL_Rect colrect;\ GfxSurface *surface;\ const AnimFrame *anim;\ Sint32 current_frame, anim_frame, frame_delay, anim_speed_fine;\ typedef struct { OBJHDR; } ObjHdr; struct GfxDomain_t; // rect collision int objhdr_check_collision(const ObjHdr *a, const ObjHdr *b); const ObjHdr * objhdr_check_collision_chained(const ObjHdr *a, const ObjHdr *head); const ObjHdr * objhdr_check_collision_chained2(const ObjHdr *head1, const ObjHdr *head2); void objhdr_draw(struct GfxDomain_t *destination, const ObjHdr *object, int xofs, int yofs); void objhdr_draw_chained(struct GfxDomain_t *destination, const ObjHdr *head, int xofs, int yofs); void objhdr_set_animation(ObjHdr *obj, const AnimFrame *anim, int anim_speed_fine); void objhdr_advance_animation(ObjHdr *obj); void objhdr_advance_animation_chained(ObjHdr *head); #define objhdr_walk(ptr,head,block) sllhdr_walk(ptr,head,block) #define objhdr_insert_after(queue, obj) sllhdr_insert_after(queue, obj) #define objhdr_insert_before(queue, obj) sllhdr_insert_before(queue, obj) #define objhdr_update_list(ptr, unused_head, in_use_head, foreach, kill_if, on_death) sllhdr_update_list(ObjHdr, ptr, unused_head, in_use_head, foreach, kill_if, on_death) #endif klystrack-0.20171212/klystron/src/gfx/background.c0000644000000000000000000001240113214501362020334 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "background.h" #include "gfx.h" #include #include int bg_check_collision(const Background *bg, const ObjHdr *object, ObjHdr *collided_object) { int right = (object->x + object->w) / CELLSIZE, bottom = (object->y + object->h) / CELLSIZE; int top = (object->y) / CELLSIZE-1, left = (object->x) / CELLSIZE-1; ObjHdr _hdr; ObjHdr *hdr = (collided_object != NULL) ? collided_object : &_hdr; hdr->w = CELLSIZE; hdr->h = CELLSIZE; hdr->y = top * CELLSIZE; for (int y = top ; y <= bottom ; ++y) { hdr->x = left * CELLSIZE; int _y = y; if (bg->flags & BG_REPEAT_Y) _y = ((y % bg->h)+bg->h) % bg->h; else if (y >= bg->h) break; //printf("%d %d\n", hdr.x, object->x); if (_y >= 0) { for (int x = left ; x <= right ; ++x) { int _x = x; if (bg->flags & BG_REPEAT_X) _x = ((x % bg->w)+bg->w) % bg->w; else if (x >= bg->w) break; if (_x >= 0) { if ( bg->data[_x+_y*bg->w].tile && !(bg->tiles[bg->data[_x+_y*bg->w].tile-1].flags & TILE_COL_DISABLE)) { hdr->objflags = bg->tiles[bg->data[_x+_y*bg->w].tile-1].flags; hdr->surface = bg->tiles[bg->data[_x+_y*bg->w].tile-1].surface; hdr->current_frame = bg->tiles[bg->data[_x+_y*bg->w].tile-1].rect.x / CELLSIZE; hdr->_yofs = bg->tiles[bg->data[_x+_y*bg->w].tile-1].rect.y; if (objhdr_check_collision(object, hdr)) { return 1; } } } hdr->x += CELLSIZE; } } hdr->y += CELLSIZE; } return 0; } void bg_draw(GfxDomain *surface, const SDL_Rect * dest, const Background *bg, int xofs, int yofs) { int sx = 0; int sy = 0; const SDL_Rect def = {0, 0, surface->screen_w, surface->screen_h}; if (dest == NULL) dest = &def; for (int y = (yofs) / CELLSIZE - 1; sy <= dest->h + 2 * CELLSIZE ; ++y, sy += CELLSIZE) { sx = 0; int _y = y; if (bg->flags & BG_REPEAT_Y) _y = ((y % bg->h)+bg->h) % bg->h; else if (y < 0) continue; else if (y >= bg->h) break; for (int x = (xofs) / CELLSIZE - 1 ; sx <= dest->w + 2 * CELLSIZE ; ++x, sx += CELLSIZE) { int _x = x; if (bg->flags & BG_REPEAT_X) _x = ((x % bg->w)+bg->w) % bg->w; else if (x < 0) continue; else if (x >= bg->w) break; BgCell * cell = &bg->data[_y*bg->w + _x]; if ( cell->tile ) { SDL_Rect rect = { sx - (xofs % (CELLSIZE)) + dest->x - CELLSIZE, sy - (yofs % (CELLSIZE)) + dest->y - CELLSIZE, CELLSIZE, CELLSIZE }; my_BlitSurface(bg->tiles[cell->tile-1].surface, &bg->tiles[cell->tile-1].rect, surface, &rect); // SDL_FillRect(surface, &rect, 0x808080); } } } } const ObjHdr * bg_check_collision_chained(const Background *bg, const ObjHdr *head, ObjHdr *collided_tile) { const ObjHdr *ptr; objhdr_walk(ptr, head, if (bg_check_collision(bg, ptr, collided_tile)) return ptr); return NULL; } int bg_create_tile_objhdr(ObjHdr* object_array, const Background *bg, int x, int y, int w, int h, int zero_src, TileDescriptor *tiles) { int items = 0; ObjHdr *obj = object_array; if (!tiles) tiles = bg->tiles; for (int _y = y ; _y < h + y ; ++_y) { for (int _x = x ; _x < w + x ; ++_x) { if (bg->data[_x + _y * bg->w].tile) { if (obj != NULL) { obj->objflags = tiles[bg->data[_x + _y * bg->w].tile-1].flags & OBJ_COL_FLAGS; obj->x = (_x - x) * CELLSIZE; obj->y = (_y - y) * CELLSIZE; obj->w = obj->h = CELLSIZE; obj->anim = NULL; obj->current_frame = tiles[bg->data[_x + _y * bg->w].tile-1].rect.x / CELLSIZE; obj->_yofs = tiles[bg->data[_x + _y * bg->w].tile-1].rect.y; obj->surface = tiles[bg->data[_x + _y * bg->w].tile-1].surface; obj = obj->next; if (zero_src) bg->data[_x + _y * bg->w].tile = 0; } ++items; } } } if (items > 0) object_array[items-1].next = NULL; return items; } void bg_create(Background *bg, int w, int h) { memset(bg, 0, sizeof(*bg)); bg->data = calloc(w * h, sizeof(bg->data[0])); bg->w = w; bg->h = h; } void bg_destroy(Background *bg) { free(bg->data); memset(bg, 0, sizeof(*bg)); } klystrack-0.20171212/klystron/src/gfx/levelbase.c0000644000000000000000000000614113214501362020163 0ustar rootroot#include "levelbase.h" #include #define ptr_read(dest, ptr) SDL_RWread(data, &dest, sizeof(dest), 1); int lev_load(Background *bg, int *n_layers, SDL_RWops* data, int (*interpret_event)(void *, const LevEvent *), void* pdata) { int current_layer = -1; BgCell * cell = NULL; while (1) { Uint8 x = 0; SDL_RWread(data, &x, 1, 1); if (x == LOP_END) break; LevOpCode opcode; opcode.opcode = x; ptr_read(opcode.repeat, data); FIX_ENDIAN(opcode.repeat); for (int di = 0 ; di < opcode.repeat ; ++di) { switch (opcode.opcode) { default: fatal("Unknown opcode %d\n", opcode.opcode); return 0; break; case LOP_EVENT: { LevEvent event = {0}; ptr_read(event.x, data); ptr_read(event.y, data); ptr_read(event.w, data); ptr_read(event.h, data); SDL_RWread(data, &event.param[0], sizeof(event.param[0]), EV_PARAMS); if (!interpret_event) break; FIX_ENDIAN(event.x); FIX_ENDIAN(event.y); FIX_ENDIAN(event.w); FIX_ENDIAN(event.h); for (int i = 0 ; i < EV_PARAMS ; ++i) { FIX_ENDIAN(event.param[i]); } if (!interpret_event(pdata, &event)) { warning("Unknown event %d\n", event.param[0]); } } break; case LOP_LAYER: { ++current_layer; if (current_layer >= *n_layers) { fatal("Too many layers"); return 0; } LevLayer header; ptr_read(header.flags, data); ptr_read(header.w, data); ptr_read(header.h, data); ptr_read(header.prx_mlt_x, data); ptr_read(header.prx_mlt_y, data); ptr_read(header.off_x, data); ptr_read(header.off_y, data); FIX_ENDIAN(header.flags); FIX_ENDIAN(header.w); FIX_ENDIAN(header.h); FIX_ENDIAN(header.prx_mlt_x); FIX_ENDIAN(header.prx_mlt_y); FIX_ENDIAN(header.off_x); FIX_ENDIAN(header.off_y); bg_create(&bg[current_layer], header.w, header.h); bg[current_layer].flags = header.flags; bg[current_layer].prx_mlt_x = header.prx_mlt_x; bg[current_layer].prx_mlt_y = header.prx_mlt_y; bg[current_layer].off_x = header.off_x; bg[current_layer].off_y = header.off_y; cell = bg[current_layer].data; } break; case LOP_TILE: { LevTile tile = {0}; ptr_read(tile.type, data); FIX_ENDIAN(tile.type); cell->tile = tile.type; ++cell; } break; case LOP_REP_TILE: { LevRepTile tile = {0}; ptr_read(tile.repeat, data); ptr_read(tile.type, data); FIX_ENDIAN(tile.type); FIX_ENDIAN(tile.repeat); for (int i = 0 ; i < tile.repeat ; ++i) { cell->tile = tile.type; ++cell; } } break; } } } *n_layers = current_layer+1; return 1; } void lev_unload(Background *bg, int n_layers) { for (int i = 0 ; i < n_layers ; ++i) { free(bg[i].data); bg[i].data = NULL; } } klystrack-0.20171212/klystron/src/gfx/tiledescriptor.h0000644000000000000000000000243413214501362021263 0ustar rootroot#ifndef TILEDESCRIPTOR_H #define TILEDESCRIPTOR_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "gfxsurf.h" #include "bgcell.h" typedef struct { int flags; GfxSurface *surface; SDL_Rect rect; } TileDescriptor; #endif klystrack-0.20171212/klystron/src/gfx/objhdr.c0000644000000000000000000002271213214501362017473 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "objhdr.h" #include #include #include "gfx.h" static inline int surf_alpha_both(const int *a, const int *b, int ax, int ay, int bx, int by, int w, int h, int stride_a, int stride_b) { for (int y = 0 ; y < h ; ++y) { const int *pa = a + (ay + y) * stride_a + ax; const int *pb = b + (by + y) * stride_b + bx; for (int x = 0 ; x < w ; ++x) { if (*pa && *pb) { return 1; } ++pa; ++pb; } } return 0; } static inline int surf_alpha_a(const int *a, int ax, int ay, int w, int h, int stride) { for (int y = ay ; y < h+ay ; ++y) { const int *pa = a + y * stride + ax; for (int x = 0 ; x < w ; ++x) { if (*pa) { return 1; } ++pa; } } return 0; } static int objhdr_check_collision_internal(const ObjHdr *a, const ObjHdr *b, int axoff, int ayoff, int bxoff, int byoff) { if ((a->objflags & OBJ_COL_DISABLE) || (b->objflags & OBJ_COL_DISABLE)) return 0; int a_left = a->x - axoff, a_right = a_left + a->w - 1; int a_top = a->y - ayoff, a_bottom = a_top + a->h - 1; int b_left = b->x - bxoff, b_right = b_left + b->w - 1; int b_top = b->y - byoff, b_bottom = b_top + b->h - 1; if (a->objflags & OBJ_COL_RECT) { a_left = a->x + a->colrect.x - axoff; a_right = a_left + a->colrect.w - 1; a_top = a->y + a->colrect.y - ayoff; a_bottom = a_top + a->colrect.h - 1; } if (b->objflags & OBJ_COL_RECT) { b_left = b->x + b->colrect.x - bxoff; b_right = b_left + b->colrect.w - 1; b_top = b->y + b->colrect.y - ayoff; b_bottom = b_top + b->colrect.h - 1; } if(b_right < a_left) return 0; //just checking if their if(b_left > a_right) return 0; //bounding boxes even touch if(b_bottom < a_top) return 0; if(b_top > a_bottom) return 0; if (!(a->objflags & OBJ_COL_PIXEL) && !(b->objflags & OBJ_COL_PIXEL)) return 1; int a_xofs, a_yofs; int b_xofs, b_yofs; if (a_left < b_left) { b_xofs = 0; a_xofs = b_left-a_left; } else { b_xofs = a_left-b_left; a_xofs = 0; } if (a_top < b_top) { b_yofs = 0; a_yofs = b_top-a_top; } else { b_yofs = a_top-b_top; a_yofs = 0; } int h = my_min(a_bottom - a_top - a_yofs+1, b_bottom - b_top - b_yofs+1), w = my_min(a_right - a_left - a_xofs+1, b_right - b_left - b_xofs+1); if (a->objflags & OBJ_COL_PIXEL && b->objflags & OBJ_COL_PIXEL) return surf_alpha_both(a->surface->mask, b->surface->mask, a_xofs + a->current_frame*a->w, a_yofs + a->_yofs, b_xofs + b->current_frame*b->w, b_yofs + b->_yofs, w, h, a->surface->surface->w, b->surface->surface->w); else if (a->objflags & OBJ_COL_PIXEL && !(b->objflags & OBJ_COL_PIXEL)) return surf_alpha_a(a->surface->mask, a_xofs + a->current_frame*a->w, a_yofs + a->_yofs, w, h, a->surface->surface->w); else if (b->objflags & OBJ_COL_PIXEL && !(a->objflags & OBJ_COL_PIXEL)) return surf_alpha_a(b->surface->mask, b_xofs + b->current_frame*b->w, b_yofs + b->_yofs , w, h, b->surface->surface->w); else return 1; } int objhdr_check_collision(const ObjHdr *a, const ObjHdr *b) { if (!(a->objflags & OBJ_RELATIVE_CHILDREN) && !(b->objflags & OBJ_RELATIVE_CHILDREN)) return objhdr_check_collision_internal(a, b, 0, 0, 0, 0); else if ((a->objflags & OBJ_RELATIVE_CHILDREN) && !(b->objflags & OBJ_RELATIVE_CHILDREN)) return objhdr_check_collision_chained(b, a) != NULL; else if (!(a->objflags & OBJ_RELATIVE_CHILDREN) && (b->objflags & OBJ_RELATIVE_CHILDREN)) return objhdr_check_collision_chained(a, b) != NULL; else if ((a->objflags & OBJ_RELATIVE_CHILDREN) && (b->objflags & OBJ_RELATIVE_CHILDREN)) return objhdr_check_collision_chained2(a, b) != NULL; else return 0; } const ObjHdr * objhdr_check_collision_chained(const ObjHdr *a, const ObjHdr *head) { const ObjHdr *ptr; if (!(head->objflags & OBJ_RELATIVE_CHILDREN)) { objhdr_walk(ptr, head, if (a != ptr && objhdr_check_collision_internal(a, ptr, 0, 0, 0, 0)) return ptr;); } else { if (objhdr_check_collision_internal(a, head, 0, 0, 0, 0)) return head; objhdr_walk(ptr, head->next, if (a != ptr && objhdr_check_collision_internal(a, ptr, 0, 0, -head->x, -head->y)) return ptr;); } return NULL; } const ObjHdr * objhdr_check_collision_chained2(const ObjHdr *head1, const ObjHdr *head2) { const ObjHdr *ptr1, *ptr2; if (!head1 || !head2) return NULL; if (!(head1->objflags & OBJ_RELATIVE_CHILDREN) && !(head2->objflags & OBJ_RELATIVE_CHILDREN)) { objhdr_walk(ptr1, head1, objhdr_walk(ptr2, head2, if (ptr1 != ptr2 && objhdr_check_collision_internal(ptr1, ptr2, 0, 0, 0, 0)) return ptr2;)); } else if ((head1->objflags & OBJ_RELATIVE_CHILDREN) && !(head2->objflags & OBJ_RELATIVE_CHILDREN)) { if (objhdr_check_collision_internal(head1, head2, 0, 0, 0, 0)) return head2; objhdr_walk(ptr1, head1->next, objhdr_walk(ptr2, head2, if (ptr1 != ptr2 && objhdr_check_collision_internal(ptr1, ptr2, -head1->x, -head1->y, 0, 0)) return ptr2;)); } else if (!(head1->objflags & OBJ_RELATIVE_CHILDREN) && (head2->objflags & OBJ_RELATIVE_CHILDREN)) { if (objhdr_check_collision_internal(head1, head2, 0, 0, 0, 0)) return head2; objhdr_walk(ptr1, head1, objhdr_walk(ptr2, head2->next, if (ptr1 != ptr2 && objhdr_check_collision_internal(ptr1, ptr2, 0, 0, -head2->x, -head2->y)) return ptr2;)); } else if ((head1->objflags & OBJ_RELATIVE_CHILDREN) && (head2->objflags & OBJ_RELATIVE_CHILDREN)) { if (objhdr_check_collision_internal(head1, head2, 0, 0, 0, 0)) return head2; objhdr_walk(ptr1, head1->next, objhdr_walk(ptr2, head2->next, if (ptr1 != ptr2 && objhdr_check_collision_internal(ptr1, ptr2, -head1->x, -head1->y, -head2->x, -head2->y)) return ptr2;)); } return NULL; } void objhdr_draw(GfxDomain *destination, const ObjHdr *object, int xofs, int yofs) { if (object->objflags & OBJ_RELATIVE_CHILDREN) objhdr_draw_chained(destination, object, xofs, yofs); else { SDL_Rect dest = {object->x - xofs, object->y - yofs, object->w, object->h}; #ifdef DEBUG if (object->surface == NULL) { gfx_rect(destination, &dest, 0xffffffff); } else #endif if (object->objflags & OBJ_DRAW_RECT) { gfx_rect(destination, &dest, *(Uint32*)&object->surface); } else { if (object->surface != NULL) { SDL_Rect src = { object->current_frame * object->w, object->_yofs, object->w, object->h }; my_BlitSurface(object->surface , &src, destination, &dest); } } #ifdef DEBUG if (object->objflags & OBJ_COL_RECT) { SDL_Rect dest = {object->x - xofs + object->colrect.x, object->y - yofs + object->colrect.y, object->colrect.w, object->colrect.h}; gfx_rect(destination, &dest, 0xff0000); } #endif } } void objhdr_draw_chained(GfxDomain *destination, const ObjHdr *head, int xofs, int yofs) { const ObjHdr *ptr; if (!head) return; if (head->objflags & OBJ_RELATIVE_CHILDREN) { //objhdr_draw(destination, head, xofs, yofs); if (head->next) { xofs -= head->x; yofs -= head->y; objhdr_walk(ptr, head->next, objhdr_draw(destination, ptr, xofs, yofs)); } } else { objhdr_walk(ptr, head, objhdr_draw(destination, ptr, xofs, yofs)); } } void objhdr_set_animation(ObjHdr *obj, const AnimFrame *anim, int anim_speed_fine) { obj->anim = anim; obj->anim_frame = 0; obj->anim_speed_fine = anim_speed_fine; if (anim) { obj->current_frame = obj->anim[0].frame; obj->frame_delay = obj->anim[0].delay * OBJHDR_ANIM_SPEED_NORMAL; } } void objhdr_advance_animation(ObjHdr *obj) { if (obj->anim == NULL) return; obj->objflags &= ~(OBJ_ANIM_FINISHED|OBJ_ANIM_LOOPED|OBJ_ANIM_NEXT_FRAME); if (obj->frame_delay <= 0) { obj->objflags |= OBJ_ANIM_NEXT_FRAME; ++obj->anim_frame; switch (obj->anim[obj->anim_frame].frame) { case ANIM_JUMP: { obj->anim_frame = obj->anim[obj->anim_frame].delay; obj->objflags |= OBJ_ANIM_LOOPED; } break; case ANIM_END: { obj->anim_frame = 0; obj->objflags |= OBJ_ANIM_FINISHED; } break; } obj->current_frame = obj->anim[obj->anim_frame].frame; obj->frame_delay += obj->anim[obj->anim_frame].delay * OBJHDR_ANIM_SPEED_NORMAL; } obj->frame_delay -= obj->anim_speed_fine; } void objhdr_advance_animation_chained(ObjHdr *head) { ObjHdr *ptr; objhdr_walk(ptr, head, objhdr_advance_animation(ptr)); } klystrack-0.20171212/klystron/src/gfx/levelbase.h0000644000000000000000000000372513214501362020175 0ustar rootroot#ifndef LEVELBASE_H #define LEVELBASE_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "background.h" #include "SDL_rwops.h" enum { LOP_LAYER, LOP_END, LOP_TILE, LOP_REP_TILE, LOP_EVENT }; #define PACKED __attribute__ ((packed)) #define EV_PARAMS 16 #define EV_NEXT 15 #define EV_TRGPARENT 14 typedef struct { Uint8 opcode; Uint32 repeat; } PACKED LevOpCode; typedef struct { Uint32 flags; Uint16 w, h; Sint16 prx_mlt_x, prx_mlt_y; Sint16 off_x, off_y; } PACKED LevLayer; typedef struct { Sint16 x, y; Uint16 w, h; Sint32 param[EV_PARAMS]; } PACKED LevEvent; typedef struct { Uint16 type; } PACKED LevTile; typedef struct { Uint16 repeat; Uint16 type; } PACKED LevRepTile; int lev_load(Background *bg, int *n_layers, SDL_RWops* data, int (*interpret_event)(void *, const LevEvent *), void* pdata); void lev_unload(Background *bg, int n_layers); #endif klystrack-0.20171212/klystron/src/gfx/font.c0000644000000000000000000002416713214501362017177 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "font.h" #include "gfx.h" #include #include #include static int tile_width(TileDescriptor *desc) { #if SDL_VERSION_ATLEAST(1,3,0) Uint32 key; SDL_GetColorKey(desc->surface->surface, &key); #else const Uint32 key = desc->surface->surface->format->colorkey; #endif my_lock(desc->surface->surface); int result = 0; for (int y = 0 ; y < desc->rect.h ; ++y) { Uint8 *pa = (Uint8 *)desc->surface->surface->pixels + ((int)desc->rect.y + y) * desc->surface->surface->pitch + (int)desc->rect.x * desc->surface->surface->format->BytesPerPixel; for (int x = 0 ; x < desc->rect.w ; ++x) { int p = 0; switch (desc->surface->surface->format->BytesPerPixel) { default: case 1: p = ((*((Uint8*)pa))) != key; break; case 2: p = ((*((Uint16*)pa))&0xffff) != key; break; case 3: p = ((*((Uint32*)pa))&0xffffff) != key; break; case 4: p = ((*((Uint32*)pa))&0xffffff) != key; break; } if (p) { result = my_max(result, x); } pa += desc->surface->surface->format->BytesPerPixel; } } my_unlock(desc->surface->surface); return result + 1; } static const TileDescriptor * findchar(const Font *font, char c) { return font->ordered_tiles[(unsigned char)c]; } static const TileDescriptor * findchar_slow(const Font *font, char c) { if (c == ' ') return NULL; char *tc; const TileDescriptor *tile; for (tile = font->tiledescriptor, tc = font->charmap; *tc ; ++tile, ++tc) if (*tc == c) return tile; c = tolower(c); for (tile = font->tiledescriptor, tc = font->charmap; *tc ; ++tile, ++tc) if (tolower(*tc) == c) return tile; //debug("Could not find character '%c'", c); return NULL; } void font_create(Font *font, GfxSurface *tiles, const int w, const int h, const int char_spacing, const int space_width, char *charmap) { font->tiledescriptor = gfx_build_tiledescriptor(tiles, w, h, NULL); font->charmap = strdup(charmap); font->w = w; font->h = h; font->char_spacing = char_spacing; font->space_width = space_width ? space_width : w; if (space_width) { for (int i = 0 ; i < (tiles->surface->w/w)*(tiles->surface->h/h) ; ++i) font->tiledescriptor[i].rect.w = tile_width(&font->tiledescriptor[i]); } for (int i = 0 ; i < 256 ; ++i) { font->ordered_tiles[i] = findchar_slow(font, i); } } void font_destroy(Font *font) { if (font->tiledescriptor) free(font->tiledescriptor); if (font->charmap) free(font->charmap); if (font->surface) gfx_free_surface(font->surface); font->tiledescriptor = NULL; font->charmap = NULL; font->surface = NULL; } static void inner_write(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 * cursor, SDL_Rect *bounds, const char * text) { const char *c = text; int x = (*cursor & 0xff) * font->w, y = ((*cursor >> 8) & 0xff) * font->h, cr = 0, right = dest->screen_w; if (r) { x = x + (cr = r->x); y = r->y + y; right = r->w + r->x; } for (;*c;++c) { if (*c == '\n' || x >= right) { y += font->h; x = cr; *cursor &= (Uint16)0xff00; *cursor += 0x0100; if (*c == '\n') continue; } const TileDescriptor *tile = findchar(font, *c); if (tile) { SDL_Rect rect = { x, y, tile->rect.w, tile->rect.h }; my_BlitSurface(tile->surface, (SDL_Rect*)&tile->rect, dest, &rect); if (bounds) { if (bounds->w == 0) memcpy(bounds, &rect, sizeof(rect)); else { bounds->x = my_min(rect.x, bounds->x); bounds->y = my_min(rect.y, bounds->y); bounds->w = my_max(rect.x + rect.w - bounds->x, bounds->w); bounds->h = my_max(rect.y + rect.h - bounds->y, bounds->h); } } x += tile->rect.w + font->char_spacing; } else { if (bounds) { if (bounds->w == 0) { bounds->x = x; bounds->y = y; bounds->w = font->w; bounds->h = font->h; } else { bounds->x = my_min(x, bounds->x); bounds->y = my_min(y, bounds->y); bounds->w = my_max(x + font->w - bounds->x, bounds->w); bounds->h = my_max(y + font->h - bounds->y, bounds->h); } } x += font->space_width; } ++*cursor; } } void font_write_va(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 * cursor, SDL_Rect *bounds, const char * text, va_list va) { #ifdef USESTATICTEMPSTRINGS const int len = 2048; char formatted[len]; #else va_list va_cpy; va_copy( va_cpy, va ); const int len = vsnprintf(NULL, 0, text, va_cpy) + 1; char * formatted = malloc(len * sizeof(*formatted)); va_end( va_cpy ); #endif vsnprintf(formatted, len, text, va); inner_write(font, dest, r, cursor, bounds, formatted); #ifndef USESTATICTEMPSTRINGS free(formatted); #endif } static int font_load_inner(GfxDomain *domain, Font *font, Bundle *fb) { SDL_RWops *rw = SDL_RWFromBundle(fb, "font.bmp"); #ifdef USESDL_IMAGE if (!rw) rw = SDL_RWFromBundle(fb, "font.png"); #endif if (rw) { GfxSurface * s= gfx_load_surface_RW(domain, rw, GFX_KEYED); char map[1000]; memset(map, 0, sizeof(map)); { SDL_RWops *rw = SDL_RWFromBundle(fb, "charmap.txt"); if (rw) { char temp[1000]; memset(temp, 0, sizeof(temp)); rw->read(rw, temp, 1, sizeof(temp)-1); SDL_RWclose(rw); size_t len = my_min(strlen(temp), 256); const char *c = temp; char *m = map; debug("Read charmap (%u chars)", len); while (*c) { if (*c == '\\' && len > 1) { char hex = 0; int digits = 0; while (len > 1 && digits < 2) { char digit = tolower(*(c + 1)); if (!((digit >= '0' && digit <= '9') || (digit >= 'a' && digit <= 'f'))) { if (digits < 1) goto not_hex; break; } hex <<= 4; hex |= (digit >= 'a' ? digit - 'a' + 10 : digit - '0') & 0x0f; --len; ++digits; ++c; } if (digits < 1) goto not_hex; ++c; *(m++) = hex; } else { not_hex: *(m++) = *(c++); --len; } } if (*c && len == 0) warning("Excess font charmap chars (max. 256)"); } else { strcpy(map, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); debug("Charmap not found in font file"); } } int w, h, spacing = 0, spacewidth = 0; { SDL_RWops *rw = SDL_RWFromBundle(fb, "res.txt"); char res[10] = { 0 }; if (rw) { rw->read(rw, res, 1, sizeof(res)-1); SDL_RWclose(rw); sscanf(res, "%d %d %d %d", &w, &h, &spacing, &spacewidth); } else { w = 8; h = 9; } } font_create(font, s, w, h, spacing, spacewidth, map); font->surface = s; bnd_free(fb); return 1; } else { warning("Bitmap not found in font file"); bnd_free(fb); return 0; } } int font_load_file(GfxDomain *domain, Font *font, char *filename) { debug("Loading font '%s'", filename); Bundle fb; if (bnd_open(&fb, filename)) { return font_load_inner(domain, font, &fb); } return 0; } int font_load(GfxDomain *domain, Font *font, Bundle *bundle, char *name) { debug("Loading font '%s'", name); SDL_RWops *rw = SDL_RWFromBundle(bundle, name); if (rw) { int r = 0; Bundle fb; if (bnd_open_RW(&fb, rw)) { r = font_load_inner(domain, font, &fb); } SDL_RWclose(rw); return r; } else return 0; } void font_write_cursor_args(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 *cursor, SDL_Rect *bounds, const char * text, ...) { va_list va; va_start(va, text); font_write_va(font, dest, r, cursor, bounds, text, va); va_end(va); } void font_write_cursor(const Font *font, GfxDomain *dest, const SDL_Rect *r, Uint16 *cursor, SDL_Rect *bounds, const char * text) { inner_write(font, dest, r, cursor, bounds, text); } void font_write(const Font *font, GfxDomain *dest, const SDL_Rect *r, const char * text) { Uint16 cursor = 0; inner_write(font, dest, r, &cursor, NULL, text); } void font_write_args(const Font *font, GfxDomain *dest, const SDL_Rect *r, const char * text, ...) { Uint16 cursor = 0; va_list va; va_start(va, text); font_write_va(font, dest, r, &cursor, NULL, text, va); va_end(va); } int font_load_RW(GfxDomain *domain, Font *font, SDL_RWops *rw) { int r = 0; Bundle fb; if (bnd_open_RW(&fb, rw)) { r = font_load_inner(domain, font, &fb); } return r; } int font_text_width(const Font *font, const char *text) { const char *c = text; int w = 0; for (;*c && *c != '\n';++c) { const TileDescriptor *tile = findchar(font, *c); w += tile ? tile->rect.w + font->char_spacing : font->space_width; } return w; } void font_set_color(Font *font, Uint32 rgb) { gfx_surface_set_color(font->surface, rgb); } klystrack-0.20171212/klystron/src/snd/0000755000000000000000000000000013214501362016053 5ustar rootrootklystrack-0.20171212/klystron/src/snd/cydrvb.h0000644000000000000000000000400713214501362017516 0ustar rootroot#ifndef CYDRVB_H #define CYDRVB_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" #include // Max delay length in milliseconds #define CYDRVB_SIZE 2000 #define CYDRVB_TAPS 16 #define CYDRVB_0dB 2048 #define CYDRVB_LOW_LIMIT (int)(100.0 * log(1.0 / (double)CYDRVB_0dB)) typedef struct { int position; #ifdef STEREOOUTPUT int gain_r, gain_l; #else int gain; #endif int delay; } CydTap; typedef struct { Sint32 *buffer; int size, rate; int position; CydTap tap[CYDRVB_TAPS]; } CydReverb; void cydrvb_init(CydReverb *rvb, int rate); void cydrvb_deinit(CydReverb *rvb); #ifdef STEREOOUTPUT void cydrvb_cycle(CydReverb *rvb, Sint32 left, Sint32 right); void cydrvb_output(CydReverb *rvb, Sint32 *left, Sint32 *right); #else void cydrvb_cycle(CydReverb *rvb, Sint32 input); Sint32 cydrvb_output(CydReverb *rvb); #endif void cydrvb_set_tap(CydReverb *rvb, int idx, int delay_ms, int gain_db, int panning); #endif klystrack-0.20171212/klystron/src/snd/music.h0000644000000000000000000002350513214501362017351 0ustar rootroot#ifndef MUSIC_H #define MUSIC_H /* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "cyd.h" #include "cydfx.h" #include #define MUS_PROG_LEN 32 #define MUS_MAX_CHANNELS CYD_MAX_CHANNELS #define MUS_VERSION 27 #define MUS_SONG_TITLE_LEN 64 #define MUS_INSTRUMENT_NAME_LEN 32 #define MUS_WAVETABLE_NAME_LEN MUS_INSTRUMENT_NAME_LEN typedef struct { Uint8 a, d, s, r; // 0-15 } MusAdsr; typedef struct { Uint32 flags; Uint32 cydflags; MusAdsr adsr; Uint8 sync_source, ring_mod; // 0xff == self Uint16 pw; Uint8 volume; Uint16 program[MUS_PROG_LEN]; Uint8 prog_period; Uint8 vibrato_speed, vibrato_depth, slide_speed, pwm_speed, pwm_depth; Uint8 base_note; Uint16 cutoff; Uint8 resonance; Uint8 flttype; Uint8 ym_env_shape; Sint16 buzz_offset; Uint8 fx_bus, vib_shape, vib_delay, pwm_shape; char name[MUS_INSTRUMENT_NAME_LEN + 1]; Uint8 wavetable_entry; Uint8 lfsr_type; Sint8 finetune; Uint32 fm_flags; Uint8 fm_modulation, fm_feedback, fm_wave, fm_harmonic; MusAdsr fm_adsr; Uint8 fm_attack_start; } MusInstrument; enum { MUS_INST_PROG_SPEED_RELATIVE = 0, // chn.current_tick / mus.tick_period * ins.prog_period MUS_INST_PROG_SPEED_ABSOLUTE = 1, // absolute number of ticks MUS_INST_DRUM = 2, MUS_INST_INVERT_VIBRATO_BIT = 4, MUS_INST_LOCK_NOTE = 8, MUS_INST_SET_PW = 16, MUS_INST_SET_CUTOFF = 32, MUS_INST_YM_BUZZ = 64, MUS_INST_RELATIVE_VOLUME = 128, MUS_INST_QUARTER_FREQ = 256, MUS_INST_WAVE_LOCK_NOTE = 512, MUS_INST_NO_PROG_RESTART = 1024, MUS_INST_MULTIOSC = 2048, }; enum { MUS_FX_WAVE_NOISE = 1, MUS_FX_WAVE_PULSE = 2, MUS_FX_WAVE_TRIANGLE = 4, MUS_FX_WAVE_SAW = 8, MUS_FX_WAVE_LFSR = 16, MUS_FX_WAVE_WAVE = 32, }; typedef struct { MusInstrument *instrument; Uint16 note; Uint8 volume; // ------ Uint8 arpeggio_note; Uint16 target_note, last_note, fixed_note; volatile Uint32 flags; Uint32 current_tick; Uint8 program_counter, program_tick, program_loop, prog_period; Sint16 buzz_offset; } MusChannel; typedef struct { Uint8 note, instrument, ctrl; Uint16 command; Uint8 volume; } MusStep; typedef struct { Uint16 position; Uint16 pattern; Sint8 note_offset; } MusSeqPattern; typedef struct { MusStep *step; Uint16 num_steps; Uint8 color; } MusPattern; typedef struct { MusInstrument *instrument; Uint8 num_instruments; MusPattern *pattern; Uint16 num_patterns; MusSeqPattern *sequence[MUS_MAX_CHANNELS]; Uint16 num_sequences[MUS_MAX_CHANNELS]; Uint16 song_length, loop_point; Uint8 song_speed, song_speed2, song_rate; Uint16 time_signature, sequence_step; Uint32 flags; Uint8 num_channels; Uint8 multiplex_period, pitch_inaccuracy; char title[MUS_SONG_TITLE_LEN + 1]; CydFxSerialized fx[CYD_MAX_FX_CHANNELS]; Uint8 master_volume; Uint8 default_volume[MUS_MAX_CHANNELS]; Sint8 default_panning[MUS_MAX_CHANNELS]; char **wavetable_names; int num_wavetables; } MusSong; typedef struct { MusPattern *pattern; Uint8 last_ctrl; Uint16 pw, pattern_step, sequence_position, slide_speed; Uint16 vibrato_position, pwm_position; Sint8 note_offset; Uint16 filter_cutoff; Uint8 filter_resonance; Uint8 extarp1, extarp2; Uint8 volume; Uint8 vib_delay; } MusTrackStatus; typedef struct { MusChannel channel[MUS_MAX_CHANNELS]; Uint8 tick_period; // 1 = at the rate this is polled // ---- MusTrackStatus song_track[MUS_MAX_CHANNELS]; MusSong *song; Uint8 song_counter; Uint16 song_position; CydEngine *cyd; Uint8 current_tick; Uint8 volume, play_volume; // 0..128 Uint8 multiplex_ctr; Uint32 flags; Uint32 ext_sync_ticks; Uint32 pitch_mask; } MusEngine; enum { MUS_CHN_PLAYING = 1, MUS_CHN_PROGRAM_RUNNING = 2, MUS_CHN_DISABLED = 4 }; enum { MUS_NOTE_NONE = 0xff, MUS_NOTE_RELEASE = 0xfe }; enum { MUS_PAK_BIT_NOTE = 1, MUS_PAK_BIT_INST = 2, MUS_PAK_BIT_CTRL = 4, MUS_PAK_BIT_CMD = 8, /* -- these go in ctrl byte -- */ MUS_PAK_BIT_VOLUME = 128 }; enum { MUS_EXT_SYNC = 1 }; #define MUS_NOTE_VOLUME_SET_PAN 0xa0 #define MUS_NOTE_VOLUME_PAN_LEFT 0xb0 #define MUS_NOTE_VOLUME_PAN_RIGHT 0xc0 #define MUS_NOTE_VOLUME_FADE_UP 0xe0 #define MUS_NOTE_VOLUME_FADE_DN 0xd0 #define MUS_NOTE_NO_VOLUME 0xff #define MUS_NOTE_NO_INSTRUMENT 0xff #define MUS_CTRL_BIT 1 #define MAX_VOLUME 128 enum { MUS_FX_ARPEGGIO = 0x0000, MUS_FX_ARPEGGIO_ABS = 0x4000, MUS_FX_SET_EXT_ARP = 0x1000, MUS_FX_PORTA_UP = 0x0100, MUS_FX_PORTA_DN = 0x0200, MUS_FX_PORTA_UP_LOG = 0x0500, MUS_FX_PORTA_DN_LOG = 0x0600, MUS_FX_SLIDE = 0x0300, MUS_FX_VIBRATO = 0x0400, MUS_FX_FADE_VOLUME = 0x0a00, MUS_FX_SET_VOLUME = 0x0c00, MUS_FX_LOOP_PATTERN = 0x0d00, MUS_FX_SKIP_PATTERN = 0x2d00, MUS_FX_EXT = 0x0e00, MUS_FX_EXT_PORTA_UP = 0x0e10, MUS_FX_EXT_PORTA_DN = 0x0e20, MUS_FX_EXT_RETRIGGER = 0x0e90, MUS_FX_EXT_FADE_VOLUME_DN = 0x0ea0, MUS_FX_EXT_FADE_VOLUME_UP = 0x0eb0, MUS_FX_EXT_NOTE_CUT = 0x0ec0, MUS_FX_EXT_NOTE_DELAY = 0x0ed0, MUS_FX_SET_SPEED = 0x0f00, MUS_FX_SET_RATE = 0x1f00, MUS_FX_PORTA_UP_SEMI = 0x1100, MUS_FX_PORTA_DN_SEMI = 0x1200, MUS_FX_SET_PANNING = 0x1800, MUS_FX_PAN_LEFT = 0x1700, MUS_FX_PAN_RIGHT = 0x1900, MUS_FX_FADE_GLOBAL_VOLUME = 0x1a00, MUS_FX_SET_GLOBAL_VOLUME = 0x1d00, MUS_FX_SET_CHANNEL_VOLUME = 0x1c00, MUS_FX_CUTOFF_UP = 0x2100, MUS_FX_CUTOFF_DN = 0x2200, MUS_FX_CUTOFF_SET = 0x2900, MUS_FX_RESONANCE_SET = 0x2a00, MUS_FX_FILTER_TYPE = 0x2b00, MUS_FX_CUTOFF_SET_COMBINED = 0x2c00, MUS_FX_BUZZ_UP = 0x3100, MUS_FX_BUZZ_DN = 0x3200, MUS_FX_BUZZ_SHAPE = 0x3f00, MUS_FX_BUZZ_SET = 0x3900, MUS_FX_BUZZ_SET_SEMI = 0x3a00, MUS_FX_FM_SET_MODULATION = 0x3300, MUS_FX_FM_SET_FEEDBACK = 0x3400, MUS_FX_FM_SET_HARMONIC = 0x3500, MUS_FX_FM_SET_WAVEFORM = 0x3600, MUS_FX_PW_DN = 0x0700, MUS_FX_PW_UP = 0x0800, MUS_FX_PW_SET = 0x0900, MUS_FX_SET_WAVEFORM = 0x0b00, MUS_FX_SET_FXBUS = 0x1b00, MUS_FX_SET_SYNCSRC = 0x7a00, MUS_FX_SET_RINGSRC = 0x7b00, MUS_FX_SET_WAVETABLE_ITEM = 0x3b00, MUS_FX_SET_DOWNSAMPLE = 0x1e00, MUS_FX_WAVETABLE_OFFSET = 0x5000, MUS_FX_CUTOFF_FINE_SET = 0x6000, MUS_FX_END = 0xffff, MUS_FX_JUMP = 0xff00, MUS_FX_LABEL = 0xfd00, MUS_FX_LOOP = 0xfe00, MUS_FX_TRIGGER_RELEASE = 0x7c00, MUS_FX_RESTART_PROGRAM = 0x7d00, MUS_FX_NOP = 0xfffe }; enum { MUS_CTRL_LEGATO = MUS_CTRL_BIT, MUS_CTRL_SLIDE = MUS_CTRL_BIT << 1, MUS_CTRL_VIB = MUS_CTRL_BIT << 2 }; enum { MUS_ENABLE_REVERB = 1, MUS_ENABLE_CRUSH = 2, MUS_ENABLE_MULTIPLEX = 4, MUS_NO_REPEAT = 8 }; enum { MUS_SHAPE_SINE, MUS_SHAPE_RAMP_UP, MUS_SHAPE_RAMP_DN, MUS_SHAPE_RANDOM, MUS_SHAPE_SQUARE, MUS_NUM_SHAPES }; #define MUS_INST_SIG "cyd!inst" #define MUS_SONG_SIG "cyd!song" #define MUS_FX_SIG "cyd!efex" #ifdef USESDL_RWOPS #include "SDL_rwops.h" typedef SDL_RWops RWops; #else typedef struct RWops { int (*read)(struct RWops *context, void *ptr, int size, int maxnum); int (*close)(struct RWops *context); union { FILE *fp; struct { Uint32 ptr, length; void *base; } mem; }; int close_fp; } RWops; #endif int mus_advance_tick(void* udata); int mus_trigger_instrument(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning); void mus_set_channel_volume(MusEngine* mus, int chan, int volume); void mus_release(MusEngine* mus, int chan); void mus_init_engine(MusEngine *mus, CydEngine *cyd); void mus_set_song(MusEngine *mus, MusSong *song, Uint16 position); int mus_poll_status(MusEngine *mus, int *song_position, int *pattern_position, MusPattern **pattern, MusChannel *channel, int *cyd_env, int *mus_note, Uint64 *time_played); int mus_load_instrument_file(Uint8 version, FILE *f, MusInstrument *inst, CydWavetableEntry *wavetable_entries); int mus_load_instrument_file2(FILE *f, MusInstrument *inst, CydWavetableEntry *wavetable_entries); int mus_load_instrument_RW(Uint8 version, RWops *ctx, MusInstrument *inst, CydWavetableEntry *wavetable_entries); int mus_load_instrument_RW2(RWops *ctx, MusInstrument *inst, CydWavetableEntry *wavetable_entries); int mus_load_instrument(const char *path, MusInstrument *inst, CydWavetableEntry *wavetable_entries); void mus_get_default_instrument(MusInstrument *inst); int mus_load_song(const char *path, MusSong *song, CydWavetableEntry *wavetable_entries); int mus_load_song_file(FILE *f, MusSong *song, CydWavetableEntry *wavetable_entries); int mus_load_song_RW(RWops *rw, MusSong *song, CydWavetableEntry *wavetable_entries); int mus_load_fx_RW(RWops *ctx, CydFxSerialized *fx); int mus_load_fx_file(FILE *f, CydFxSerialized *fx); int mus_load_fx(const char *path, CydFxSerialized *fx); void mus_free_song(MusSong *song); void mus_set_fx(MusEngine *mus, MusSong *song); Uint32 mus_ext_sync(MusEngine *mus); Uint32 mus_get_playtime_at(MusSong *song, int position); #endif klystrack-0.20171212/klystron/src/snd/cydfx.c0000644000000000000000000000613613214501362017342 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydfx.h" #include "cyd.h" #ifdef STEREOOUTPUT void cydfx_output(CydFx *fx, Sint32 fx_l, Sint32 fx_r, Sint32 *left, Sint32 *right) { *left = fx_l; *right = fx_r; #else Sint32 cydfx_output(CydFx *fx, Sint32 fx_input) { Sint32 v = fx_input; #endif #ifndef CYD_DISABLE_FX if (fx->flags & CYDFX_ENABLE_CHORUS) { #ifdef STEREOOUTPUT cydchr_output(&fx->chr, fx_l, fx_r, left, right); #else // it's a stereo effect #endif } if (fx->flags & CYDFX_ENABLE_REVERB) { #ifdef STEREOOUTPUT cydrvb_cycle(&fx->rvb, fx_l, fx_l); cydrvb_output(&fx->rvb, &fx_l, &fx_r); *left += fx_l; *right += fx_r; #else cydrvb_cycle(&fx->rvb, fx_input); v = cydrvb_output(&fx->rvb); #endif } if (fx->flags & CYDFX_ENABLE_CRUSH) { #ifdef STEREOOUTPUT cydcrush_output(&fx->crush, *left, *right, left, right); #else v = cydcrush_output(&fx->crush, v); #endif } #endif // CYD_DISABLE_FX #ifndef STEREOOUTPUT return v; #endif } void cydfx_init(CydFx *fx, int rate) { #ifndef CYD_DISABLE_FX cydrvb_init(&fx->rvb, rate); #ifdef STEREOOUTPUT cydchr_init(&fx->chr, rate); #endif cydcrush_init(&fx->crush, rate); #endif // CYD_DISABLE_FX } void cydfx_deinit(CydFx *fx) { #ifndef CYD_DISABLE_FX cydrvb_deinit(&fx->rvb); #ifdef STEREOOUTPUT cydchr_deinit(&fx->chr); #endif cydcrush_deinit(&fx->crush); #endif // CYD_DISABLE_FX } void cydfx_set(CydFx *fx, const CydFxSerialized *ser) { #ifndef CYD_DISABLE_FX fx->flags = ser->flags; for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { if (ser->rvb.tap[i].flags & 1) cydrvb_set_tap(&fx->rvb, i, ser->rvb.tap[i].delay, ser->rvb.tap[i].gain, ser->rvb.tap[i].panning); else cydrvb_set_tap(&fx->rvb, i, 0, CYDRVB_LOW_LIMIT, 0); } cydchr_set(&fx->chr, ser->chr.rate, ser->chr.min_delay, ser->chr.max_delay, ser->chr.sep); cydcrush_set(&fx->crush, ser->crushex.downsample, ser->crush.bit_drop, fx->flags & CYDFX_ENABLE_CRUSH_DITHER, ser->crushex.gain); #endif // CYD_DISABLE_FX } klystrack-0.20171212/klystron/src/snd/cydfm.h0000644000000000000000000000177713214501362017342 0ustar rootroot#pragma once #include "cydadsr.h" #include "cydentry.h" #include "cydtypes.h" #include "cydwave.h" typedef struct { Uint32 flags; Uint8 feedback; // 0-7 Uint8 harmonic; // 0-15 CydAdsr adsr; Uint32 period; Uint32 wave_period; Uint32 accumulator; const CydWavetableEntry *wave_entry; CydWaveState wave; Uint32 fb1, fb2, env_output; Uint32 current_modulation; Uint8 attack_start; } CydFm; #include "cyd.h" struct CydEngine_t; void cydfm_init(CydFm *fm); void cydfm_cycle(const struct CydEngine_t *cyd, CydFm *fm); void cydfm_cycle_oversample(const struct CydEngine_t *cyd, CydFm *fm); void cydfm_set_frequency(const struct CydEngine_t *cyd, CydFm *fm, Uint32 base_frequency); Uint32 cydfm_modulate(const struct CydEngine_t *cyd, const CydFm *fm, Uint32 accumulator); CydWaveAcc cydfm_modulate_wave(const struct CydEngine_t *cyd, const CydFm *fm, const CydWavetableEntry *wave, CydWaveAcc accumulator); void cydfm_set_wave_entry(CydFm *fm, const CydWavetableEntry * entry); klystrack-0.20171212/klystron/src/snd/cydchr.h0000644000000000000000000000317213214501362017503 0ustar rootroot#ifndef CYDCHR_H #define CYDCHR_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #define CYDCHR_SIZE 50 #include "cydtypes.h" typedef struct { Sint32 *buffer, *lut; int sample_rate; int min_delay, max_delay; int pos_l, pos_r, pos_buf, buf_size, lut_size; } CydChorus; void cydchr_output(CydChorus *chr, Sint32 in_l, Sint32 in_r, Sint32 *out_l, Sint32 *out_r); void cydchr_set(CydChorus *chr, int rate /* 1 = 0.1 Hz */, int min_delay, int max_delay, int stereo_separation); void cydchr_init(CydChorus *chr, int sample_rate); void cydchr_deinit(CydChorus *chr); #endif klystrack-0.20171212/klystron/src/snd/cydrvb.c0000644000000000000000000000775113214501362017522 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cyddefs.h" #include "cydrvb.h" #include "macros.h" #include #include #include void cydrvb_init(CydReverb *rvb, int rate) { memset(rvb, 0, sizeof(*rvb)); int bufsize = CYDRVB_SIZE * rate / 1000; rvb->size = bufsize; rvb->rate = rate; #ifdef STEREOOUTPUT rvb->buffer = calloc(sizeof(*rvb->buffer) * 2, bufsize); #else rvb->buffer = calloc(sizeof(*rvb->buffer), bufsize); #endif for (int i = 0 ; i < CYDRVB_TAPS ; ++i) cydrvb_set_tap(rvb, i, i * 100 + 50, (i + 1) * -30, CYD_PAN_CENTER); } void cydrvb_deinit(CydReverb *rvb) { free(rvb->buffer); rvb->buffer = NULL; } #ifdef STEREOOUTPUT void cydrvb_cycle(CydReverb *rvb, Sint32 left, Sint32 right) { for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { ++rvb->tap[i].position; if (rvb->tap[i].position >= rvb->size) rvb->tap[i].position = 0; } ++rvb->position; if (rvb->position >= rvb->size) rvb->position = 0; rvb->buffer[rvb->position * 2] = left; rvb->buffer[rvb->position * 2 + 1] = right; } #else void cydrvb_cycle(CydReverb *rvb, Sint32 input) { for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { ++rvb->tap[i].position; if (rvb->tap[i].position >= rvb->size) rvb->tap[i].position = 0; } ++rvb->position; if (rvb->position >= rvb->size) rvb->position = 0; rvb->buffer[rvb->position] = input; } #endif #ifdef STEREOOUTPUT void cydrvb_output(CydReverb *rvb, Sint32 *left, Sint32 *right) { *left = 0; *right = 0; for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { if (rvb->tap[i].gain_l != 0 || rvb->tap[i].gain_r != 0) { *left += rvb->tap[i].gain_l * (Sint32)rvb->buffer[rvb->tap[i].position * 2] / CYDRVB_0dB; *right += rvb->tap[i].gain_r * (Sint32)rvb->buffer[rvb->tap[i].position * 2 + 1] / CYDRVB_0dB; } } } #else Sint32 cydrvb_output(CydReverb *rvb) { Sint32 o = 0; for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { if (rvb->tap[i].gain != 0) { o += rvb->tap[i].gain * rvb->buffer[rvb->tap[i].position] / CYDRVB_0dB; } } return o; } #endif void cydrvb_set_tap(CydReverb *rvb, int idx, int delay_ms, int gain_db, int panning) { rvb->tap[idx].delay = delay_ms; rvb->tap[idx].position = (rvb->position - (delay_ms * rvb->rate / 1000) + rvb->size) % rvb->size; if (gain_db <= CYDRVB_LOW_LIMIT) { #ifdef STEREOOUTPUT rvb->tap[idx].gain_l = 0; rvb->tap[idx].gain_r = 0; #else rvb->tap[idx].gain = 0; #endif } else { #ifdef STEREOOUTPUT panning = my_min(CYD_PAN_RIGHT, my_max(CYD_PAN_LEFT, panning)); float a = M_PI / 2 * (float)(panning - CYD_PAN_LEFT) / (CYD_PAN_RIGHT - CYD_PAN_LEFT); int gain = pow(10.0, (double)gain_db * 0.01) * CYDRVB_0dB; rvb->tap[idx].gain_l = gain * cos(a); rvb->tap[idx].gain_r = gain * sin(a); #else int gain = pow(10.0, (double)gain_db * 0.01) * CYDRVB_0dB; rvb->tap[idx].gain = gain; #endif } } klystrack-0.20171212/klystron/src/snd/cydtypes.h0000644000000000000000000000122713214501362020072 0ustar rootroot#ifndef CYDTYPES_H #define CYDTYPES_H /* SDL-equivalent types */ #include "SDL.h" #ifndef USENATIVEAPIS typedef SDL_mutex * CydMutex; #else # ifdef WIN32 #include /*typedef BYTE Uint8; typedef CHAR Sint8; typedef WORD Uint16; typedef SHORT Sint16; typedef DWORD Uint32; typedef INT Sint32; typedef unsigned long long Uint64;*/ typedef CRITICAL_SECTION CydMutex; # else # error USENATIVEAPIS: Platform not supported # endif #endif #ifdef LOWRESWAVETABLE typedef Uint32 CydWaveAcc; typedef Sint32 CydWaveAccSigned; #else typedef Uint64 CydWaveAcc; typedef Sint64 CydWaveAccSigned; #endif #endif klystrack-0.20171212/klystron/src/snd/cyddefs.h0000644000000000000000000000405613214501362017652 0ustar rootroot#ifndef CYDDEFS_H #define CYDDEFS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #define RANDOM_SEED 0xf31782ce #define CLOCK 985250 #define PRE_GAIN 1 #define PRE_GAIN_DIVISOR 4 #define OUTPUT_BITS 16 #define MAX_OVERSAMPLE 2 #define ACC_BITS (23 + MAX_OVERSAMPLE) #define ENVELOPE_SCALE 2 #ifdef LOWRESWAVETABLE #define WAVETABLE_RESOLUTION 2048 #else #define WAVETABLE_RESOLUTION 65536 #endif #define ACC_LENGTH (1 << (ACC_BITS - 1)) // Osc counter length #define YM_LENGTH (ACC_LENGTH) // YM envelope counter length #define MAX_VOLUME 128 #define CYD_WAVE_MAX_ENTRIES 128 #define CYD_BASE_FREQ 22050 #define CYD_MAX_CHANNELS 32 #define CYD_MAX_FX_CHANNELS 8 #define CYD_SUB_OSCS 3 #define CYD_PAN_CENTER 64 #define CYD_PAN_LEFT 0 #define CYD_PAN_RIGHT 128 #define CYD_STEREO_GAIN 2048 #define CYD_CUTOFF_MAX 2048 #define CYD_CHORUS_OVERSAMPLE 1 #define WAVE_AMP (1 << OUTPUT_BITS) #define BUFFER_GRANULARITY 150 // mutex is locked and audio generated in 150 sample blocks #endif klystrack-0.20171212/klystron/src/snd/cydflt.c0000644000000000000000000000426613214501362017514 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydflt.h" #include "macros.h" #include void cydflt_set_coeff(CydFilter *flt, Uint16 frequency, Uint16 resonance) { flt->q = 2048 - frequency; flt->p = frequency + ((Sint32)(0.8f * 2048.0f) * frequency / 2048 * flt->q) / 2048; flt->f = flt->p + flt->p - 2048; flt->q = resonance; } void cydflt_cycle(CydFilter *flt, Sint32 input) { input -= flt->q * flt->b4 / 2048; //feedback Sint32 t1 = flt->b1; flt->b1 = (input + flt->b0) * flt->p / 2048- flt->b1 * flt->f / 2048; Sint32 t2 = flt->b2; flt->b2 = (flt->b1 + t1) * flt->p / 2048 - flt->b2 * flt->f / 2048; t1 = flt->b3; flt->b3 = (flt->b2 + t2) * flt->p / 2048 - flt->b3 * flt->f / 2048; flt->b4 = (flt->b3 + t1) * flt->p / 2048 - flt->b4 * flt->f / 2048; flt->b4 = my_min(32767, my_max(-32768, flt->b4)); //clipping flt->b0 = input; } Sint32 cydflt_output_lp(CydFilter *flt) { return flt->b4; } Sint32 cydflt_output_hp(CydFilter *flt) { return flt->b0 - flt->b4; } Sint32 cydflt_output_bp(CydFilter *flt) { return 3 * (flt->b3 - flt->b4); } klystrack-0.20171212/klystron/src/snd/cydflt.h0000644000000000000000000000303313214501362017510 0ustar rootroot#ifndef CYDFLT_H #define CYDFLT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" typedef struct { Sint32 f, q, p; Sint32 b0, b1, b2, b3, b4; //filter coefficients } CydFilter; /* 0..2047 */ void cydflt_set_coeff(CydFilter *flt, Uint16 frequency, Uint16 cutoff); void cydflt_cycle(CydFilter *flt, Sint32 input); Sint32 cydflt_output_lp(CydFilter *flt); Sint32 cydflt_output_hp(CydFilter *flt); Sint32 cydflt_output_bp(CydFilter *flt); #endif klystrack-0.20171212/klystron/src/snd/cydentry.h0000644000000000000000000000354613214501362020075 0ustar rootroot#ifndef CYDENTRY_H #define CYDENTRY_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" enum { CYD_WAVE_LOOP = 1, CYD_WAVE_PINGPONG = 2, // ping-pong loop as in FT2 CYD_WAVE_NO_INTERPOLATION = 4, CYD_WAVE_COMPRESSED_DELTA = 8, CYD_WAVE_COMPRESSED_GRAY = 16 }; typedef enum { CYD_WAVE_TYPE_SINT16, // internal format CYD_WAVE_TYPE_SINT8, // amiga modules? CYD_WAVE_TYPE_UINT8 // atari YM files? } CydWaveType; typedef struct { Uint32 flags; Uint32 sample_rate; Uint32 samples, loop_begin, loop_end; Uint16 base_note; Sint16 *data; } CydWavetableEntry; void cyd_wave_entry_init(CydWavetableEntry *entry, const void *data, Uint32 n_samples, CydWaveType sample_type, int channels, int denom, int nom); void cyd_wave_entry_deinit(CydWavetableEntry *entry); #endif klystrack-0.20171212/klystron/src/snd/cydwave.c0000644000000000000000000001222513214501362017663 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydwave.h" #include "cyddefs.h" #include "macros.h" #ifndef LOWRESWAVETABLE typedef Sint64 WaveAccSigned; #else typedef Sint32 WaveAccSigned; #endif #ifndef CYD_DISABLE_WAVETABLE static Sint32 cyd_wave_get_sample_no_interpolation(const CydWavetableEntry *entry, CydWaveAcc wave_acc, int direction) { if (entry->data) { return entry->data[wave_acc / WAVETABLE_RESOLUTION]; } else return 0; } static Sint32 cyd_wave_get_sample_linear(const CydWavetableEntry *entry, CydWaveAcc wave_acc, int direction) { if (entry->data) { if (direction == 0) { int a = wave_acc / WAVETABLE_RESOLUTION; int b = a + 1; if (a >= entry->samples || a < 0) return 0; if ((entry->flags & CYD_WAVE_LOOP) && b >= entry->loop_end) { if (!(entry->flags & CYD_WAVE_PINGPONG)) b = b - entry->loop_end + entry->loop_begin; else b = entry->loop_end - (b - entry->loop_end); } if (b >= entry->samples) return entry->data[a]; else return entry->data[a] + (entry->data[b] - entry->data[a]) * ((CydWaveAccSigned)wave_acc % WAVETABLE_RESOLUTION) / WAVETABLE_RESOLUTION; } else { int a = wave_acc / WAVETABLE_RESOLUTION; int b = a - 1; if (a >= entry->samples || a < 0) return 0; if ((entry->flags & CYD_WAVE_LOOP) && b < (Sint32)entry->loop_begin) { if (!(entry->flags & CYD_WAVE_PINGPONG)) b = b - entry->loop_begin + entry->loop_end; else b = entry->loop_begin - (b - entry->loop_begin); } if (b < 0) return entry->data[a]; else return entry->data[a] + (entry->data[b] - entry->data[a]) * (WAVETABLE_RESOLUTION - ((CydWaveAccSigned)wave_acc % WAVETABLE_RESOLUTION)) / WAVETABLE_RESOLUTION; } } else return 0; } #endif // CYD_DISABLE_WAVETABLE Sint32 cyd_wave_get_sample(const CydWaveState *state, const CydWavetableEntry *wave_entry, CydWaveAcc acc) { #ifndef CYD_DISABLE_WAVETABLE if (wave_entry->flags & CYD_WAVE_NO_INTERPOLATION) { return cyd_wave_get_sample_no_interpolation(wave_entry, acc, state->direction); } else { return cyd_wave_get_sample_linear(wave_entry, acc, state->direction); } #else return 0; #endif // CYD_DISABLE_WAVETABLE } void cyd_wave_cycle(CydWaveState *wave, const CydWavetableEntry *wave_entry) { #ifndef CYD_DISABLE_WAVETABLE if (wave_entry && wave->playing) { if (wave->direction == 0) { wave->acc += wave->frequency; if ((wave_entry->flags & CYD_WAVE_LOOP) && wave_entry->loop_end != wave_entry->loop_begin) { if (wave->acc / WAVETABLE_RESOLUTION >= (Uint64)wave_entry->loop_end) { if (wave_entry->flags & CYD_WAVE_PINGPONG) { wave->acc = (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION - (wave->acc - (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION); wave->direction = 1; } else { wave->acc = wave->acc - (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION + (Uint64)wave_entry->loop_begin * WAVETABLE_RESOLUTION; } } } else { if (wave->acc / WAVETABLE_RESOLUTION >= (Uint64)wave_entry->samples) { // stop playback wave->playing = false; } } } else { wave->acc -= wave->frequency; if ((wave_entry->flags & CYD_WAVE_LOOP) && wave_entry->loop_end != wave_entry->loop_begin) { if ((WaveAccSigned)wave->acc / WAVETABLE_RESOLUTION < (WaveAccSigned)wave_entry->loop_begin) { if (wave_entry->flags & CYD_WAVE_PINGPONG) { wave->acc = (WaveAccSigned)wave_entry->loop_begin * WAVETABLE_RESOLUTION - ((WaveAccSigned)wave->acc - (WaveAccSigned)wave_entry->loop_begin * WAVETABLE_RESOLUTION); wave->direction = 0; } else { wave->acc = wave->acc - (Uint64)wave_entry->loop_begin * WAVETABLE_RESOLUTION + (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION; } } } else { if ((WaveAccSigned)wave->acc < 0) { // stop playback wave->playing = false; } } } } #endif // CYD_DISABLE_WAVETABLE } klystrack-0.20171212/klystron/src/snd/cyd.h0000644000000000000000000001440113214501362017003 0ustar rootroot#ifndef CYD_H #define CYD_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "cydtypes.h" #include "cydflt.h" #include "cydfx.h" #include "cydentry.h" #include "cyddefs.h" #include "cydadsr.h" #include "cydfm.h" #include "cydwave.h" typedef struct { Uint32 frequency; Uint32 accumulator; Uint32 random; // random lfsr Uint32 lfsr, lfsr_period, lfsr_ctr, lfsr_acc; // lfsr state Uint32 reg4, reg5, reg9; // "pokey" lfsr registers CydWaveState wave; } CydOscState; typedef struct { // ---- interface Uint32 flags; Uint16 pw; // 0-2047 Uint8 sync_source, ring_mod; // channel Uint8 flttype; CydAdsr adsr; Uint8 ym_env_shape; #ifdef STEREOOUTPUT Uint8 panning; // 0-128, 64 = center Sint32 gain_left, gain_right; #endif // ---- internal Uint32 sync_bit; Uint32 lfsr_type; const CydWavetableEntry *wave_entry; CydOscState subosc[CYD_SUB_OSCS]; CydFilter flt; int fx_bus; #ifndef CYD_DISABLE_FM CydFm fm; #endif } CydChannel; enum { FLT_LP, FLT_HP, FLT_BP, FLT_TYPES }; enum { CYD_CHN_ENABLE_NOISE = 1, CYD_CHN_ENABLE_PULSE = 2, CYD_CHN_ENABLE_TRIANGLE = 4, CYD_CHN_ENABLE_SAW = 8, CYD_CHN_ENABLE_SYNC = 16, CYD_CHN_ENABLE_GATE = 32, CYD_CHN_ENABLE_KEY_SYNC = 64, CYD_CHN_ENABLE_METAL = 128, CYD_CHN_ENABLE_RING_MODULATION = 256, CYD_CHN_ENABLE_FILTER = 512, CYD_CHN_ENABLE_FX = 1024, CYD_CHN_ENABLE_YM_ENV = 2048, CYD_CHN_ENABLE_WAVE = 4096, CYD_CHN_WAVE_OVERRIDE_ENV = 8192, CYD_CHN_ENABLE_LFSR = 16384, CYD_CHN_ENABLE_FM = 32768 }; enum { CYD_FM_ENABLE_WAVE = CYD_CHN_ENABLE_WAVE, CYD_FM_ENABLE_TRIANGLE = CYD_CHN_ENABLE_TRIANGLE, CYD_FM_ENABLE_PULSE = CYD_CHN_ENABLE_PULSE, CYD_FM_ENABLE_SAW = CYD_CHN_ENABLE_SAW }; enum { ATTACK, DECAY, SUSTAIN, RELEASE, DONE }; enum { CYD_LOCK_REQUEST=1, CYD_LOCK_LOCKED=2, CYD_LOCK_CALLBACK=4 }; #define WAVEFORMS (CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_WAVE|CYD_CHN_ENABLE_LFSR) #define LUT_SIZE 1024 #define YM_LUT_SIZE 16 #define CYD_NUM_WO_BUFFER_SIZE 2000 #define CYD_NUM_WO_BUFFERS 4 #define CYD_NUM_LFSR 16 typedef struct CydEngine_t { CydChannel *channel; int n_channels; Uint32 sample_rate; // ----- internal volatile Uint32 flags; int (*callback)(void*); void *callback_parameter; volatile Uint32 callback_period, callback_counter; Uint16 *lookup_table, *lookup_table_ym; CydFx fx[CYD_MAX_FX_CHANNELS]; #ifdef USESDLMUTEXES CydMutex mutex; #else volatile sig_atomic_t lock_request; volatile sig_atomic_t lock_locked; #endif size_t samples_output; // bytes in last cyd_output_buffer CydWavetableEntry *wavetable_entries; #ifdef USENATIVEAPIS # ifdef WIN32 BOOL thread_running; DWORD thread_handle, cb_handle; CRITICAL_SECTION thread_lock; int buffers_available; int waveout_hdr_idx; HWAVEOUT hWaveOut; WAVEHDR waveout_hdr[CYD_NUM_WO_BUFFERS]; # endif #endif Uint64 samples_played; int oversample; } CydEngine; enum { CYD_PAUSED = 1, CYD_CLIPPING = 2, CYD_SINGLE_THREAD = 8, }; // YM2149 envelope shape flags, CONT is assumed to be always set enum { CYD_YM_ENV_ATT = 1, CYD_YM_ENV_ALT = 2}; /////////////////777 void cyd_init(CydEngine *cyd, Uint16 sample_rate, int initial_channels); void cyd_set_oversampling(CydEngine *cyd, int oversampling); void cyd_reserve_channels(CydEngine *cyd, int channels); void cyd_deinit(CydEngine *cyd); void cyd_reset(CydEngine *cyd); void cyd_set_frequency(CydEngine *cyd, CydChannel *chn, int subosc, Uint16 frequency); void cyd_set_wavetable_frequency(CydEngine *cyd, CydChannel *chn, int subosc, Uint16 frequency); void cyd_reset_wavetable(CydEngine *cyd); void cyd_set_wavetable_offset(CydChannel *chn, Uint16 offset /* 0..0x1000 = 0-100% */); void cyd_set_env_frequency(CydEngine *cyd, CydChannel *chn, Uint16 frequency); void cyd_set_env_shape(CydChannel *chn, Uint8 shape); void cyd_enable_gate(CydEngine *cyd, CydChannel *chn, Uint8 enable); void cyd_set_waveform(CydChannel *chn, Uint32 wave); void cyd_set_wave_entry(CydChannel *chn, const CydWavetableEntry * entry); void cyd_set_filter_coeffs(CydEngine * cyd, CydChannel *chn, Uint16 cutoff, Uint8 resonance); void cyd_pause(CydEngine *cyd, Uint8 enable); void cyd_set_callback(CydEngine *cyd, int (*callback)(void*), void*param, Uint16 period); void cyd_set_callback_rate(CydEngine *cyd, Uint16 period); #ifdef NOSDL_MIXER int cyd_register(CydEngine * cyd, int buffer_length); #else int cyd_register(CydEngine * cyd); #endif int cyd_unregister(CydEngine * cyd); void cyd_lock(CydEngine *cyd, Uint8 enable); #ifdef ENABLEAUDIODUMP void cyd_enable_audio_dump(CydEngine *cyd); void cyd_disable_audio_dump(CydEngine *cyd); #endif #ifdef STEREOOUTPUT void cyd_set_panning(CydEngine *cyd, CydChannel *chn, Uint8 panning); #endif #ifdef NOSDL_MIXER void cyd_output_buffer_stereo(void *udata, Uint8 *_stream, int len); #else void cyd_output_buffer_stereo(int chan, void *_stream, int len, void *udata); #endif Sint32 cyd_env_output(const CydEngine *cyd, Uint32 channel_flags, const CydAdsr *adsr, Sint32 input); Uint32 cyd_cycle_adsr(const CydEngine *eng, Uint32 flags, Uint32 ym_env_shape, CydAdsr *adsr); #endif klystrack-0.20171212/klystron/src/snd/cyd.c0000644000000000000000000010151413214501362017000 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "cyd.h" #include "macros.h" #include #include #include #ifdef ENABLEAUDIODUMP #include #endif #include "cyddefs.h" #include "cydwave.h" #include "freqs.h" #include "cydosc.h" #ifndef USENATIVEAPIS # ifndef NOSDL_MIXER # include "SDL_mixer.h" # endif #else # ifdef WIN32 # endif #endif #define envspd(cyd,slope) (slope!=0?(((Uint64)0xff0000 / ((slope) * (slope) * 256 / (ENVELOPE_SCALE * ENVELOPE_SCALE))) * CYD_BASE_FREQ / cyd->sample_rate):((Uint64)0xff0000 * CYD_BASE_FREQ / cyd->sample_rate)) // used lfsr-generator for this: inline static void shift_lfsr(Uint32 *v, int tap_0, int tap_1) { typedef unsigned int T; const T zero = (T)(0); const T lsb = zero + (T)(1); const T feedback = ( (lsb << (tap_0)) ^ (lsb << (tap_1)) ); *v = (*v >> 1) ^ ((zero - (*v & lsb)) & feedback); } static void cyd_init_channel(CydEngine *cyd, CydChannel *chn) { memset(chn, 0, sizeof(*chn)); chn->pw = 0x400; cyd_set_filter_coeffs(cyd, chn, 2047, 0); #ifdef STEREOOUTPUT cyd_set_panning(cyd, chn, CYD_PAN_CENTER); #endif for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { chn->subosc[s].random = RANDOM_SEED; chn->subosc[s].reg4 = chn->subosc[s].reg5 = chn->subosc[s].reg9 = 1; } #ifndef CYD_DISABLE_FM cydfm_init(&chn->fm); #endif } static void cyd_init_log_tables(CydEngine *cyd) { for (int i = 0 ; i < LUT_SIZE ; ++i) { cyd->lookup_table[i] = i * (i/2) / ((LUT_SIZE*LUT_SIZE / 65536)/2); } #ifndef CYD_DISABLE_BUZZ for (int i = 0 ; i < YM_LUT_SIZE ; ++i) { static const int ymVolumeTable[16] = { 62,161,265,377,580,774,1155,1575,2260,3088,4570,6233,9330,13187,21220,32767}; // from leonard's code cyd->lookup_table_ym[i] = ymVolumeTable[i]; //(Uint32)32767 * (Uint32)(i+1) * (Uint32)(i+1) * (Uint32)(i+1) / (Uint32)(YM_LUT_SIZE * YM_LUT_SIZE * YM_LUT_SIZE); } cyd->lookup_table_ym[0] = 0; #endif } void cyd_reset_wavetable(CydEngine *cyd) { #ifndef CYD_DISABLE_WAVETABLE memset(cyd->wavetable_entries, 0, sizeof(cyd->wavetable_entries[0]) * CYD_WAVE_MAX_ENTRIES); for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { cyd_wave_entry_init(&cyd->wavetable_entries[i], NULL, 0, 0, 0, 0, 0); } #endif } void cyd_init(CydEngine *cyd, Uint16 sample_rate, int channels) { memset(cyd, 0, sizeof(*cyd)); cyd->sample_rate = sample_rate; cyd->lookup_table = malloc(sizeof(*cyd->lookup_table) * LUT_SIZE); cyd->oversample = MAX_OVERSAMPLE; #ifndef CYD_DISABLE_BUZZ cyd->lookup_table_ym = malloc(sizeof(*cyd->lookup_table) * YM_LUT_SIZE); #endif #ifndef USENATIVEAPIS # ifdef USESDLMUTEXES cyd->mutex = SDL_CreateMutex(); # endif #else # ifdef WIN32 InitializeCriticalSection(&cyd->mutex); InitializeCriticalSection(&cyd->thread_lock); # endif #endif cyd_init_log_tables(cyd); for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i) cydfx_init(&cyd->fx[i], sample_rate); #ifndef CYD_DISABLE_WAVETABLE cyd->wavetable_entries = calloc(sizeof(cyd->wavetable_entries[0]), CYD_WAVE_MAX_ENTRIES); cyd_reset_wavetable(cyd); #endif cyd_reserve_channels(cyd, channels); } void cyd_set_oversampling(CydEngine *cyd, int oversampling) { cyd->oversample = oversampling; } void cyd_reserve_channels(CydEngine *cyd, int channels) { debug("Reserving %d Cyd channels", channels); cyd_lock(cyd, 1); cyd->n_channels = channels; if (cyd->n_channels > CYD_MAX_CHANNELS) cyd->n_channels = CYD_MAX_CHANNELS; if (cyd->channel) free(cyd->channel); cyd->channel = calloc(sizeof(*cyd->channel), CYD_MAX_CHANNELS); cyd_reset(cyd); cyd_lock(cyd, 0); } void cyd_deinit(CydEngine *cyd) { if (cyd->lookup_table) { free(cyd->lookup_table); cyd->lookup_table = NULL; } #ifndef CYD_DISABLE_BUZZ if (cyd->lookup_table_ym) { free(cyd->lookup_table_ym); cyd->lookup_table_ym = NULL; } #endif if (cyd->channel) { free(cyd->channel); cyd->channel = NULL; } for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i) cydfx_deinit(&cyd->fx[i]); #ifndef USENATIVEAPIS # ifdef USESDLMUTEXES if (cyd->mutex) SDL_DestroyMutex(cyd->mutex); cyd->mutex = NULL; # endif #else # ifdef WIN32 DeleteCriticalSection(&cyd->mutex); DeleteCriticalSection(&cyd->thread_lock); # endif #endif #ifndef CYD_DISABLE_WAVETABLE if (cyd->wavetable_entries) { for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) cyd_wave_entry_deinit(&cyd->wavetable_entries[i]); free(cyd->wavetable_entries); cyd->wavetable_entries = NULL; } #endif } void cyd_reset(CydEngine *cyd) { for (int i = 0 ; i < cyd->n_channels ; ++i) { cyd_init_channel(cyd, &cyd->channel[i]); cyd->channel[i].sync_source = i; } } Uint32 cyd_cycle_adsr(const CydEngine *eng, Uint32 flags, Uint32 ym_env_shape, CydAdsr *adsr) { if (!(flags & CYD_CHN_ENABLE_YM_ENV)) { #ifndef CYD_DISABLE_ENVELOPE // SID style ADSR envelope switch (adsr->envelope_state) { case SUSTAIN: case DONE: return flags; break; case ATTACK: adsr->envelope += adsr->env_speed; if (adsr->envelope >= 0xff0000) { adsr->envelope_state = DECAY; adsr->envelope=0xff0000; adsr->env_speed = envspd(eng, adsr->d); } break; case DECAY: if (adsr->envelope > ((Uint32)adsr->s << 19) + adsr->env_speed) adsr->envelope -= adsr->env_speed; else { adsr->envelope = (Uint32)adsr->s << 19; adsr->envelope_state = (adsr->s == 0) ? RELEASE : SUSTAIN; adsr->env_speed = envspd(eng, adsr->r);; } break; case RELEASE: if (adsr->envelope > adsr->env_speed) { adsr->envelope -= adsr->env_speed; } else { adsr->envelope_state = DONE; if ((flags & (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) != (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) flags &= ~CYD_CHN_ENABLE_GATE; adsr->envelope = 0; } break; } #endif } else { #ifndef CYD_DISABLE_BUZZ // YM2149 style envelope HOLD is not processed switch (adsr->envelope_state) { case ATTACK: adsr->envelope += adsr->env_speed; if (adsr->envelope >= YM_LENGTH) { if (ym_env_shape & CYD_YM_ENV_ALT) { adsr->envelope = YM_LENGTH - (adsr->envelope - YM_LENGTH); adsr->envelope_state = DECAY; } else { adsr->envelope &= YM_LENGTH - 1; adsr->envelope_state = ATTACK; } } break; case DECAY: if (adsr->envelope >= adsr->env_speed) adsr->envelope -= adsr->env_speed; else { if (ym_env_shape & CYD_YM_ENV_ALT) { adsr->envelope = (Uint32)adsr->env_speed - adsr->envelope; adsr->envelope_state = ATTACK; } else { adsr->envelope -= adsr->env_speed; adsr->envelope &= YM_LENGTH - 1; adsr->envelope_state = DECAY; } } break; case RELEASE: adsr->envelope_state = DONE; if ((flags & (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) != (CYD_CHN_ENABLE_WAVE|CYD_CHN_WAVE_OVERRIDE_ENV)) flags &= ~CYD_CHN_ENABLE_GATE; adsr->envelope = 0; break; default: break; } #endif } return flags; } #ifndef CYD_DISABLE_LFSR static void run_lfsrs(CydChannel *chn) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { shift_lfsr(&chn->subosc[s].reg4, 4, 3); shift_lfsr(&chn->subosc[s].reg5, 5, 3); if (chn->lfsr_type & 8) shift_lfsr(&chn->subosc[s].reg9, 9, 5); else shift_lfsr(&chn->subosc[s].reg9, 17, 14); } } #endif static void cyd_cycle_channel(CydEngine *cyd, CydChannel *chn) { chn->flags = cyd_cycle_adsr(cyd, chn->flags, chn->ym_env_shape, &chn->adsr); if (chn->flags & CYD_CHN_ENABLE_WAVE) { for (int i = 0 ; i < CYD_SUB_OSCS ; ++i) { cyd_wave_cycle(&chn->subosc[i].wave, chn->wave_entry); } } #ifndef CYD_DISABLE_FM if (chn->flags & CYD_CHN_ENABLE_FM) cydfm_cycle(cyd, &chn->fm); #endif // cycle random lfsr } static void cyd_sync_channel(CydEngine *cyd, CydChannel *chn) { if ((chn->flags & CYD_CHN_ENABLE_SYNC) && cyd->channel[chn->sync_source].sync_bit) { for (int i = 0 ; i < CYD_SUB_OSCS ; ++i) { chn->subosc[i].wave.acc = 0; chn->subosc[i].wave.direction = 0; chn->subosc[i].accumulator = 0; chn->subosc[i].random = RANDOM_SEED; chn->subosc[i].reg4 = 1; chn->subosc[i].reg5 = 1; chn->subosc[i].reg9 = 1; chn->subosc[i].lfsr_ctr = 0; } } } static void cyd_advance_oscillators(CydEngine *cyd, CydChannel *chn) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { Uint32 prev_acc = chn->subosc[s].accumulator; chn->subosc[s].accumulator = (chn->subosc[s].accumulator + (Uint32)chn->subosc[s].frequency); /* only subosc #0 can set the sync bit */ if (s == 0) chn->sync_bit |= chn->subosc[s].accumulator & ACC_LENGTH; chn->subosc[s].accumulator &= ACC_LENGTH - 1; if ((prev_acc & (ACC_LENGTH/32)) != (chn->subosc[s].accumulator & (ACC_LENGTH/32))) { if (chn->flags & CYD_CHN_ENABLE_METAL) { shift_lfsr(&chn->subosc[s].random, 0xe, 8); chn->subosc[s].random &= (1 << (0xe + 1)) - 1; } else { shift_lfsr(&chn->subosc[s].random, 22, 17); chn->subosc[s].random &= (1 << (22 + 1)) - 1; } } #ifndef CYD_DISABLE_LFSR if (chn->flags & CYD_CHN_ENABLE_LFSR) { chn->subosc[s].lfsr_acc = (chn->subosc[s].lfsr & 1) ? (WAVE_AMP - 1) : 0; if (chn->subosc[s].lfsr_ctr >= chn->subosc[s].lfsr_period) { chn->subosc[s].lfsr_ctr = 0; switch (chn->lfsr_type & 3) { case 0: chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg5 & chn->subosc[s].reg9 & 1); break; case 1: case 3: chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg5 & 1); break; case 2: chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg5 & chn->subosc[s].reg4 & 1); break; case 4: chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg9 & 1); break; case 5: case 7: chn->subosc[s].lfsr ^= 1; break; case 6: chn->subosc[s].lfsr ^= !!(chn->subosc[s].reg4 & 1); break; } } ++chn->subosc[s].lfsr_ctr; run_lfsrs(chn); } #endif } } static Sint32 cyd_output_channel(CydEngine *cyd, CydChannel *chn) { Sint32 ovr = 0; chn->sync_bit = 0; #ifndef CYD_DISABLE_FM const Uint32 mod = (chn->flags & CYD_CHN_ENABLE_FM) ? cydfm_modulate(cyd, &chn->fm, 0) : 0; #endif for (int i = 0 ; i < (1 << cyd->oversample) ; ++i) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { if (chn->subosc[s].frequency != 0) { #ifdef CYD_DISABLE_FM Uint32 accumulator = chn->subosc[s].accumulator; #else Uint32 accumulator = chn->subosc[s].accumulator + mod; #endif ovr += cyd_osc(chn->flags, accumulator % ACC_LENGTH, chn->pw, chn->subosc[s].random, chn->subosc[s].lfsr_acc) - WAVE_AMP / 2; } } cyd_advance_oscillators(cyd, chn); // Need to move the oscillators per every oversample subcycle #ifndef CYD_DISABLE_FM cydfm_cycle_oversample(cyd, &chn->fm); #endif } return (ovr >> cyd->oversample); } Sint32 cyd_env_output(const CydEngine *cyd, Uint32 chn_flags, const CydAdsr *adsr, Sint32 input) { if (chn_flags & CYD_CHN_ENABLE_YM_ENV) { #ifndef CYD_DISABLE_BUZZ int idx = adsr->envelope * (Uint32)YM_LUT_SIZE / YM_LENGTH; return input * cyd->lookup_table_ym[idx % YM_LUT_SIZE] / 32768 * (Sint32)(adsr->volume) / MAX_VOLUME; #else return input * (Sint32)(adsr->volume) / MAX_VOLUME; #endif } else { #ifndef CYD_DISABLE_ENVELOPE if (adsr->envelope_state == ATTACK) return ((Sint64)input * ((Sint32)adsr->envelope / 0x10000) / 256) * (Sint32)(adsr->volume) / MAX_VOLUME; else return ((Sint64)input * (cyd->lookup_table[(adsr->envelope / (65536*256 / LUT_SIZE) ) & (LUT_SIZE - 1)]) / 65536) * (Sint32)(adsr->volume) / MAX_VOLUME; #else return input * (Sint32)(adsr->volume) / MAX_VOLUME; #endif } } #ifdef STEREOOUTPUT static void cyd_output(CydEngine *cyd, Sint32 *left, Sint32 *right) #else static Sint32 cyd_output(CydEngine *cyd) #endif { #ifdef STEREOOUTPUT *left = *right = 0; Sint32 fx_l[CYD_MAX_FX_CHANNELS] = {0}, fx_r[CYD_MAX_FX_CHANNELS] = {0}; #else Sint32 v = 0, fx_input[CYD_MAX_FX_CHANNELS] = {0}; #endif Sint32 s[CYD_MAX_CHANNELS]; for (int i = 0 ; i < cyd->n_channels ; ++i) { s[i] = (Sint32)cyd_output_channel(cyd, &cyd->channel[i]); #ifndef CYD_DISABLE_WAVETABLE if ((cyd->channel[i].flags & CYD_CHN_ENABLE_WAVE) && cyd->channel[i].wave_entry && !(cyd->channel[i].flags & CYD_CHN_WAVE_OVERRIDE_ENV)) { for (int sub = 0 ; sub < CYD_SUB_OSCS ; ++sub) { if (cyd->channel[i].subosc[sub].wave.playing && cyd->channel[i].subosc[sub].wave.frequency != 0) { #ifdef CYD_DISABLE_FM CydWaveAcc accumulator = cyd->channel[i].subosc[sub].wave.acc; #else CydWaveAcc accumulator = (cyd->channel[i].flags & CYD_CHN_ENABLE_FM) ? cydfm_modulate_wave(cyd, &cyd->channel[i].fm, cyd->channel[i].wave_entry, cyd->channel[i].subosc[sub].wave.acc) : cyd->channel[i].subosc[sub].wave.acc; #endif s[i] += cyd_wave_get_sample(&cyd->channel[i].subosc[sub].wave, cyd->channel[i].wave_entry, accumulator); } } } #endif } for (int i = 0 ; i < cyd->n_channels ; ++i) { CydChannel *chn = &cyd->channel[i]; Sint32 o = 0; if (chn->flags & CYD_CHN_ENABLE_GATE) { if (chn->flags & CYD_CHN_ENABLE_RING_MODULATION) { o = cyd_env_output(cyd, chn->flags, &chn->adsr, s[i] * (s[chn->ring_mod] + (WAVE_AMP / 2)) / WAVE_AMP); } else { o = cyd_env_output(cyd, chn->flags, &chn->adsr, s[i]); } #ifndef CYD_DISABLE_WAVETABLE if ((cyd->channel[i].flags & CYD_CHN_ENABLE_WAVE) && cyd->channel[i].wave_entry && (cyd->channel[i].flags & CYD_CHN_WAVE_OVERRIDE_ENV)) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { if (cyd->channel[i].subosc[s].wave.playing && cyd->channel[i].subosc[s].wave.frequency != 0) { #ifdef CYD_DISABLE_FM CydWaveAcc accumulator = cyd->channel[i].subosc[s].wave.acc; #else CydWaveAcc accumulator = (cyd->channel[i].flags & CYD_CHN_ENABLE_FM) ? cydfm_modulate_wave(cyd, &cyd->channel[i].fm, cyd->channel[i].wave_entry, cyd->channel[i].subosc[s].wave.acc) : cyd->channel[i].subosc[s].wave.acc; #endif o += cyd_wave_get_sample(&cyd->channel[i].subosc[s].wave, chn->wave_entry, accumulator) * (Sint32)(chn->adsr.volume) / MAX_VOLUME; } } } #endif #ifndef CYD_DISABLE_FILTER if (chn->flags & CYD_CHN_ENABLE_FILTER) { cydflt_cycle(&chn->flt, o); switch (chn->flttype) { case FLT_BP: o = cydflt_output_bp(&chn->flt); break; default: case FLT_LP: o = cydflt_output_lp(&chn->flt); break; case FLT_HP: o = cydflt_output_hp(&chn->flt); break; } } #endif #ifdef STEREOOUTPUT Sint32 ol = o * chn->gain_left / CYD_STEREO_GAIN, or = o * chn->gain_right / CYD_STEREO_GAIN; #endif if (chn->flags & CYD_CHN_ENABLE_FX) { #ifdef STEREOOUTPUT fx_l[chn->fx_bus] += ol; fx_r[chn->fx_bus] += or; #else fx_input[chn->fx_bus] += o; #endif } else { #ifdef STEREOOUTPUT *left += ol; *right += or; #else v += o; #endif } } } for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i) { #ifdef STEREOOUTPUT Sint32 l, r; cydfx_output(&cyd->fx[i], fx_l[i], fx_r[i], &l, &r); *left += l; *right += r; #else v += cydfx_output(&cyd->fx[i], fx_input[i]); #endif } #ifndef STEREOOUTPUT return v; #endif } static void cyd_cycle(CydEngine *cyd) { for (int i = 0 ; i < cyd->n_channels ; ++i) { cyd_cycle_channel(cyd, &cyd->channel[i]); } for (int i = 0 ; i < cyd->n_channels ; ++i) { cyd_sync_channel(cyd, &cyd->channel[i]); } } #ifdef NOSDL_MIXER void cyd_output_buffer(void *udata, Uint8 *_stream, int len) #else void cyd_output_buffer(int chan, void *_stream, int len, void *udata) #endif { CydEngine *cyd = udata; Sint16 * stream = (void*)_stream; cyd->samples_output = 0; for (int i = 0 ; i < len ; i += sizeof(Sint16), ++stream, ++cyd->samples_output) { #ifndef USENATIVEAPIS #ifndef USESDLMUTEXES #ifdef DEBUG Uint32 waittime = SDL_GetTicks(); #endif while (cyd->lock_request) { #ifdef DEBUG if (SDL_GetTicks() - waittime > 5000) { warning("Deadlock from cyd_output_buffer"); waittime = SDL_GetTicks(); } #endif SDL_Delay(1); } #endif #endif if (cyd->flags & CYD_PAUSED) { i += BUFFER_GRANULARITY * 2 * sizeof(Sint16); stream += BUFFER_GRANULARITY * 2; continue; } cyd_lock(cyd, 1); for (int g = 0 ; g < BUFFER_GRANULARITY && i < len ; i += sizeof(Sint16)*2, stream += 2, ++cyd->samples_output) { if (cyd->callback && cyd->callback_counter-- == 0) { cyd->callback_counter = cyd->callback_period-1; if (!cyd->callback(cyd->callback_parameter)) { cyd_lock(cyd, 0); return; } } #ifdef STEREOOUTPUT Sint32 output, left, right; cyd_output(cyd, &left, &right); output = (left + right) / 2; #else Sint32 output = cyd_output(cyd); #endif #ifdef NOSDL_MIXER Sint32 o = (output * PRE_GAIN) / PRE_GAIN_DIVISOR; #else Sint32 o = (Sint32)*(Sint16*)stream + (output * PRE_GAIN) / PRE_GAIN_DIVISOR; #endif if (o < -32768) o = -32768; else if (o > 32767) o = 32767; *(Sint16*)stream = o; cyd_cycle(cyd); } cyd_lock(cyd, 0); } } #ifdef NOSDL_MIXER void cyd_output_buffer_stereo(void *udata, Uint8 *_stream, int len) #else void cyd_output_buffer_stereo(int chan, void *_stream, int len, void *udata) #endif { CydEngine *cyd = udata; Sint16 *stream = (void*)_stream; cyd->samples_output = 0; cyd->flags &= ~CYD_CLIPPING; for (int i = 0 ; i < len ; ) { #ifndef USENATIVEAPIS #ifndef USESDLMUTEXES #ifdef DEBUG Uint32 waittime = SDL_GetTicks(); #endif while (cyd->lock_request) { #ifdef DEBUG if (SDL_GetTicks() - waittime > 5000) { warning("Deadlock from cyd_output_buffer"); waittime = SDL_GetTicks(); } #endif SDL_Delay(1); } #endif #endif if (cyd->flags & CYD_PAUSED) { i += BUFFER_GRANULARITY * 2 * sizeof(Sint16); stream += BUFFER_GRANULARITY * 2; continue; } cyd_lock(cyd, 1); for (int g = 0 ; g < BUFFER_GRANULARITY && i < len ; i += sizeof(Sint16)*2, stream += 2, ++cyd->samples_output) { if (cyd->callback && cyd->callback_counter-- == 0) { cyd->callback_counter = cyd->callback_period-1; if (!cyd->callback(cyd->callback_parameter)) { cyd_lock(cyd, 0); return; } } Sint32 left, right; #ifdef STEREOOUTPUT cyd_output(cyd, &left, &right); #else left = right = cyd_output(cyd); #endif #ifdef NOSDL_MIXER Sint32 o1 = (left * PRE_GAIN) / PRE_GAIN_DIVISOR; #else Sint32 o1 = (Sint32)*(Sint16*)stream + (left * PRE_GAIN) / PRE_GAIN_DIVISOR; #endif if (o1 < -32768) { o1 = -32768; cyd->flags |= CYD_CLIPPING; } else if (o1 > 32767) { o1 = 32767; cyd->flags |= CYD_CLIPPING; } *(Sint16*)stream = o1; #ifdef NOSDL_MIXER Sint32 o2 = (right * PRE_GAIN) / PRE_GAIN_DIVISOR; #else Sint32 o2 = (Sint32)*((Sint16*)stream + 1) + (right * PRE_GAIN) / PRE_GAIN_DIVISOR; #endif if (o2 < -32768) { o2 = -32768; cyd->flags |= CYD_CLIPPING; } else if (o2 > 32767) { o2 = 32767; cyd->flags |= CYD_CLIPPING; } *((Sint16*)stream + 1) = o2; cyd_cycle(cyd); ++cyd->samples_played; } cyd_lock(cyd, 0); } } void cyd_set_frequency(CydEngine *cyd, CydChannel *chn, int subosc, Uint16 frequency) { if (frequency != 0) { chn->subosc[subosc].frequency = (Uint64)(ACC_LENGTH >> (cyd->oversample))/16 * (Uint64)(frequency) / (Uint64)cyd->sample_rate; #ifndef CYD_DISABLE_LFSR chn->subosc[subosc].lfsr_period = (Uint64)cyd->sample_rate * 16 / frequency; #endif } else chn->subosc[subosc].frequency = 0; #ifndef CYD_DISABLE_FM if (subosc == 0) cydfm_set_frequency(cyd, &chn->fm, frequency); #endif } void cyd_set_wavetable_frequency(CydEngine *cyd, CydChannel *chn, int subosc, Uint16 frequency) { #ifndef CYD_DISABLE_WAVETABLE if (frequency != 0 && chn->wave_entry) { chn->subosc[subosc].wave.frequency = (Uint64)WAVETABLE_RESOLUTION * (Uint64)chn->wave_entry->sample_rate / (Uint64)cyd->sample_rate * (Uint64)frequency / (Uint64)get_freq(chn->wave_entry->base_note); } else { chn->subosc[subosc].wave.playing = false; chn->subosc[subosc].wave.frequency = 0; } #endif } void cyd_set_env_frequency(CydEngine *cyd, CydChannel *chn, Uint16 frequency) { #ifndef CYD_DISABLE_BUZZ chn->adsr.env_speed = (Uint64)YM_LENGTH/16 * (Uint64)frequency / (Uint64)cyd->sample_rate; #endif } void cyd_set_env_shape(CydChannel *chn, Uint8 shape) { #ifndef CYD_DISABLE_BUZZ chn->ym_env_shape = shape; if ((chn->flags & CYD_CHN_ENABLE_KEY_SYNC) || (chn->adsr.envelope_state == DONE || chn->adsr.envelope_state == SUSTAIN)) { if (shape & CYD_YM_ENV_ATT) { chn->adsr.envelope = 0; chn->adsr.envelope_state = ATTACK; } else { chn->adsr.envelope = YM_LENGTH; chn->adsr.envelope_state = DECAY; } } #endif } void cyd_enable_gate(CydEngine *cyd, CydChannel *chn, Uint8 enable) { if (enable) { if (!(chn->flags & CYD_CHN_ENABLE_YM_ENV)) { #ifndef CYD_DISABLE_ENVELOPE chn->adsr.envelope_state = ATTACK; chn->adsr.envelope = 0x0; chn->adsr.env_speed = envspd(cyd, chn->adsr.a); chn->flags = cyd_cycle_adsr(cyd, chn->flags, chn->ym_env_shape, &chn->adsr); #ifndef CYD_DISABLE_FM chn->fm.adsr.envelope_state = ATTACK; chn->fm.adsr.envelope = chn->fm.attack_start << 19; chn->fm.adsr.env_speed = envspd(cyd, chn->fm.adsr.a); cyd_cycle_adsr(cyd, 0, 0, &chn->fm.adsr); #endif #endif } if (chn->flags & CYD_CHN_ENABLE_KEY_SYNC) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { chn->subosc[s].accumulator = 0; chn->subosc[s].reg4 = chn->subosc[s].reg5 = chn->subosc[s].reg9 = 1; chn->subosc[s].lfsr_ctr = 0; } #ifndef CYD_DISABLE_FM chn->fm.accumulator = 0; chn->fm.wave.acc = 0; #endif } chn->flags |= CYD_CHN_ENABLE_GATE; } else { chn->flags &= ~CYD_CHN_WAVE_OVERRIDE_ENV; chn->adsr.envelope_state = RELEASE; chn->adsr.env_speed = envspd(cyd, chn->adsr.r); #ifndef CYD_DISABLE_FM chn->fm.adsr.envelope_state = RELEASE; chn->fm.adsr.env_speed = envspd(cyd, chn->fm.adsr.r); #endif } } void cyd_set_waveform(CydChannel *chn, Uint32 wave) { chn->flags = (chn->flags & (~WAVEFORMS)) | (wave & WAVEFORMS); } void cyd_set_callback(CydEngine *cyd, int (*callback)(void*), void*param, Uint16 period) { cyd_lock(cyd, 1); cyd->samples_played = 0; cyd->callback_parameter = param; cyd->callback = callback; cyd->callback_period = cyd->sample_rate / period; cyd->callback_counter = cyd->callback_counter % cyd->callback_period; cyd_lock(cyd, 0); } void cyd_set_callback_rate(CydEngine *cyd, Uint16 period) { cyd_lock(cyd, 1); cyd->callback_period = cyd->sample_rate / period; cyd->callback_counter = cyd->callback_counter % cyd->callback_period; cyd_lock(cyd, 0); } #ifdef USENATIVEAPIS # ifdef WIN32 static void fill_buffer(CydEngine *cyd) { //waveOutUnprepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[cyd->waveout_hdr_idx],sizeof(WAVEHDR)); #ifdef NOSDL_MIXER cyd_output_buffer_stereo(cyd, cyd->waveout_hdr[cyd->waveout_hdr_idx].lpData, cyd->waveout_hdr[cyd->waveout_hdr_idx].dwBufferLength); #else cyd_output_buffer_stereo(0, cyd->waveout_hdr[cyd->waveout_hdr_idx].lpData, cyd->waveout_hdr[cyd->waveout_hdr_idx].dwBufferLength, cyd); #endif //waveOutPrepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[cyd->waveout_hdr_idx],sizeof(WAVEHDR)); cyd->waveout_hdr[cyd->waveout_hdr_idx].dwFlags = WHDR_PREPARED; if (waveOutWrite(cyd->hWaveOut, &cyd->waveout_hdr[cyd->waveout_hdr_idx], sizeof(cyd->waveout_hdr[cyd->waveout_hdr_idx])) != MMSYSERR_NOERROR) warning("waveOutWrite returned error"); if (++cyd->waveout_hdr_idx >= CYD_NUM_WO_BUFFERS) cyd->waveout_hdr_idx = 0; } static DWORD WINAPI ThreadProc(void *param) { CydEngine *cyd = param; for(;;) { EnterCriticalSection(&cyd->thread_lock); if (!cyd->thread_running) { LeaveCriticalSection(&cyd->thread_lock); break; } while (cyd->buffers_available > 0) { LeaveCriticalSection(&cyd->thread_lock); fill_buffer(cyd); EnterCriticalSection(&cyd->thread_lock); --cyd->buffers_available; } LeaveCriticalSection(&cyd->thread_lock); Sleep(1); } debug("Thread exit"); return 0; } static DWORD WINAPI waveOutProc(void *param) { CydEngine *cyd = (void*)param; MSG msg; while (GetMessage(&msg, 0, 0, 0) == 1) { if (msg.message == MM_WOM_DONE) { EnterCriticalSection(&cyd->thread_lock); ++cyd->buffers_available; LeaveCriticalSection(&cyd->thread_lock); } if (msg.message == MM_WOM_CLOSE) { break; } } return 0; } # endif #endif #ifdef NOSDL_MIXER int cyd_register(CydEngine * cyd, int buffer_length) #else int cyd_register(CydEngine * cyd) #endif { #ifndef USENATIVEAPIS # ifndef NOSDL_MIXER int frequency, channels; Uint16 format; if (Mix_QuerySpec(&frequency, &format, &channels)) { switch (format) { case AUDIO_S16SYS: break; default: return 0; break; } switch (channels) { case 1: if (!Mix_RegisterEffect(MIX_CHANNEL_POST, cyd_output_buffer, NULL, cyd)) return 0; break; case 2: if (!Mix_RegisterEffect(MIX_CHANNEL_POST, cyd_output_buffer_stereo, NULL, cyd)) return 0; break; default: return 0; break; } return 1; } else return 0; # else SDL_AudioSpec desired, obtained; /* 22050Hz - FM Radio quality */ desired.freq=cyd->sample_rate; /* 16-bit signed audio */ desired.format=AUDIO_S16SYS; /* Stereo */ desired.channels=2; /* Large audio buffer reduces risk of dropouts but increases response time */ desired.samples=buffer_length; /* Our callback function */ desired.callback=cyd_output_buffer_stereo; desired.userdata=cyd; debug("Opening SDL audio"); /* Open the audio device */ if ( SDL_OpenAudio(&desired, &obtained) < 0 ) { warning("Could not open audio device"); return 0; } debug("Got %d Hz/format %d/%d channels", obtained.freq, obtained.format, obtained.channels); SDL_PauseAudio(0); return 1; # endif #else # ifdef WIN32 WAVEFORMATEX waveformat; waveformat.cbSize = 0; waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat.wBitsPerSample = 16; waveformat.nChannels = 2; waveformat.nSamplesPerSec = cyd->sample_rate; waveformat.nBlockAlign = waveformat.nChannels * waveformat.wBitsPerSample / 8; waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign; CreateThread(NULL, 0, waveOutProc, cyd, 0, &cyd->cb_handle); MMRESULT result = waveOutOpen(&cyd->hWaveOut, 0, &waveformat, cyd->cb_handle, (DWORD)cyd, CALLBACK_THREAD); if (result != MMSYSERR_NOERROR) { warning("waveOutOpen failed (%x)", result); return 0; } for (int i = 0 ; i < CYD_NUM_WO_BUFFERS ; ++i) { WAVEHDR * h = &cyd->waveout_hdr[i]; ZeroMemory(h, sizeof(*h)); h->dwBufferLength = CYD_NUM_WO_BUFFER_SIZE * 2 * sizeof(Sint16); h->lpData = calloc(h->dwBufferLength, 1); waveOutPrepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[i],sizeof(WAVEHDR)); } cyd->buffers_available = CYD_NUM_WO_BUFFERS; cyd->thread_running = 1; CreateThread(NULL, 0, ThreadProc, cyd, 0, &cyd->thread_handle); SetThreadPriority((HANDLE)cyd->thread_handle, THREAD_PRIORITY_HIGHEST); return 1; # else # error Platform not supported for native apis # endif return 0; #endif } int cyd_unregister(CydEngine * cyd) { debug("cyd_unregister"); #ifndef USENATIVEAPIS # ifndef NOSDL_MIXER int frequency, channels; Uint16 format; if (Mix_QuerySpec(&frequency, &format, &channels)) { switch (channels) { case 1: if (!Mix_UnregisterEffect(MIX_CHANNEL_POST, cyd_output_buffer)) return 0; break; case 2: if (!Mix_UnregisterEffect(MIX_CHANNEL_POST, cyd_output_buffer_stereo)) return 0; break; default: return 0; break; } cyd_lock(cyd, 1); cyd_lock(cyd, 0); return 1; } else return 0; # else debug("Waiting for stuff"); cyd_lock(cyd, 1); debug("Done waiting"); cyd_lock(cyd, 0); debug("Closing audio"); SDL_CloseAudio(); debug("SDL_CloseAudio finished"); return 1; # endif #else cyd_pause(cyd, 0); debug("Waiting for thread"); cyd_lock(cyd, 1); cyd->thread_running = 0; cyd_lock(cyd, 0); WaitForSingleObject((HANDLE)cyd->thread_handle, 2000); waveOutReset(cyd->hWaveOut); for (int i = 0 ; i < CYD_NUM_WO_BUFFERS ; ++i) { if (cyd->waveout_hdr[i].dwFlags & WHDR_PREPARED) waveOutUnprepareHeader(cyd->hWaveOut, &cyd->waveout_hdr[i], sizeof(cyd->waveout_hdr[i])); free(cyd->waveout_hdr[i].lpData); } waveOutClose(cyd->hWaveOut); WaitForSingleObject((HANDLE)cyd->cb_handle, 2000); return 1; #endif } void cyd_set_filter_coeffs(CydEngine * cyd, CydChannel *chn, Uint16 cutoff, Uint8 resonance) { #ifndef CYD_DISABLE_FILTER static const Uint16 resonance_table[] = {10, 512, 1300, 1950}; cydflt_set_coeff(&chn->flt, cutoff, resonance_table[resonance & 3]); #endif } void cyd_lock(CydEngine *cyd, Uint8 enable) { if (cyd->flags & CYD_SINGLE_THREAD) return; // For export, mainly #ifndef USENATIVEAPIS #ifndef USESDLMUTEXES if (enable) { #ifdef DEBUG Uint32 waittime = SDL_GetTicks(); #endif cyd->lock_request = 1; while (cyd->lock_locked ) { #ifdef DEBUG if (SDL_GetTicks() - waittime > 5000) { warning("Deadlock from cyd_lock"); waittime = SDL_GetTicks(); } #endif SDL_Delay(1); } } else { cyd->lock_request = 0; while (cyd->lock_locked) { SDL_Delay(1); } } #else if (enable) { SDL_LockMutex(cyd->mutex); } else { SDL_UnlockMutex(cyd->mutex); } #endif #else # ifdef WIN32 if (enable) { EnterCriticalSection(&cyd->mutex); } else { LeaveCriticalSection(&cyd->mutex); } # endif #endif } #ifdef STEREOOUTPUT void cyd_set_panning(CydEngine *cyd, CydChannel *chn, Uint8 panning) { if (chn->panning == panning) return; chn->panning = my_min(CYD_PAN_RIGHT, my_max(CYD_PAN_LEFT, panning)); float a = M_PI / 2 * (float)(chn->panning - CYD_PAN_LEFT) / (CYD_PAN_RIGHT - CYD_PAN_LEFT); chn->gain_left = cos(a) * CYD_STEREO_GAIN; chn->gain_right = sin(a) * CYD_STEREO_GAIN; } #endif void cyd_set_wave_entry(CydChannel *chn, const CydWavetableEntry * entry) { chn->wave_entry = entry; for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { chn->subosc[s].wave.playing = true; chn->subosc[s].wave.acc = 0; chn->subosc[s].wave.frequency = 0; chn->subosc[s].wave.direction = 0; } } void cyd_set_wavetable_offset(CydChannel *chn, Uint16 offset /* 0..0x1000 = 0-100% */) { #ifndef CYD_DISABLE_WAVETABLE if (chn->wave_entry) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { chn->subosc[s].wave.acc = (Uint64)offset * WAVETABLE_RESOLUTION * chn->wave_entry->samples / 0x1000; } } #endif } void cyd_pause(CydEngine *cyd, Uint8 enable) { #ifdef USENATIVEAPIS #ifdef WIN32 if (enable) waveOutPause(cyd->hWaveOut); else waveOutRestart(cyd->hWaveOut); #endif #else cyd_lock(cyd, 1); if (enable) cyd->flags |= CYD_PAUSED; else cyd->flags &= ~CYD_PAUSED; cyd_lock(cyd, 0); #endif } klystrack-0.20171212/klystron/src/snd/cydentry.c0000644000000000000000000000446513214501362020071 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydentry.h" #include "cyddefs.h" #include "freqs.h" #include "SDL_endian.h" #include #include void cyd_wave_entry_deinit(CydWavetableEntry *entry) { if (entry->data) free(entry->data); entry->data = NULL; } void cyd_wave_entry_init(CydWavetableEntry *entry, const void *data, Uint32 n_samples, CydWaveType sample_type, int channels, int denom, int nom) { if (data && n_samples > 0) { entry->data = realloc(entry->data, sizeof(*entry->data) * n_samples); for (int i = 0; i < n_samples ; ++i) { Sint32 v = 0; for (int c = 0; c < channels ; ++c) { switch (sample_type) { case CYD_WAVE_TYPE_SINT16: v += SDL_SwapLE16(((Sint16*)data)[i * channels + c]); break; case CYD_WAVE_TYPE_UINT8: v += ((Sint16)(((Uint8*)data)[i * channels + c]) - 0x80) << 8; break; case CYD_WAVE_TYPE_SINT8: v += (Sint16)(((Sint8*)data)[i * channels + c]) << 8; break; } } if (channels > 1) v /= channels; entry->data[i] = v * denom / nom; } entry->samples = n_samples; } else { free(entry->data); entry->data = NULL; entry->samples = 0; } } klystrack-0.20171212/klystron/src/snd/cydfm.c0000644000000000000000000000631013214501362017321 0ustar rootroot#include "cydfm.h" #include "cyddefs.h" #include "freqs.h" #include "cydosc.h" #include "macros.h" #include #include #define MODULATOR_MAX 1024 void cydfm_init(CydFm *fm) { memset(fm, 0, sizeof(*fm)); } static Uint32 get_modulator(const CydEngine *cyd, const CydFm *fm) { const static Uint32 fbtab[] = { 0, 64, 32, 16, 8, 4, 2, 1 }; if ((fm->flags & CYD_FM_ENABLE_WAVE) && fm->wave_entry) { Uint32 acc = fm->wave.acc; CydWaveAcc length = (CydWaveAcc)(fm->wave_entry->loop_end - fm->wave_entry->loop_begin) * WAVETABLE_RESOLUTION; if (length == 0) return 0; if (fm->feedback) { acc = acc + ((Uint64)(fm->fb1 + fm->fb2) / 2 * (length * 4 / fbtab[fm->feedback]) / MODULATOR_MAX); } return (Sint64)(cyd_wave_get_sample(&fm->wave, fm->wave_entry, acc % length)) * fm->env_output / 32768 + 65536; } else { Uint32 acc = fm->accumulator; if (fm->feedback) acc += ((Uint64)(fm->fb1 + fm->fb2) / 2 * (ACC_LENGTH * 4 / fbtab[fm->feedback]) / MODULATOR_MAX); return (Uint64)cyd_osc(CYD_CHN_ENABLE_TRIANGLE, acc % ACC_LENGTH, 0, 0, 0) * fm->env_output / WAVE_AMP + WAVE_AMP / 2; } } void cydfm_cycle_oversample(const CydEngine *cyd, CydFm *fm) { } void cydfm_cycle(const CydEngine *cyd, CydFm *fm) { cyd_cycle_adsr(cyd, 0, 0, &fm->adsr); fm->env_output = cyd_env_output(cyd, 0, &fm->adsr, MODULATOR_MAX); cyd_wave_cycle(&fm->wave, fm->wave_entry); fm->accumulator = (fm->accumulator + fm->period) % ACC_LENGTH; Uint32 mod = get_modulator(cyd, fm); fm->fb2 = fm->fb1; fm->fb1 = mod; fm->current_modulation = mod; } void cydfm_set_frequency(const CydEngine *cyd, CydFm *fm, Uint32 base_frequency) { const int MUL = 2; static Sint32 harmonic[16] = { 0.5 * MUL, 1.0 * MUL, 2.0 * MUL, 3 * MUL, 4 * MUL, 5 * MUL, 6 * MUL, 7 * MUL, 8 * MUL, 9 * MUL, 10 * MUL, 10 * MUL, 12 * MUL, 12 * MUL, 15 * MUL, 15 * MUL }; fm->period = ((Uint64)(ACC_LENGTH)/16 * (Uint64)base_frequency / (Uint64)cyd->sample_rate) * (Uint64)harmonic[fm->harmonic & 15] / (Uint64)harmonic[fm->harmonic >> 4]; if (fm->wave_entry) { fm->wave.playing = true; fm->wave.frequency = ((Uint64)(WAVETABLE_RESOLUTION) * (Uint64)fm->wave_entry->sample_rate / (Uint64)cyd->sample_rate * (Uint64)base_frequency / (Uint64)get_freq(fm->wave_entry->base_note)) * (Uint64)harmonic[fm->harmonic & 15] / (Uint64)harmonic[fm->harmonic >> 4]; } } Uint32 cydfm_modulate(const CydEngine *cyd, const CydFm *fm, Uint32 accumulator) { Uint32 mod = (Uint64)fm->current_modulation * ACC_LENGTH * 8 / MODULATOR_MAX; return (mod + accumulator) % ACC_LENGTH; } CydWaveAcc cydfm_modulate_wave(const CydEngine *cyd, const CydFm *fm, const CydWavetableEntry *wave, CydWaveAcc accumulator) { if (wave->loop_begin == wave->loop_end) return accumulator; CydWaveAcc length = (CydWaveAcc)(wave->loop_end - wave->loop_begin) * WAVETABLE_RESOLUTION; CydWaveAcc mod = (CydWaveAcc)fm->current_modulation * length * 8 / MODULATOR_MAX; return (mod + accumulator) % length; } void cydfm_set_wave_entry(CydFm *fm, const CydWavetableEntry * entry) { fm->wave_entry = entry; fm->wave.frequency = 0; fm->wave.direction = 0; } klystrack-0.20171212/klystron/src/snd/cydwave.h0000644000000000000000000000304613214501362017671 0ustar rootroot#ifndef CYDWAVE_H #define CYDWAVE_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" #include "cydentry.h" #include typedef struct { int direction; // 0 = forward, 1 = backwards bool playing; CydWaveAcc acc; // probably overkill Uint32 frequency; } CydWaveState; Sint32 cyd_wave_get_sample(const CydWaveState *state, const CydWavetableEntry *wave_entry, CydWaveAcc acc); void cyd_wave_cycle(CydWaveState *wave, const CydWavetableEntry *wave_entry); #endif klystrack-0.20171212/klystron/src/snd/pack.c0000644000000000000000000002321213214501362017135 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ // note: for only loading files all the compression code below is useless // note: compression code added for convenience (and klystrack) #include "pack.h" #include #include /* bitpack() bitplane codes */ enum { BITPACK_STATIC0, BITPACK_STATIC1, BITPACK_LITERAL, BITPACK_RLE }; /* bitstream writer helpers*/ typedef struct { Uint8 *buffer; Uint32 byte, size_byte; // Read/write position counters (byte component) Uint8 bit, size_bit; // Read/write position counters (bit component) } BitPtr; #define BIT_BLOCK_SIZE 1024 static void bit_init(BitPtr *p, Uint8 *buffer, Uint32 size_bytes, Uint8 size_bits) { memset(p, 0, sizeof(*p)); p->buffer = buffer; p->size_byte = size_bytes; p->size_bit = size_bits; } static void bit_seek(BitPtr *p, Uint32 byte, Uint8 bit) { p->byte = byte; p->bit = bit; } static void bit_w(BitPtr *p, int bit) { if (p->bit == 0 && !(p->byte & (BIT_BLOCK_SIZE - 1))) { p->buffer = realloc(p->buffer, p->byte + BIT_BLOCK_SIZE); } if (bit) p->buffer[p->byte] |= 1 << p->bit; else p->buffer[p->byte] &= ~(1 << p->bit); ++p->bit; if (p->bit == 8) { p->bit = 0; ++p->byte; } p->size_byte = p->byte; p->size_bit = p->bit; } static int bit_r(BitPtr *p) { if (p->size_byte <= p->byte && p->size_bit <= p->bit) return -1; int bit = (p->buffer[p->byte] & (1 << p->bit)) != 0; ++p->bit; if (p->bit == 8) { p->bit = 0; ++p->byte; } return bit; } /* By Sean Eron Anderson */ static int log2u(Uint32 v) { const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; const unsigned int S[] = {1, 2, 4, 8, 16}; int i; register unsigned int r = 0; // result of log2(v) will go here for (i = 4; i >= 0; i--) // unroll for speed... { if (v & b[i]) { v >>= S[i]; r |= S[i]; } } return r; } /* Write Elias gamma coded value (has to be nonzero) */ static void bit_wgamma(BitPtr *p, Uint32 value) { int l = log2u(value); for (int a=0; a < l; a++) bit_w(p, 0); //put 0s to indicate how many bits will follow bit_w(p, 1); //mark the end of the 0s for (int a=l-1; a >= 0; a--) //Write the bits as plain binary { bit_w(p, value & 1 << a); } } /* Read Elias gamma coded value, zero return value signals read error */ static Uint32 bit_rgamma(BitPtr *p) { int numberBits = 0; int bit; while (!(bit = bit_r(p))) numberBits++; //keep on reading until we fetch a one... if (bit < 0) return 0; Uint32 current = 0; for (int a=numberBits-1; a >= 0; a--) //Read numberBits bits { if ((bit = bit_r(p))) current |= 1 << a; if (bit < 0) return 0; } current |= 1 << numberBits; //last bit isn't encoded! return current; } /* Read bits bits */ static Sint32 bit_rbits(BitPtr *p, Uint8 bits) { Sint32 rval = 0; for (int i = 0 ; i < bits ; ++i) { int bit = bit_r(p); if (bit < 0) return -1; rval |= bit << i; } return rval; } /* Write bits bits of v */ static void bit_wbits(BitPtr *p, Uint32 v, Uint8 bits) { for (int i = 0 ; i < bits ; ++i) { bit_w(p, v & (1 << i)); } } /* Gray and delta encoding helpers */ static inline Uint16 gray(Uint16 v) { return v ^ (v >> 1); } static inline Uint16 degray(Uint16 v) { v ^= (v>>8); v ^= (v>>4); v ^= (v>>2); v ^= (v>>1); return v; } static void gray_encode(Sint16 *buffer, const int n) { for (int i = 0; i < n; ++i) buffer[i] = gray((Sint32)buffer[i] + 32768); // Gray code can not be negative } static void gray_decode(Sint16 *buffer, const int n) { for (int i = 0; i < n; ++i) buffer[i] = (Sint32)degray(buffer[i]) - 32768; // Gray code can not be negative } static void delta_encode(Sint16 *buffer, const int n) { Sint32 delta = 0; Sint32 original; for (int i = 0; i < n; ++i) { original = buffer[i]; buffer[i] = original - delta; delta = original; } } static void delta_decode(Sint16 *buffer, const int n) { Sint32 delta = 0; for (int i = 0; i < n; ++i) { buffer[i] = buffer[i] + delta; delta = buffer[i]; } } /* Compress 16-bit signed data into bitstream, return compressed data size in packed_size (in bits) */ Uint8 * bitpack(const Sint16 *_buffer, const int n, int flags, Uint32 *packed_size) { BitPtr bp; bit_init(&bp, NULL, 0, 0); Sint16 *buffer = malloc(sizeof(Sint16) * n); memcpy(buffer, _buffer, sizeof(Sint16) * n); if (flags & BITPACK_OPT_DELTA) delta_encode(buffer, n); if (flags & BITPACK_OPT_GRAY) gray_encode(buffer, n); for (int plane = 0 ; plane < sizeof(*buffer) * 8 ; ++plane) { const Sint16 mask = 1 << plane; int bit = mask & *buffer; int type = BITPACK_STATIC0 | (bit != 0); for (int i = 0 ; i < n ; ++i) if ((buffer[i] & mask) != bit) { // Was not all zeros or all ones, needs to compress type = BITPACK_RLE; break; } Uint32 p_byte = bp.byte; Uint32 p_bit = bp.bit; again: bit_wbits(&bp, type, 2); switch (type) { case BITPACK_LITERAL: for (int i = 0 ; i < n ; ++i) bit_w(&bp, buffer[i] & mask); break; case BITPACK_STATIC0: case BITPACK_STATIC1: // No data needed, bitplane is all zeros or all ones break; case BITPACK_RLE: { // Write starting bit state bit_w(&bp, bit); Uint32 ctr = 0; for (int i = 0 ; i < n ; ++i) { if (((buffer[i] & mask) == bit)) ++ctr; if ((buffer[i] & mask) != bit) { bit_wgamma(&bp, ctr); ctr = 1; // Flip the bit (no neighboring bits are the same state) bit ^= mask; } } if (ctr != 0) bit_wgamma(&bp, ctr); if ((bp.byte * 8 + bp.bit) - (p_byte * 8 + p_bit) > n + 2) { // RLE gave longer data than the original, dump data instead bit_seek(&bp, p_byte, p_bit); type = BITPACK_LITERAL; goto again; } } break; } } free(buffer); *packed_size = bp.byte * 8 + bp.bit; return bp.buffer; } /* Decompress compressed bitstream into 16-bit signed data, decompress at most packed_size bits unpacked_size tells the function the data length (important) */ Sint16 * bitunpack(const Uint8 *packed_data, const Uint32 packed_size, Uint32 unpacked_size, int flags) { BitPtr bp; bit_init(&bp, (Uint8*)packed_data, packed_size / 8, packed_size & 7); Sint16 *buffer = calloc(unpacked_size, sizeof(Sint16)); for (int plane = 0 ; plane < sizeof(*buffer) * 8 ; ++plane) { const Sint16 mask = 1 << plane; Sint32 type = bit_rbits(&bp, 2); if (type < 0) goto read_error; switch (type) { case BITPACK_LITERAL: for (int i = 0 ; i < unpacked_size ; ++i) { int bit = bit_r(&bp); if (bit < 0) goto read_error; if (bit) buffer[i] |= mask; } break; case BITPACK_STATIC0: // Data bits are zero by default, no action needed break; case BITPACK_STATIC1: // Fill bitplane with set/unset bit for (int i = 0 ; i < unpacked_size ; ++i) buffer[i] |= mask; break; case BITPACK_RLE: { // Read the starting bit status int bit = bit_r(&bp); if (bit < 0) goto read_error; if (bit) bit = mask; else bit = 0; buffer[0] |= bit; for (int i = 0 ; i < unpacked_size ; ) { Uint32 ctr = bit_rgamma(&bp); if (ctr == 0) goto read_error; for (; i < unpacked_size && ctr ; ++i, --ctr) buffer[i] |= bit; if (ctr) goto read_error; // Flip the bit (neighboring bits are always different) bit ^= mask; } } break; } } if (flags & BITPACK_OPT_GRAY) gray_decode(buffer, unpacked_size); if (flags & BITPACK_OPT_DELTA) delta_decode(buffer, unpacked_size); if (0) { read_error: free(buffer); return NULL; } return buffer; } /* Compress with best combination of options */ Uint8 * bitpack_best(const Sint16 *data, Uint32 data_size, Uint32 *_packed_size, int *flags) { Uint32 best_packed_size = 0; Uint8 *best = NULL; int best_flags = 0; for (int i = 0 ; i < 4 ; ++i) { Uint32 packed_size; Uint8 * cdata = bitpack(data, data_size, i, &packed_size); if (best == NULL || best_packed_size > packed_size) { best_packed_size = packed_size; best = cdata; best_flags = i; } else free(cdata); } *_packed_size = best_packed_size; *flags = best_flags; return best; } klystrack-0.20171212/klystron/src/snd/cydcrush.c0000644000000000000000000000577613214501362020062 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydcrush.h" #include "macros.h" #ifdef STEREOOUTPUT void cydcrush_output(CydCrush *crush, Sint32 in_l, Sint32 in_r, Sint32 *out_l, Sint32 *out_r) { if (crush->counter++ >= crush->downsample) { crush->counter = 0; if (!crush->dither) { crush->hold_l = (((in_l + 32768) & crush->bit_drop) - 32768); crush->hold_r = (((in_r + 32768) & crush->bit_drop) - 32768); } else { crush->hold_l = ((my_max(0, my_min(65535, in_l + 32768 + crush->error_l)) & crush->bit_drop) - 32768); crush->hold_r = ((my_max(0, my_min(65535, in_r + 32768 + crush->error_r)) & crush->bit_drop) - 32768); crush->error_l += in_l - crush->hold_l; crush->error_r += in_r - crush->hold_r; } } *out_l = crush->hold_l * crush->gain / 128; *out_r = crush->hold_r * crush->gain / 128; } #else Sint32 cydcrush_output(CydCrush *crush, Sint32 input) { if (crush->counter++ >= crush->downsample) { crush->counter = 0; if (!crush->dither) crush->hold = (((input + 32768) & crush->bit_drop) - 32768); else crush->hold = ((my_max(0, my_min(65535, input + 32768 + crush->error)) & crush->bit_drop) - 32768); crush->error += input - crush->hold; } return crush->hold * crush->gain / 128; } #endif void cydcrush_set(CydCrush *crush, int downsample, int bit_drop, int dither, int gain) { crush->downsample = downsample * crush->sample_rate / 44100; //crush->counter = 0; if (bit_drop >= 0) crush->bit_drop = 0xffffffff << (bit_drop); if (dither >= 0) crush->dither = dither; if (gain >= 0) crush->gain = gain; } void cydcrush_init(CydCrush *crush, int sample_rate) { crush->sample_rate = sample_rate; crush->counter = 0; #ifdef STEREOOUTPUT crush->error_l = 0; crush->error_r = 0; crush->hold_l = 0; crush->hold_r = 0; #else crush->error = 0; crush->hold = 0; #endif crush->gain = 128; } void cydcrush_deinit(CydCrush *crush) { } klystrack-0.20171212/klystron/src/snd/cydadsr.h0000644000000000000000000000024513214501362017656 0ustar rootroot#pragma once #include "SDL.h" typedef struct { Uint8 volume; Uint32 envelope, env_speed; Uint8 envelope_state; Uint8 a, d, s, r; // 0-15 } CydAdsr; klystrack-0.20171212/klystron/src/snd/cydosc.h0000644000000000000000000000020713214501362017507 0ustar rootroot#pragma once #include "cydtypes.h" Sint32 cyd_osc(Uint32 flags, Uint32 accumulator, Uint32 pw, Uint32 random, Uint32 lfsr_acc); klystrack-0.20171212/klystron/src/snd/freqs.h0000644000000000000000000000244113214501362017345 0ustar rootroot#ifndef FREQS_H #define FREQS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" #define FREQ_TAB_SIZE 96 #define MIDDLE_C (12*4) extern const Uint16 frequency_table[FREQ_TAB_SIZE]; Uint16 get_freq(int note); #endif klystrack-0.20171212/klystron/src/snd/pack.h0000644000000000000000000000302313214501362017140 0ustar rootroot#ifndef PACK_H #define PACK_H /* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" /* bitpack() option flags */ enum { BITPACK_OPT_DELTA = 1, BITPACK_OPT_GRAY = 2 }; Uint8 * bitpack(const Sint16 *_buffer, const int n, int flags, Uint32 *packed_size); Sint16 * bitunpack(const Uint8 *packed_data, const Uint32 packed_size, Uint32 unpacked_size, int flags); Uint8 * bitpack_best(const Sint16 *data, Uint32 data_size, Uint32 *_packed_size, int *flags); #endif klystrack-0.20171212/klystron/src/snd/cydosc.c0000644000000000000000000001260013214501362017502 0ustar rootroot#include "cydosc.h" #include "cyddefs.h" #include "cyd.h" static inline Uint32 cyd_pulse(Uint32 acc, Uint32 pw) { return (((acc >> ((ACC_BITS - 17))) >= (pw << 4) ? (WAVE_AMP - 1) : 0)); } static inline Uint32 cyd_saw(Uint32 acc) { return (acc >> (ACC_BITS - OUTPUT_BITS - 1)) & (WAVE_AMP - 1); } static inline Uint32 cyd_triangle(Uint32 acc) { return ((((acc & (ACC_LENGTH / 2)) ? ~acc : acc) >> (ACC_BITS - OUTPUT_BITS - 2)) & (WAVE_AMP * 2 - 1)); } static inline Uint32 cyd_noise(Uint32 acc) { return acc & (WAVE_AMP - 1); } #ifndef CYD_DISABLE_LFSR Uint32 cyd_lfsr(Uint32 bits) { return bits; } #endif Sint32 cyd_osc(Uint32 flags, Uint32 accumulator, Uint32 pw, Uint32 random, Uint32 lfsr_acc) { switch (flags & WAVEFORMS & ~CYD_CHN_ENABLE_WAVE) { case CYD_CHN_ENABLE_PULSE: return cyd_pulse(accumulator, pw); break; case CYD_CHN_ENABLE_SAW: return cyd_saw(accumulator); break; case CYD_CHN_ENABLE_TRIANGLE: return cyd_triangle(accumulator); break; case CYD_CHN_ENABLE_NOISE: return cyd_noise(random); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_PULSE: return cyd_pulse(accumulator, pw) & cyd_triangle(accumulator); break; case CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_PULSE: return cyd_saw(accumulator) & cyd_pulse(accumulator, pw); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_PULSE: return cyd_noise(random) & cyd_pulse(accumulator, pw); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_SAW: return cyd_triangle(accumulator) & cyd_saw(accumulator); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW: return cyd_noise(random) & cyd_saw(accumulator); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_TRIANGLE: return cyd_noise(random) & cyd_triangle(accumulator); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_SAW: return cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_saw(accumulator); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_NOISE: return cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_noise(random); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW: return cyd_saw(accumulator) & cyd_triangle(accumulator) & cyd_noise(random); break; case CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW: return cyd_pulse(accumulator, pw) & cyd_saw(accumulator) & cyd_noise(random); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_TRIANGLE: return cyd_saw(accumulator) & cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_noise(random); break; #ifndef CYD_DISABLE_LFSR case CYD_CHN_ENABLE_LFSR: return cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_LFSR: return cyd_pulse(accumulator, pw) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_LFSR: return cyd_saw(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_LFSR: return cyd_triangle(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_LFSR: return cyd_noise(random) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_LFSR: return cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_LFSR: return cyd_saw(accumulator) & cyd_pulse(accumulator, pw) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_LFSR: return cyd_noise(random) & cyd_pulse(accumulator, pw) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_LFSR: return cyd_triangle(accumulator) & cyd_saw(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_LFSR: return cyd_noise(random) & cyd_saw(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_LFSR: return cyd_noise(random) & cyd_triangle(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_LFSR: return cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_saw(accumulator) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_LFSR: return cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_noise(random) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_LFSR: return cyd_saw(accumulator) & cyd_triangle(accumulator) & cyd_noise(random) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_LFSR: return cyd_pulse(accumulator, pw) & cyd_saw(accumulator) & cyd_noise(random) & cyd_lfsr(lfsr_acc); break; case CYD_CHN_ENABLE_NOISE|CYD_CHN_ENABLE_SAW|CYD_CHN_ENABLE_PULSE|CYD_CHN_ENABLE_TRIANGLE|CYD_CHN_ENABLE_LFSR: return cyd_saw(accumulator) & cyd_pulse(accumulator, pw) & cyd_triangle(accumulator) & cyd_noise(random) & cyd_lfsr(lfsr_acc); break; #endif default: return WAVE_AMP / 2; break; } } klystrack-0.20171212/klystron/src/snd/cydcrush.h0000644000000000000000000000343513214501362020055 0ustar rootroot#ifndef CYDCRUSH_H #define CYDCRUSH_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydtypes.h" typedef struct { int sample_rate; #ifdef STEREOOUTPUT Sint32 hold_r, hold_l; Sint32 error_r, error_l; #else Sint32 hold; Sint32 error; #endif int counter, bit_drop, downsample, dither, gain; } CydCrush; #ifdef STEREOOUTPUT void cydcrush_output(CydCrush *crush, Sint32 in_l, Sint32 in_r, Sint32 *out_l, Sint32 *out_r); #else Sint32 cydcrush_output(CydCrush *crush, Sint32 input); #endif void cydcrush_set(CydCrush *crush, int downsample /* 1 = original, 2 = half rate etc. */, int bit_drop, int dither, int gain); void cydcrush_init(CydCrush *crush, int sample_rate); void cydcrush_deinit(CydCrush *crush); #endif klystrack-0.20171212/klystron/src/snd/freqs.c0000644000000000000000000000775413214501362017354 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "freqs.h" const Uint16 frequency_table[FREQ_TAB_SIZE] = { (Uint16)(16.35 * 16), (Uint16)(17.32 * 16), (Uint16)(18.35 * 16), (Uint16)(19.45 * 16), (Uint16)(20.60 * 16), (Uint16)(21.83 * 16), (Uint16)(23.12 * 16), (Uint16)(24.50 * 16), (Uint16)(25.96 * 16), (Uint16)(27.50 * 16), (Uint16)(29.14 * 16), (Uint16)(30.87 * 16), (Uint16)(32.70 * 16), (Uint16)(34.65 * 16), (Uint16)(36.71 * 16), (Uint16)(38.89 * 16), (Uint16)(41.20 * 16), (Uint16)(43.65 * 16), (Uint16)(46.25 * 16), (Uint16)(49.00 * 16), (Uint16)(51.91 * 16), (Uint16)(55.00 * 16), (Uint16)(58.27 * 16), (Uint16)(61.74 * 16), (Uint16)(65.41 * 16), (Uint16)(69.30 * 16), (Uint16)(73.42 * 16), (Uint16)(77.78 * 16), (Uint16)(82.41 * 16), (Uint16)(87.31 * 16), (Uint16)(92.50 * 16), (Uint16)(98.00 * 16), (Uint16)(103.83 * 16), (Uint16)(110.00 * 16), (Uint16)(116.54 * 16), (Uint16)(123.47 * 16), (Uint16)(130.81 * 16), (Uint16)(138.59 * 16), (Uint16)(146.83 * 16), (Uint16)(155.56 * 16), (Uint16)(164.81 * 16), (Uint16)(174.61 * 16), (Uint16)(185.00 * 16), (Uint16)(196.00 * 16), (Uint16)(207.65 * 16), (Uint16)(220.00 * 16), (Uint16)(233.08 * 16), (Uint16)(246.94 * 16), (Uint16)(261.63 * 16), (Uint16)(277.18 * 16), (Uint16)(293.66 * 16), (Uint16)(311.13 * 16), (Uint16)(329.63 * 16), (Uint16)(349.23 * 16), (Uint16)(369.99 * 16), (Uint16)(392.00 * 16), (Uint16)(415.30 * 16), (Uint16)(440.00 * 16), (Uint16)(466.16 * 16), (Uint16)(493.88 * 16), (Uint16)(523.25 * 16), (Uint16)(554.37 * 16), (Uint16)(587.33 * 16), (Uint16)(622.25 * 16), (Uint16)(659.26 * 16), (Uint16)(698.46 * 16), (Uint16)(739.99 * 16), (Uint16)(783.99 * 16), (Uint16)(830.61 * 16), (Uint16)(880.00 * 16), (Uint16)(932.33 * 16), (Uint16)(987.77 * 16), (Uint16)(1046.50 * 16), (Uint16)(1108.73 * 16), (Uint16)(1174.66 * 16), (Uint16)(1244.51 * 16), (Uint16)(1318.51 * 16), (Uint16)(1396.91 * 16), (Uint16)(1479.98 * 16), (Uint16)(1567.98 * 16), (Uint16)(1661.22 * 16), (Uint16)(1760.00 * 16), (Uint16)(1864.66 * 16), (Uint16)(1975.53 * 16), (Uint16)(2093.00 * 16), (Uint16)(2217.46 * 16), (Uint16)(2349.32 * 16), (Uint16)(2489.02 * 16), (Uint16)(2637.02 * 16), (Uint16)(2793.83 * 16), (Uint16)(2959.96 * 16), (Uint16)(3135.96 * 16), (Uint16)(3322.44 * 16), (Uint16)(3520.00 * 16), (Uint16)(3729.31 * 16), (Uint16)(3951.07 * 16) }; Uint16 get_freq(int note) { if (note <= 0) return frequency_table[0]; if (note >= (FREQ_TAB_SIZE << 8)) return frequency_table[FREQ_TAB_SIZE - 1]; if ((note & 0xff) == 0) { return frequency_table[(note >> 8)]; } else { Uint16 f1 = frequency_table[(note >> 8)]; Uint16 f2 = frequency_table[((note >> 8) + 1)]; return f1 + ((f2-f1) * (note & 0xff)) / 256; } } klystrack-0.20171212/klystron/src/snd/cydchr.c0000644000000000000000000001022113214501362017467 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cyddefs.h" #include "cydchr.h" #include #include #include #ifdef CYD_DISABLE_CHORUS_INTERPOLATION # define CHORUS_ACCURACY 1 #else # define CHORUS_ACCURACY 256 #endif void cydchr_output(CydChorus *chr, Sint32 in_l, Sint32 in_r, Sint32 *out_l, Sint32 *out_r) { ++chr->pos_buf; if (chr->pos_buf >= chr->buf_size) chr->pos_buf = 0; chr->buffer[chr->pos_buf] = in_r; chr->buffer[chr->pos_buf + chr->buf_size] = in_r; int acc_l = 0, acc_r = 0; for (int o = 0 ; o < CYD_CHORUS_OVERSAMPLE ; ++o) { ++chr->pos_l; if (chr->pos_l >= chr->lut_size) chr->pos_l = 0; ++chr->pos_r; if (chr->pos_r >= chr->lut_size) chr->pos_r = 0; #ifdef CYD_DISABLE_CHORUS_INTERPOLATION int a = chr->buffer[(chr->pos_buf - chr->lut[chr->pos_l] + chr->buf_size)]; if (chr->lut_size) acc_l += a; else acc_l += in_l; a = chr->buffer[(chr->pos_buf - chr->lut[chr->pos_r] + chr->buf_size)]; acc_r += a; #else int a = chr->buffer[(chr->pos_buf - chr->lut[chr->pos_l] / CHORUS_ACCURACY + chr->buf_size)]; int b = chr->buffer[(chr->pos_buf - chr->lut[chr->pos_l] / CHORUS_ACCURACY - 1 + chr->buf_size)]; int s = chr->lut[chr->pos_l] % CHORUS_ACCURACY; if (chr->lut_size) acc_l += a + (b - a) * s / CHORUS_ACCURACY; else acc_l += in_l; a = chr->buffer[(chr->pos_buf - chr->lut[chr->pos_r] / CHORUS_ACCURACY + chr->buf_size)]; b = chr->buffer[(chr->pos_buf - chr->lut[chr->pos_r] / CHORUS_ACCURACY - 1 + chr->buf_size)]; s = chr->lut[chr->pos_r] % CHORUS_ACCURACY; acc_r += a + (b - a) * s / CHORUS_ACCURACY; #endif } *out_l = acc_l / CYD_CHORUS_OVERSAMPLE; *out_r = acc_r / CYD_CHORUS_OVERSAMPLE; } void cydchr_set(CydChorus *chr, int rate, int min_delay, int max_delay, int stereo_separation) { #ifdef STEREOOUTPUT if (rate) { int old = chr->lut_size; chr->lut_size = CYD_CHORUS_OVERSAMPLE * chr->sample_rate * 4 * 10 / (10 + (rate - 1)); chr->pos_l = 0; chr->pos_r = (stereo_separation * chr->lut_size / 2 / 64) % chr->lut_size; if (old == chr->lut_size && min_delay == chr->min_delay && chr->max_delay == max_delay) return; chr->min_delay = min_delay; chr->max_delay = max_delay; for (int i = 0 ; i < chr->lut_size ; ++i) chr->lut[i] = (int)(((sin((double)i / chr->lut_size * M_PI * 2) * 0.5 + 0.5) * (max_delay - min_delay) + min_delay) * CHORUS_ACCURACY * chr->sample_rate / 10000) % (chr->buf_size * CHORUS_ACCURACY); } else { chr->pos_l = 0; chr->pos_r = 0; chr->lut_size = 0; chr->lut[0] = chr->sample_rate * min_delay / 10000; } #endif } void cydchr_init(CydChorus *chr, int sample_rate) { memset(chr, 0, sizeof(*chr)); chr->sample_rate = sample_rate; chr->buf_size = sample_rate * CYDCHR_SIZE / 1000; chr->buffer = calloc(chr->buf_size, sizeof(chr->buffer[0]) * 2); chr->lut = calloc(sample_rate * 4 * CYD_CHORUS_OVERSAMPLE, sizeof(chr->buffer[0])); chr->lut_size = 0; } void cydchr_deinit(CydChorus *chr) { free(chr->buffer); free(chr->lut); } klystrack-0.20171212/klystron/src/snd/music.c0000644000000000000000000020400713214501362017342 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #define GENERATE_VIBRATO_TABLES #include "music.h" #include #include #include #include #include "freqs.h" #include "macros.h" #include "pack.h" #ifdef GENERATE_VIBRATO_TABLES #include #endif #define VIB_TAB_SIZE 128 #ifndef GENERATE_VIBRATO_TABLES static const Sint8 rnd_table[VIB_TAB_SIZE] = { 110, -1, 88, -31, 64, -13, 29, -70, -113, 71, 99, -71, 74, 82, 52, -82, -58, 37, 20, -76, 46, -97, -69, 41, 31, -62, -5, 99, -2, -48, -89, 17, -19, 4, -27, -43, -20, 25, 112, -34, 78, 26, -56, -54, 72, -75, 22, 72, -119, 115, 56, -66, 25, 87, 93, 14, 82, 127, 79, -40, -100, 21, 17, 17, -116, -110, 61, -99, 105, 73, 116, 53, -9, 105, 91, 120, -73, 112, -10, 66, -10, -30, 99, -67, 60, 84, 110, 87, -27, -46, 114, 77, -27, -46, 75, -78, 83, -110, 92, -9, 107, -64, 31, 77, -39, 115, 126, -7, 121, -2, 66, 116, -45, 91, 1, -96, -27, 17, 76, -82, 58, -7, 75, -35, 49, 3, -52, 40 }; static const Sint8 sine_table[VIB_TAB_SIZE] = { 0, 6, 12, 18, 24, 31, 37, 43, 48, 54, 60, 65, 71, 76, 81, 85, 90, 94, 98, 102, 106, 109, 112, 115, 118, 120, 122, 124, 125, 126, 127, 127, 127, 127, 127, 126, 125, 124, 122, 120, 118, 115, 112, 109, 106, 102, 98, 94, 90, 85, 81, 76, 71, 65, 60, 54, 48, 43, 37, 31, 24, 18, 12, 6, 0, -6, -12, -18, -24, -31, -37, -43, -48, -54, -60, -65, -71, -76, -81, -85, -90, -94, -98, -102, -106, -109, -112, -115, -118, -120, -122, -124, -125, -126, -127, -127, -128, -127, -127, -126, -125, -124, -122, -120, -118, -115, -112, -109, -106, -102, -98, -94, -90, -85, -81, -76, -71, -65, -60, -54, -48, -43, -37, -31, -24, -18, -12, -6 }; #else static Sint8 rnd_table[VIB_TAB_SIZE]; static Sint8 sine_table[VIB_TAB_SIZE]; #endif static int mus_trigger_instrument_internal(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning); #ifndef USESDL_RWOPS static int RWread(struct RWops *context, void *ptr, int size, int maxnum) { return fread(ptr, size, maxnum, context->fp); } static int RWclose(struct RWops *context) { if (context->close_fp) fclose(context->fp); free(context); return 1; } #define my_RWread(ctx, ptr, size, maxnum) ctx->read(ctx, ptr, size, maxnum) #define my_RWclose(ctx) ctx->close(ctx) #define my_RWtell(ctx) 0 #else #include "SDL_rwops.h" #define my_RWread SDL_RWread #define my_RWclose SDL_RWclose #define my_RWtell SDL_RWtell #endif static RWops * RWFromFP(FILE *f, int close) { #ifdef USESDL_RWOPS SDL_RWops *rw = SDL_RWFromFP(f, close); if (!rw) { warning("SDL_RWFromFP: %s", SDL_GetError()); } return rw; #else RWops *rw = calloc(sizeof(*rw), 1); rw->fp = f; rw->close_fp = close; rw->read = RWread; rw->close = RWclose; return rw; #endif } static RWops * RWFromFile(const char *name, const char *mode) { #ifdef USESDL_RWOPS return SDL_RWFromFile(name, mode); #else FILE *f = fopen(name, mode); if (!f) return NULL; return RWFromFP(f, 1); #endif } static void update_volumes(MusEngine *mus, MusTrackStatus *ts, MusChannel *chn, CydChannel *cydchn, int volume) { if (chn->instrument && (chn->instrument->flags & MUS_INST_RELATIVE_VOLUME)) { ts->volume = volume; cydchn->adsr.volume = (chn->flags & MUS_CHN_DISABLED) ? 0 : (int)chn->instrument->volume * volume / MAX_VOLUME * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)chn->volume / MAX_VOLUME; } else { ts->volume = volume; cydchn->adsr.volume = (chn->flags & MUS_CHN_DISABLED) ? 0 : ts->volume * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)chn->volume / MAX_VOLUME; } } static void update_all_volumes(MusEngine *mus) { for (int i = 0 ; i < MUS_MAX_CHANNELS && i < mus->cyd->n_channels ; ++i) update_volumes(mus, &mus->song_track[i], &mus->channel[i], &mus->cyd->channel[i], mus->song_track[i].volume); } static void mus_set_buzz_frequency(MusEngine *mus, int chan, Uint16 note) { #ifndef CYD_DISABLE_BUZZ MusChannel *chn = &mus->channel[chan]; if (chn->instrument && chn->instrument->flags & MUS_INST_YM_BUZZ) { #ifndef CYD_DISABLE_INACCURACY Uint16 buzz_frequency = get_freq(note + chn->buzz_offset) & mus->pitch_mask; #else Uint16 buzz_frequency = get_freq(note + chn->buzz_offset); #endif cyd_set_env_frequency(mus->cyd, &mus->cyd->channel[chan], buzz_frequency); } #endif } static void mus_set_wavetable_frequency(MusEngine *mus, int chan, Uint16 note) { #ifndef CYD_DISABLE_WAVETABLE MusChannel *chn = &mus->channel[chan]; CydChannel *cydchn = &mus->cyd->channel[chan]; MusTrackStatus *track_status = &mus->song_track[chan]; if (chn->instrument && (chn->instrument->cydflags & CYD_CHN_ENABLE_WAVE) && (cydchn->wave_entry)) { for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { Uint16 final = 0; if (s == 0 || (chn->instrument->flags & MUS_INST_MULTIOSC)) { switch (s) { default: case 0: final = note; break; case 1: if (track_status->extarp1 != 0) final = note + ((Uint16)track_status->extarp1 << 8); else final = 0; break; case 2: if (track_status->extarp2 != 0) final = note + ((Uint16)track_status->extarp2 << 8); else final = 0; break; } } Uint16 wave_frequency = 0; if (final != 0) { #ifndef CYD_DISABLE_INACCURACY wave_frequency = get_freq((chn->instrument->flags & MUS_INST_WAVE_LOCK_NOTE) ? cydchn->wave_entry->base_note : (final)) & mus->pitch_mask; #else wave_frequency = get_freq((chn->instrument->flags & MUS_INST_WAVE_LOCK_NOTE) ? cydchn->wave_entry->base_note : (final)); #endif } cyd_set_wavetable_frequency(mus->cyd, cydchn, s, wave_frequency); } } #endif } static void mus_set_frequency(MusEngine *mus, int chan, Uint16 note, int divider) { MusChannel *chn = &mus->channel[chan]; MusTrackStatus *track_status = &mus->song_track[chan]; for (int s = 0 ; s < CYD_SUB_OSCS ; ++s) { Uint16 final = 0; if (s == 0 || (chn->instrument->flags & MUS_INST_MULTIOSC)) { switch (s) { default: case 0: final = note; break; case 1: if (track_status->extarp1 != 0) final = note + ((Uint16)track_status->extarp1 << 8); else final = 0; break; case 2: if (track_status->extarp2 != 0) final = note + ((Uint16)track_status->extarp2 << 8); else final = 0; break; } } Uint16 frequency = 0; if (final != 0) { #ifndef CYD_DISABLE_INACCURACY frequency = get_freq(final) & mus->pitch_mask; #else frequency = get_freq(final); #endif } cyd_set_frequency(mus->cyd, &mus->cyd->channel[chan], s, frequency / divider); } } static void mus_set_note(MusEngine *mus, int chan, Uint16 note, int update_note, int divider) { MusChannel *chn = &mus->channel[chan]; if (update_note) chn->note = note; mus_set_frequency(mus, chan, note, divider); mus_set_wavetable_frequency(mus, chan, note); mus_set_buzz_frequency(mus, chan, note); } static void mus_set_slide(MusEngine *mus, int chan, Uint16 note) { MusChannel *chn = &mus->channel[chan]; chn->target_note = note; //if (update_note) chn->note = note; } void mus_init_engine(MusEngine *mus, CydEngine *cyd) { memset(mus, 0, sizeof(*mus)); mus->cyd = cyd; mus->volume = MAX_VOLUME; mus->play_volume = MAX_VOLUME; for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) mus->channel[i].volume = MAX_VOLUME; #ifndef CYD_DISABLE_INACCURACY mus->pitch_mask = ~0; #endif #ifdef GENERATE_VIBRATO_TABLES for (int i = 0 ; i < VIB_TAB_SIZE ; ++i) { sine_table[i] = sin((float)i / VIB_TAB_SIZE * M_PI * 2) * 127; rnd_table[i] = rand(); } #endif } static void do_command(MusEngine *mus, int chan, int tick, Uint16 inst, int from_program) { MusChannel *chn = &mus->channel[chan]; CydChannel *cydchn = &mus->cyd->channel[chan]; CydEngine *cyd = mus->cyd; MusTrackStatus *track_status = &mus->song_track[chan]; switch (inst & 0x7f00) { case MUS_FX_PORTA_UP: { Uint16 prev = chn->note; chn->note += ((inst & 0xff) << 2); if (prev > chn->note) chn->note = 0xffff; mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_PORTA_DN: { Uint16 prev = chn->note; chn->note -= ((inst & 0xff) << 2); if (prev < chn->note) chn->note = 0x0; mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_PORTA_UP_LOG: { Uint16 prev = chn->note; chn->note += my_max(1, ((Uint32)frequency_table[MIDDLE_C] * (Uint32)(inst & 0xff) / (Uint32)get_freq(chn->note))); if (prev > chn->note) chn->note = 0xffff; mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_PORTA_DN_LOG: { Uint16 prev = chn->note; chn->note -= my_max(1, ((Uint32)frequency_table[MIDDLE_C] * (Uint32)(inst & 0xff) / (Uint32)get_freq(chn->note))); if (prev < chn->note) chn->note = 0x0; mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_PW_DN: { track_status->pw -= inst & 0xff; if (track_status->pw > 0xf000) track_status->pw = 0; } break; case MUS_FX_PW_UP: { track_status->pw += inst & 0xff; if (track_status->pw > 0x7ff) track_status->pw = 0x7ff; } break; #ifndef CYD_DISABLE_FILTER case MUS_FX_CUTOFF_DN: { track_status->filter_cutoff -= inst & 0xff; if (track_status->filter_cutoff > 0xf000) track_status->filter_cutoff = 0; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance); } break; case MUS_FX_CUTOFF_UP: { track_status->filter_cutoff += inst & 0xff; if (track_status->filter_cutoff > 0x7ff) track_status->filter_cutoff = 0x7ff; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance); } break; #endif #ifndef CYD_DISABLE_BUZZ case MUS_FX_BUZZ_DN: { if (chn->buzz_offset >= -32768 + (inst & 0xff)) chn->buzz_offset -= inst & 0xff; mus_set_buzz_frequency(mus, chan, chn->note); } break; case MUS_FX_BUZZ_UP: { if (chn->buzz_offset <= 32767 - (inst & 0xff)) chn->buzz_offset += inst & 0xff; mus_set_buzz_frequency(mus, chan, chn->note); } break; #endif case MUS_FX_TRIGGER_RELEASE: { if (tick == (inst & 0xff)) cyd_enable_gate(mus->cyd, cydchn, 0); } break; case MUS_FX_FADE_VOLUME: { if (!(chn->flags & MUS_CHN_DISABLED)) { track_status->volume -= inst & 0xf; if (track_status->volume > MAX_VOLUME) track_status->volume = 0; track_status->volume += (inst >> 4) & 0xf; if (track_status->volume > MAX_VOLUME) track_status->volume = MAX_VOLUME; update_volumes(mus, track_status, chn, cydchn, track_status->volume); } } break; #ifdef STEREOOUTPUT case MUS_FX_PAN_RIGHT: case MUS_FX_PAN_LEFT: { int p = cydchn->panning; if ((inst & 0xff00) == MUS_FX_PAN_LEFT) { p -= inst & 0x00ff; } else { p += inst & 0x00ff; } p = my_min(CYD_PAN_RIGHT, my_max(CYD_PAN_LEFT, p)); cyd_set_panning(mus->cyd, cydchn, p); } break; #endif case MUS_FX_EXT: { // Protracker style Exy commands switch (inst & 0xfff0) { case MUS_FX_EXT_NOTE_CUT: { if (!(chn->flags & MUS_CHN_DISABLED)) { if ((inst & 0xf) <= tick) { cydchn->adsr.volume = 0; track_status->volume = 0; } } } break; case MUS_FX_EXT_RETRIGGER: { if ((inst & 0xf) > 0 && (tick % (inst & 0xf)) == 0) { Uint8 prev_vol_tr = track_status->volume; Uint8 prev_vol_cyd = cydchn->adsr.volume; mus_trigger_instrument_internal(mus, chan, chn->instrument, chn->last_note, -1); track_status->volume = prev_vol_tr; cydchn->adsr.volume = prev_vol_cyd; } } break; } } break; } if (tick == 0) { // --- commands that run only on tick 0 switch (inst & 0xff00) { case MUS_FX_EXT: { // Protracker style Exy commands switch (inst & 0xfff0) { case MUS_FX_EXT_FADE_VOLUME_DN: { if (!(chn->flags & MUS_CHN_DISABLED)) { track_status->volume -= inst & 0xf; if (track_status->volume > MAX_VOLUME) track_status->volume = 0; update_volumes(mus, track_status, chn, cydchn, track_status->volume); } } break; case MUS_FX_EXT_FADE_VOLUME_UP: { if (!(chn->flags & MUS_CHN_DISABLED)) { track_status->volume += inst & 0xf; if (track_status->volume > MAX_VOLUME) track_status->volume = MAX_VOLUME; update_volumes(mus, track_status, chn, cydchn, track_status->volume); } } break; case MUS_FX_EXT_PORTA_UP: { Uint16 prev = chn->note; chn->note += ((inst & 0x0f)); if (prev > chn->note) chn->note = 0xffff; mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_EXT_PORTA_DN: { Uint16 prev = chn->note; chn->note -= ((inst & 0x0f)); if (prev < chn->note) chn->note = 0x0; mus_set_slide(mus, chan, chn->note); } break; } } break; default: switch (inst & 0xf000) { #ifndef CYD_DISABLE_FILTER case MUS_FX_CUTOFF_FINE_SET: { track_status->filter_cutoff = (inst & 0xfff); if (track_status->filter_cutoff > 0x7ff) track_status->filter_cutoff = 0x7ff; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance); } break; #endif #ifndef CYD_DISABLE_WAVETABLE case MUS_FX_WAVETABLE_OFFSET: { cyd_set_wavetable_offset(cydchn, inst & 0xfff); } break; #endif } switch (inst & 0x7f00) { case MUS_FX_SET_GLOBAL_VOLUME: { mus->play_volume = my_min((inst & 0xff), MAX_VOLUME); update_all_volumes(mus); } break; case MUS_FX_FADE_GLOBAL_VOLUME: { mus->play_volume -= inst & 0xf; if (mus->play_volume > MAX_VOLUME) mus->play_volume = 0; mus->play_volume += (inst & 0xf0) >> 4; if (mus->play_volume > MAX_VOLUME) mus->play_volume = MAX_VOLUME; update_all_volumes(mus); } break; case MUS_FX_SET_CHANNEL_VOLUME: { chn->volume = my_min((inst & 0xff), MAX_VOLUME); update_volumes(mus, track_status, chn, cydchn, track_status->volume); } break; case MUS_FX_PW_SET: { track_status->pw = (inst & 0xff) << 4; } break; #ifndef CYD_DISABLE_BUZZ case MUS_FX_BUZZ_SHAPE: { cyd_set_env_shape(cydchn, inst & 3); } break; case MUS_FX_BUZZ_SET_SEMI: { chn->buzz_offset = (((inst & 0xff)) - 0x80) << 8; mus_set_buzz_frequency(mus, chan, chn->note); } break; case MUS_FX_BUZZ_SET: { chn->buzz_offset = (chn->buzz_offset & 0xff00) | (inst & 0xff); mus_set_buzz_frequency(mus, chan, chn->note); } break; #endif #ifndef CYD_DISABLE_FM case MUS_FX_FM_SET_MODULATION: { cydchn->fm.adsr.volume = inst % MAX_VOLUME; } break; case MUS_FX_FM_SET_HARMONIC: { cydchn->fm.harmonic = inst % 256; } break; case MUS_FX_FM_SET_FEEDBACK: { cydchn->fm.feedback = inst % 8; } break; case MUS_FX_FM_SET_WAVEFORM: { if ((inst & 255) < CYD_WAVE_MAX_ENTRIES) { cydchn->fm.wave_entry = &mus->cyd->wavetable_entries[inst & 255]; } } break; #endif #ifdef STEREOOUTPUT case MUS_FX_SET_PANNING: { cyd_set_panning(mus->cyd, cydchn, inst & 0xff); } break; #endif #ifndef CYD_DISABLE_FILTER case MUS_FX_FILTER_TYPE: { cydchn->flttype = (inst & 0xf) % FLT_TYPES; } break; case MUS_FX_CUTOFF_SET: { track_status->filter_cutoff = (inst & 0xff) << 3; if (track_status->filter_cutoff > 0x7ff) track_status->filter_cutoff = 0x7ff; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance); } break; case MUS_FX_CUTOFF_SET_COMBINED: { if ((inst & 0xff) < 0x80) { track_status->filter_cutoff = (inst & 0xff) << 4; cydchn->flttype = FLT_LP; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance); } else { track_status->filter_cutoff = ((inst & 0xff) - 0x80) << 4; cydchn->flttype = FLT_HP; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, track_status->filter_resonance); } } break; case MUS_FX_RESONANCE_SET: { track_status->filter_resonance = inst & 3; cyd_set_filter_coeffs(mus->cyd, cydchn, track_status->filter_cutoff, inst & 3); } break; #endif case MUS_FX_SET_SPEED: { if (from_program) { chn->prog_period = inst & 0xff; } else { mus->song->song_speed = inst & 0xf; if ((inst & 0xf0) == 0) mus->song->song_speed2 = mus->song->song_speed; else mus->song->song_speed2 = (inst >> 4) & 0xf; } } break; case MUS_FX_SET_RATE: { mus->song->song_rate = inst & 0xff; if (mus->song->song_rate < 1) mus->song->song_rate = 1; cyd_set_callback_rate(mus->cyd, mus->song->song_rate); } break; case MUS_FX_PORTA_UP_SEMI: { Uint16 prev = chn->note; chn->note += (inst&0xff) << 8; if (prev > chn->note || chn->note >= (FREQ_TAB_SIZE << 8)) chn->note = ((FREQ_TAB_SIZE-1) << 8); mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_PORTA_DN_SEMI: { Uint16 prev = chn->note; chn->note -= (inst&0xff) << 8; if (prev < chn->note) chn->note = 0x0; mus_set_slide(mus, chan, chn->note); } break; case MUS_FX_ARPEGGIO_ABS: { chn->arpeggio_note = 0; chn->fixed_note = (inst & 0xff) << 8; } break; case MUS_FX_ARPEGGIO: { if (chn->fixed_note != 0xffff) { chn->note = chn->last_note; chn->fixed_note = 0xffff; } if ((inst & 0xff) == 0xf0) chn->arpeggio_note = track_status->extarp1; else if ((inst & 0xff) == 0xf1) chn->arpeggio_note = track_status->extarp2; else chn->arpeggio_note = inst & 0xff; } break; case MUS_FX_SET_VOLUME: { track_status->volume = my_min(MAX_VOLUME, inst & 0xff); update_volumes(mus, track_status, chn, cydchn, track_status->volume); } break; case MUS_FX_SET_SYNCSRC: { if ((inst & 0xff) != 0xff) { cydchn->sync_source = (inst & 0xff) % CYD_MAX_FX_CHANNELS; cydchn->flags |= CYD_CHN_ENABLE_SYNC; } else cydchn->flags &= ~CYD_CHN_ENABLE_SYNC; } break; case MUS_FX_SET_RINGSRC: { if ((inst & 0xff) != 0xff) { cydchn->ring_mod = (inst & 0xff) % CYD_MAX_FX_CHANNELS; cydchn->flags |= CYD_CHN_ENABLE_RING_MODULATION; } else cydchn->flags &= ~CYD_CHN_ENABLE_RING_MODULATION; } break; #ifndef CYD_DISABLE_FX case MUS_FX_SET_FXBUS: { cydchn->fx_bus = (inst & 0xff) % CYD_MAX_FX_CHANNELS; } break; case MUS_FX_SET_DOWNSAMPLE: { cydcrush_set(&cyd->fx[cydchn->fx_bus].crush, inst & 0xff, -1, -1, -1); } break; #endif #ifndef CYD_DISABLE_WAVETABLE case MUS_FX_SET_WAVETABLE_ITEM: { if ((inst & 255) < CYD_WAVE_MAX_ENTRIES) { cydchn->wave_entry = &mus->cyd->wavetable_entries[inst & 255]; } } break; #endif case MUS_FX_SET_WAVEFORM: { int final = 0; if (inst & MUS_FX_WAVE_NOISE) final |= CYD_CHN_ENABLE_NOISE; if (inst & MUS_FX_WAVE_PULSE) final |= CYD_CHN_ENABLE_PULSE; if (inst & MUS_FX_WAVE_TRIANGLE) final |= CYD_CHN_ENABLE_TRIANGLE; if (inst & MUS_FX_WAVE_SAW) final |= CYD_CHN_ENABLE_SAW; if (inst & MUS_FX_WAVE_WAVE) final |= CYD_CHN_ENABLE_WAVE; #ifndef CYD_DISABLE_LFSR if (inst & MUS_FX_WAVE_LFSR) final |= CYD_CHN_ENABLE_LFSR; #endif cyd_set_waveform(cydchn, final); } break; case MUS_FX_RESTART_PROGRAM: { if (!from_program) { chn->program_counter = 0; chn->program_tick = 0; chn->program_loop = 1; } } break; } break; } } } static void mus_exec_track_command(MusEngine *mus, int chan, int first_tick) { MusTrackStatus *track_status = &mus->song_track[chan]; const Uint16 inst = track_status->pattern->step[track_status->pattern_step].command; const Uint8 vol = track_status->pattern->step[track_status->pattern_step].volume; switch (vol & 0xf0) { case MUS_NOTE_VOLUME_PAN_LEFT: do_command(mus, chan, mus->song_counter, MUS_FX_PAN_LEFT | ((Uint16)(vol & 0xf)), 0); break; case MUS_NOTE_VOLUME_PAN_RIGHT: do_command(mus, chan, mus->song_counter, MUS_FX_PAN_RIGHT | ((Uint16)(vol & 0xf)), 0); break; case MUS_NOTE_VOLUME_SET_PAN: { Uint16 val = vol & 0xf; Uint16 panning = (val <= 8 ? val * CYD_PAN_CENTER / 8 : (val - 8) * (CYD_PAN_RIGHT - CYD_PAN_CENTER) / 8 + CYD_PAN_CENTER); do_command(mus, chan, mus->song_counter, MUS_FX_SET_PANNING | panning, 0); debug("Panned to %x", panning); } break; case MUS_NOTE_VOLUME_FADE_UP: do_command(mus, chan, mus->song_counter, MUS_FX_FADE_VOLUME | ((Uint16)(vol & 0xf) << 4), 0); break; case MUS_NOTE_VOLUME_FADE_DN: do_command(mus, chan, mus->song_counter, MUS_FX_FADE_VOLUME | ((Uint16)(vol & 0xf)), 0); break; default: if (vol <= MAX_VOLUME) do_command(mus, chan, first_tick ? 0 : mus->song_counter, MUS_FX_SET_VOLUME | (Uint16)(vol), 0); break; } switch (inst & 0xff00) { case MUS_FX_ARPEGGIO: if (!(inst & 0xff)) break; // no params = use the same settings case MUS_FX_SET_EXT_ARP: { track_status->extarp1 = (inst & 0xf0) >> 4; track_status->extarp2 = (inst & 0xf); } break; default: do_command(mus, chan, mus->song_counter, inst, 0); break; } } static void mus_exec_prog_tick(MusEngine *mus, int chan, int advance) { MusChannel *chn = &mus->channel[chan]; int tick = chn->program_tick; int visited[MUS_PROG_LEN] = { 0 }; do_it_again:; const Uint16 inst = chn->instrument->program[tick]; switch (inst) { case MUS_FX_END: { chn->flags &= ~MUS_CHN_PROGRAM_RUNNING; return; } break; } int dont_reloop = 0; if(inst != MUS_FX_NOP) { switch (inst & 0xff00) { case MUS_FX_JUMP: { /* This should handle infinite jumping between two jump instructions (program hang) */ if (!visited[tick]) { visited[tick] = 1; tick = inst & (MUS_PROG_LEN - 1); } else return; } break; case MUS_FX_LABEL: { } break; case MUS_FX_LOOP: { if (chn->program_loop == (inst & 0xff)) { if (advance) chn->program_loop = 1; } else { if (advance) ++chn->program_loop; int l = 0; while ((chn->instrument->program[tick] & 0xff00) != MUS_FX_LABEL && tick > 0) { --tick; if (!(chn->instrument->program[tick] & 0x8000)) ++l; } --tick; dont_reloop = l <= 1; } } break; default: do_command(mus, chan, chn->program_counter, inst, 1); break; } } if (inst == MUS_FX_NOP || (inst & 0xff00) != MUS_FX_JUMP) { ++tick; if (tick >= MUS_PROG_LEN) { tick = 0; } } // skip to next on msb if ((inst & 0x8000) && inst != MUS_FX_NOP && !dont_reloop) { goto do_it_again; } if (advance) { chn->program_tick = tick; } } static Sint8 mus_shape(Uint16 position, Uint8 shape) { switch (shape) { case MUS_SHAPE_SINE: return sine_table[position % VIB_TAB_SIZE]; break; case MUS_SHAPE_SQUARE: return ((position % VIB_TAB_SIZE) & (VIB_TAB_SIZE / 2)) ? -128 : 127; break; case MUS_SHAPE_RAMP_UP: return (position % VIB_TAB_SIZE) * 2 - 128; break; case MUS_SHAPE_RAMP_DN: return 127 - (position % VIB_TAB_SIZE) * 2; break; default: case MUS_SHAPE_RANDOM: return rnd_table[(position / 8) % VIB_TAB_SIZE]; break; } } #ifndef CYD_DISABLE_PWM static void do_pwm(MusEngine* mus, int chan) { MusChannel *chn = &mus->channel[chan]; MusInstrument *ins = chn->instrument; MusTrackStatus *track_status = &mus->song_track[chan]; track_status->pwm_position += ins->pwm_speed; mus->cyd->channel[chan].pw = track_status->pw + mus_shape(track_status->pwm_position >> 1, ins->pwm_shape) * ins->pwm_depth / 32; } #endif //***** USE THIS INSIDE MUS_ADVANCE_TICK TO AVOID MUTEX DEADLOCK int mus_trigger_instrument_internal(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning) { if (chan == -1) { for (int i = 0 ; i < mus->cyd->n_channels ; ++i) { if (!(mus->cyd->channel[i].flags & CYD_CHN_ENABLE_GATE)) chan = i; } if (chan == -1) chan = (rand() % mus->cyd->n_channels); } CydChannel *cydchn = &mus->cyd->channel[chan]; MusChannel *chn = &mus->channel[chan]; MusTrackStatus *track = &mus->song_track[chan]; chn->flags = MUS_CHN_PLAYING | (chn->flags & MUS_CHN_DISABLED); if (ins->prog_period > 0) chn->flags |= MUS_CHN_PROGRAM_RUNNING; chn->prog_period = ins->prog_period; chn->instrument = ins; if (!(ins->flags & MUS_INST_NO_PROG_RESTART)) { chn->program_counter = 0; chn->program_tick = 0; chn->program_loop = 1; } cydchn->flags = ins->cydflags; chn->arpeggio_note = 0; chn->fixed_note = 0xffff; cydchn->fx_bus = ins->fx_bus; if (ins->flags & MUS_INST_DRUM) { cyd_set_waveform(cydchn, CYD_CHN_ENABLE_NOISE); } if (ins->flags & MUS_INST_LOCK_NOTE) { note = ((Uint16)ins->base_note) << 8; } else { note += (Uint16)((int)ins->base_note-MIDDLE_C) << 8; } mus_set_note(mus, chan, ((Uint16)note) + ins->finetune, 1, ins->flags & MUS_INST_QUARTER_FREQ ? 4 : 1); chn->last_note = chn->target_note = (((Uint16)note) + ins->finetune); chn->current_tick = 0; track->vibrato_position = 0; track->vib_delay = ins->vib_delay; track->slide_speed = 0; update_volumes(mus, track, chn, cydchn, (ins->flags & MUS_INST_RELATIVE_VOLUME) ? MAX_VOLUME : ins->volume); cydchn->sync_source = ins->sync_source == 0xff? chan : ins->sync_source; cydchn->ring_mod = ins->ring_mod == 0xff? chan : ins->ring_mod; if (cydchn->ring_mod >= mus->cyd->n_channels) cydchn->ring_mod = mus->cyd->n_channels -1; if (cydchn->sync_source >= mus->cyd->n_channels) cydchn->sync_source = mus->cyd->n_channels -1; cydchn->flttype = ins->flttype; cydchn->lfsr_type = ins->lfsr_type; if (ins->cydflags & CYD_CHN_ENABLE_KEY_SYNC) { track->pwm_position = 0; } #ifndef CYD_DISABLE_FILTER if (ins->flags & MUS_INST_SET_CUTOFF) { track->filter_cutoff = ins->cutoff; track->filter_resonance = ins->resonance; cyd_set_filter_coeffs(mus->cyd, cydchn, ins->cutoff, ins->resonance); } #endif if (ins->flags & MUS_INST_SET_PW) { track->pw = ins->pw; #ifndef CYD_DISABLE_PWM do_pwm(mus,chan); #endif } if (ins->flags & MUS_INST_YM_BUZZ) { #ifndef CYD_DISABLE_BUZZ cydchn->flags |= CYD_CHN_ENABLE_YM_ENV; cyd_set_env_shape(cydchn, ins->ym_env_shape); mus->channel[chan].buzz_offset = ins->buzz_offset; #endif } else { cydchn->flags &= ~CYD_CHN_ENABLE_YM_ENV; cydchn->adsr.a = ins->adsr.a; cydchn->adsr.d = ins->adsr.d; cydchn->adsr.s = ins->adsr.s; cydchn->adsr.r = ins->adsr.r; } #ifndef CYD_DISABLE_WAVETABLE if (ins->cydflags & CYD_CHN_ENABLE_WAVE) { cyd_set_wave_entry(cydchn, &mus->cyd->wavetable_entries[ins->wavetable_entry]); } else { cyd_set_wave_entry(cydchn, NULL); } #ifndef CYD_DISABLE_FM if (ins->fm_flags & CYD_FM_ENABLE_WAVE) { cydfm_set_wave_entry(&cydchn->fm, &mus->cyd->wavetable_entries[ins->fm_wave]); } else { cydfm_set_wave_entry(&cydchn->fm, NULL); } #endif #endif #ifdef STEREOOUTPUT if (panning != -1) cyd_set_panning(mus->cyd, cydchn, panning); #endif #ifndef CYD_DISABLE_FM CydFm *fm = &cydchn->fm; fm->flags = ins->fm_flags; fm->harmonic = ins->fm_harmonic; fm->adsr.a = ins->fm_adsr.a; fm->adsr.d = ins->fm_adsr.d; fm->adsr.s = ins->fm_adsr.s; fm->adsr.r = ins->fm_adsr.r; fm->adsr.volume = ins->fm_modulation; fm->feedback = ins->fm_feedback; fm->attack_start = ins->fm_attack_start; #endif //cyd_set_frequency(mus->cyd, cydchn, chn->frequency); cyd_enable_gate(mus->cyd, cydchn, 1); return chan; } int mus_trigger_instrument(MusEngine* mus, int chan, MusInstrument *ins, Uint16 note, int panning) { cyd_lock(mus->cyd, 1); chan = mus_trigger_instrument_internal(mus, chan, ins, note, panning); cyd_lock(mus->cyd, 0); return chan; } static void mus_advance_channel(MusEngine* mus, int chan) { MusChannel *chn = &mus->channel[chan]; MusTrackStatus *track_status = &mus->song_track[chan]; if (!(mus->cyd->channel[chan].flags & CYD_CHN_ENABLE_GATE)) { chn->flags &= ~MUS_CHN_PLAYING; return; } MusInstrument *ins = chn->instrument; if (ins->flags & MUS_INST_DRUM && chn->current_tick == 1) { cyd_set_waveform(&mus->cyd->channel[chan], ins->cydflags); } if (track_status->slide_speed != 0) { if (chn->target_note > chn->note) { chn->note += my_min((Uint16)track_status->slide_speed, chn->target_note - chn->note); } else if (chn->target_note < chn->note) { chn->note -= my_min((Uint16)track_status->slide_speed , chn->note - chn->target_note); } } ++chn->current_tick; if (mus->channel[chan].flags & MUS_CHN_PROGRAM_RUNNING) { int u = (chn->program_counter + 1) >= chn->prog_period; mus_exec_prog_tick(mus, chan, u); ++chn->program_counter; if (u) chn->program_counter = 0; /*++chn->program_counter; if (chn->program_counter >= chn->instrument->prog_period) { ++chn->program_tick; if (chn->program_tick >= MUS_PROG_LEN) { chn->program_tick = 0; } chn->program_counter = 0; }*/ } #ifndef CYD_DISABLE_VIBRATO Uint8 ctrl = 0; int vibdep = my_max(0, (int)ins->vibrato_depth - (int)track_status->vib_delay); int vibspd = ins->vibrato_speed; if (track_status->pattern) { ctrl = track_status->pattern->step[track_status->pattern_step].ctrl; if ((track_status->pattern->step[track_status->pattern_step].command & 0xff00) == MUS_FX_VIBRATO) { ctrl |= MUS_CTRL_VIB; if (track_status->pattern->step[track_status->pattern_step].command & 0xff) { vibdep = (track_status->pattern->step[track_status->pattern_step].command & 0xf) << 2; vibspd = (track_status->pattern->step[track_status->pattern_step].command & 0xf0) >> 2; if (!vibspd) vibspd = ins->vibrato_speed; if (!vibdep) vibdep = ins->vibrato_depth; } } /*do_vib(mus, chan, track_status->pattern->step[track_status->pattern_step].ctrl); if ((track_status->last_ctrl & MUS_CTRL_VIB) && !(track_status->pattern->step[track_status->pattern_step].ctrl & MUS_CTRL_VIB)) { cyd_set_frequency(mus->cyd, &mus->cyd->channel[chan], mus->channel[chan].frequency); } track_status->last_ctrl = track_status->pattern->step[track_status->pattern_step].ctrl;*/ } #endif Sint16 vib = 0; #ifndef CYD_DISABLE_VIBRATO if (((ctrl & MUS_CTRL_VIB) && !(ins->flags & MUS_INST_INVERT_VIBRATO_BIT)) || (!(ctrl & MUS_CTRL_VIB) && (ins->flags & MUS_INST_INVERT_VIBRATO_BIT))) { track_status->vibrato_position += vibspd; vib = mus_shape(track_status->vibrato_position >> 1, ins->vib_shape) * vibdep / 64; if (track_status->vib_delay) --track_status->vib_delay; } #endif #ifndef CYD_DISABLE_PWM do_pwm(mus, chan); #endif Sint32 note = (mus->channel[chan].fixed_note != 0xffff ? mus->channel[chan].fixed_note : mus->channel[chan].note) + vib + ((Uint16)mus->channel[chan].arpeggio_note << 8); if (note < 0) note = 0; if (note > FREQ_TAB_SIZE << 8) note = (FREQ_TAB_SIZE - 1) << 8; mus_set_note(mus, chan, note, 0, ins->flags & MUS_INST_QUARTER_FREQ ? 4 : 1); } Uint32 mus_ext_sync(MusEngine *mus) { cyd_lock(mus->cyd, 1); Uint32 s = ++mus->ext_sync_ticks; cyd_lock(mus->cyd, 0); return s; } int mus_advance_tick(void* udata) { MusEngine *mus = udata; if (!(mus->flags & MUS_EXT_SYNC)) mus->ext_sync_ticks = 1; while (mus->ext_sync_ticks-- > 0) { if (mus->song) { for (int i = 0 ; i < mus->song->num_channels ; ++i) { MusTrackStatus *track_status = &mus->song_track[i]; CydChannel *cydchn = &mus->cyd->channel[i]; MusChannel *muschn = &mus->channel[i]; if (mus->song_counter == 0) { while (track_status->sequence_position < mus->song->num_sequences[i] && mus->song->sequence[i][track_status->sequence_position].position <= mus->song_position) { track_status->pattern = &mus->song->pattern[mus->song->sequence[i][track_status->sequence_position].pattern]; track_status->pattern_step = mus->song_position - mus->song->sequence[i][track_status->sequence_position].position; if (track_status->pattern_step >= mus->song->pattern[mus->song->sequence[i][track_status->sequence_position].pattern].num_steps) track_status->pattern = NULL; track_status->note_offset = mus->song->sequence[i][track_status->sequence_position].note_offset; ++track_status->sequence_position; } } int delay = 0; if (track_status->pattern) { if ((track_status->pattern->step[track_status->pattern_step].command & 0x7FF0) == MUS_FX_EXT_NOTE_DELAY) delay = track_status->pattern->step[track_status->pattern_step].command & 0xf; } if (mus->song_counter == delay) { if (track_status->pattern) { if (1 || track_status->pattern_step == 0) { Uint8 note = track_status->pattern->step[track_status->pattern_step].note < 0xf0 ? track_status->pattern->step[track_status->pattern_step].note + track_status->note_offset : track_status->pattern->step[track_status->pattern_step].note; Uint8 inst = track_status->pattern->step[track_status->pattern_step].instrument; MusInstrument *pinst = NULL; if (inst == MUS_NOTE_NO_INSTRUMENT) { pinst = muschn->instrument; } else { if (inst < mus->song->num_instruments) { pinst = &mus->song->instrument[inst]; muschn->instrument = pinst; } } if (note == MUS_NOTE_RELEASE) { cyd_enable_gate(mus->cyd, &mus->cyd->channel[i], 0); } else if (pinst && note != MUS_NOTE_NONE) { track_status->slide_speed = 0; int speed = pinst->slide_speed | 1; Uint8 ctrl = track_status->pattern->step[track_status->pattern_step].ctrl; if ((track_status->pattern->step[track_status->pattern_step].command & 0xff00) == MUS_FX_SLIDE) { ctrl |= MUS_CTRL_SLIDE | MUS_CTRL_LEGATO; speed = (track_status->pattern->step[track_status->pattern_step].command & 0xff); } if (ctrl & MUS_CTRL_SLIDE) { if (ctrl & MUS_CTRL_LEGATO) { mus_set_slide(mus, i, (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune); } else { Uint16 oldnote = muschn->note; mus_trigger_instrument_internal(mus, i, pinst, note << 8, -1); muschn->note = oldnote; } track_status->slide_speed = speed; } else if (ctrl & MUS_CTRL_LEGATO) { mus_set_note(mus, i, (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune, 1, pinst->flags & MUS_INST_QUARTER_FREQ ? 4 : 1); muschn->target_note = (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune; } else { Uint8 prev_vol_track = track_status->volume; Uint8 prev_vol_cyd = cydchn->adsr.volume; mus_trigger_instrument_internal(mus, i, pinst, note << 8, -1); muschn->target_note = (((Uint16)note + pinst->base_note - MIDDLE_C) << 8) + pinst->finetune; if (inst == MUS_NOTE_NO_INSTRUMENT) { track_status->volume = prev_vol_track; cydchn->adsr.volume = prev_vol_cyd; } } if (inst != MUS_NOTE_NO_INSTRUMENT) { if (pinst->flags & MUS_INST_RELATIVE_VOLUME) { track_status->volume = MAX_VOLUME; cydchn->adsr.volume = (muschn->flags & MUS_CHN_DISABLED) ? 0 : (int)pinst->volume * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)muschn->volume / MAX_VOLUME; } else { track_status->volume = pinst->volume; cydchn->adsr.volume = (muschn->flags & MUS_CHN_DISABLED) ? 0 : (int)pinst->volume * (int)mus->volume / MAX_VOLUME * (int)mus->play_volume / MAX_VOLUME * (int)muschn->volume / MAX_VOLUME; } } } } } } if (track_status->pattern) mus_exec_track_command(mus, i, mus->song_counter == delay); } ++mus->song_counter; if (mus->song_counter >= ((!(mus->song_position & 1)) ? mus->song->song_speed : mus->song->song_speed2)) { for (int i = 0 ; i < mus->cyd->n_channels ; ++i) { MusTrackStatus *track_status = &mus->song_track[i]; if (track_status->pattern) { Uint32 command = track_status->pattern->step[track_status->pattern_step].command; if ((command & 0xff00) == MUS_FX_LOOP_PATTERN) { Uint16 step = command & 0xff; track_status->pattern_step = step; } else if ((command & 0xff00) == MUS_FX_SKIP_PATTERN) { mus->song_position += my_max(track_status->pattern->num_steps - track_status->pattern_step - 1, 0); track_status->pattern = NULL; track_status->pattern_step = 0; } else { ++track_status->pattern_step; } if (track_status->pattern && track_status->pattern_step >= track_status->pattern->num_steps) { track_status->pattern = NULL; track_status->pattern_step = 0; } } } mus->song_counter = 0; ++mus->song_position; if (mus->song_position >= mus->song->song_length) { if (mus->song->flags & MUS_NO_REPEAT) return 0; mus->song_position = mus->song->loop_point; for (int i = 0 ; i < mus->cyd->n_channels ; ++i) { MusTrackStatus *track_status = &mus->song_track[i]; track_status->pattern = NULL; track_status->pattern_step = 0; track_status->sequence_position = 0; } } } } for (int i = 0 ; i < mus->cyd->n_channels ; ++i) { if (mus->channel[i].flags & MUS_CHN_PLAYING) { mus_advance_channel(mus, i); } } #ifndef CYD_DISABLE_MULTIPLEX if (mus->song && (mus->song->flags & MUS_ENABLE_MULTIPLEX) && mus->song->multiplex_period > 0) { for (int i = 0 ; i < mus->cyd->n_channels ; ++i) { CydChannel *cydchn = &mus->cyd->channel[i]; if ((mus->multiplex_ctr / mus->song->multiplex_period) == i) { update_volumes(mus, &mus->song_track[i], &mus->channel[i], cydchn, mus->song_track[i].volume); } else { cydchn->adsr.volume = 0; } } if (++mus->multiplex_ctr >= mus->song->num_channels * mus->song->multiplex_period) mus->multiplex_ctr = 0; } #endif } return 1; } void mus_set_song(MusEngine *mus, MusSong *song, Uint16 position) { cyd_lock(mus->cyd, 1); cyd_reset(mus->cyd); mus->song = song; if (song != NULL) { mus->song_counter = 0; mus->multiplex_ctr = 0; #ifndef CYD_DISABLE_INACCURACY mus->pitch_mask = (~0) << song->pitch_inaccuracy; #endif } mus->song_position = position; mus->play_volume = MAX_VOLUME; for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { mus->song_track[i].pattern = NULL; mus->song_track[i].pattern_step = 0; mus->song_track[i].sequence_position = 0; mus->song_track[i].last_ctrl = 0; mus->song_track[i].note_offset = 0; mus->song_track[i].extarp1 = mus->song_track[i].extarp2 = 0; if (song) { mus->channel[i].volume = song->default_volume[i]; #ifdef STEREOOUTPUT if (i < mus->cyd->n_channels) cyd_set_panning(mus->cyd, &mus->cyd->channel[i], song->default_panning[i] + CYD_PAN_CENTER); #endif } else { mus->channel[i].volume = MAX_VOLUME; } } cyd_lock(mus->cyd, 0); } int mus_poll_status(MusEngine *mus, int *song_position, int *pattern_position, MusPattern **pattern, MusChannel *channel, int *cyd_env, int *mus_note, Uint64 *time_played) { cyd_lock(mus->cyd, 1); if (song_position) *song_position = mus->song_position; if (pattern_position) { for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { pattern_position[i] = mus->song_track[i].pattern_step; } } if (pattern) { for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { pattern[i] = mus->song_track[i].pattern; } } if (channel) { memcpy(channel, mus->channel, sizeof(mus->channel)); } if (cyd_env) { for (int i = 0 ; i < my_min(mus->cyd->n_channels, MUS_MAX_CHANNELS) ; ++i) { if (mus->cyd->channel[i].flags & CYD_CHN_ENABLE_YM_ENV) cyd_env[i] = mus->cyd->channel[i].adsr.volume; else cyd_env[i] = cyd_env_output(mus->cyd, mus->cyd->channel[i].flags, &mus->cyd->channel[i].adsr, MAX_VOLUME); } } if (mus_note) { for (int i = 0 ; i < my_min(mus->cyd->n_channels, MUS_MAX_CHANNELS) ; ++i) { mus_note[i] = mus->channel[i].note; } } if (time_played) { *time_played = mus->cyd->samples_played * 1000 / mus->cyd->sample_rate; } cyd_lock(mus->cyd, 0); return mus->song != NULL; } int mus_load_instrument(const char *path, MusInstrument *inst, CydWavetableEntry *wavetable_entries) { RWops *ctx = RWFromFile(path, "rb"); if (ctx) { int r = mus_load_instrument_RW2(ctx, inst, wavetable_entries); my_RWclose(ctx); return r; } return 0; } static void load_wavetable_entry(Uint8 version, CydWavetableEntry * e, RWops *ctx) { VER_READ(version, 12, 0xff, &e->flags, 0); VER_READ(version, 12, 0xff, &e->sample_rate, 0); VER_READ(version, 12, 0xff, &e->samples, 0); VER_READ(version, 12, 0xff, &e->loop_begin, 0); VER_READ(version, 12, 0xff, &e->loop_end, 0); VER_READ(version, 12, 0xff, &e->base_note, 0); FIX_ENDIAN(e->flags); FIX_ENDIAN(e->sample_rate); FIX_ENDIAN(e->samples); FIX_ENDIAN(e->loop_begin); FIX_ENDIAN(e->loop_end); FIX_ENDIAN(e->base_note); if (e->samples > 0) { if (version < 15) { Sint16 *data = malloc(sizeof(data[0]) * e->samples); my_RWread(ctx, data, sizeof(data[0]), e->samples); cyd_wave_entry_init(e, data, e->samples, CYD_WAVE_TYPE_SINT16, 1, 1, 1); free(data); } else { Uint32 data_size; VER_READ(version, 15, 0xff, &data_size, 0); FIX_ENDIAN(data_size); Uint8 *compressed = malloc(sizeof(Uint8) * data_size); my_RWread(ctx, compressed, sizeof(Uint8), (data_size + 7) / 8); // data_size is in bits Sint16 *data = NULL; #ifndef CYD_DISABLE_WAVETABLE data = bitunpack(compressed, data_size, e->samples, (e->flags >> 3) & 3); #endif if (data) { cyd_wave_entry_init(e, data, e->samples, CYD_WAVE_TYPE_SINT16, 1, 1, 1); free(data); } else { warning("Sample data unpack failed"); } free(compressed); } } } static int find_and_load_wavetable(Uint8 version, RWops *ctx, CydWavetableEntry *wavetable_entries) { for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { CydWavetableEntry *e = &wavetable_entries[i]; if (e->samples == 0) { load_wavetable_entry(version, e, ctx); return i; } } return 0; } int mus_load_instrument_RW(Uint8 version, RWops *ctx, MusInstrument *inst, CydWavetableEntry *wavetable_entries) { mus_get_default_instrument(inst); debug("Loading instrument at offset %x", (Uint32)my_RWtell(ctx)); _VER_READ(&inst->flags, 0); _VER_READ(&inst->cydflags, 0); _VER_READ(&inst->adsr, 0); _VER_READ(&inst->sync_source, 0); _VER_READ(&inst->ring_mod, 0); _VER_READ(&inst->pw, 0); _VER_READ(&inst->volume, 0); Uint8 progsteps = 0; _VER_READ(&progsteps, 0); if (progsteps) _VER_READ(&inst->program, (int)progsteps*sizeof(inst->program[0])); _VER_READ(&inst->prog_period, 0); _VER_READ(&inst->vibrato_speed, 0); _VER_READ(&inst->vibrato_depth, 0); _VER_READ(&inst->pwm_speed, 0); _VER_READ(&inst->pwm_depth, 0); _VER_READ(&inst->slide_speed, 0); _VER_READ(&inst->base_note, 0); if (version >= 20) _VER_READ(&inst->finetune, 0); Uint8 len = 16; VER_READ(version, 11, 0xff, &len, 0); if (len) { memset(inst->name, 0, sizeof(inst->name)); _VER_READ(inst->name, my_min(len, sizeof(inst->name))); inst->name[sizeof(inst->name) - 1] = '\0'; } VER_READ(version, 1, 0xff, &inst->cutoff, 0); VER_READ(version, 1, 0xff, &inst->resonance, 0); VER_READ(version, 1, 0xff, &inst->flttype, 0); VER_READ(version, 7, 0xff, &inst->ym_env_shape, 0); VER_READ(version, 7, 0xff, &inst->buzz_offset, 0); VER_READ(version, 10, 0xff, &inst->fx_bus, 0); VER_READ(version, 11, 0xff, &inst->vib_shape, 0); VER_READ(version, 11, 0xff, &inst->vib_delay, 0); VER_READ(version, 11, 0xff, &inst->pwm_shape, 0); VER_READ(version, 18, 0xff, &inst->lfsr_type, 0); VER_READ(version, 12, 0xff, &inst->wavetable_entry, 0); VER_READ(version, 23, 0xff, &inst->fm_flags, 0); VER_READ(version, 23, 0xff, &inst->fm_modulation, 0); VER_READ(version, 23, 0xff, &inst->fm_feedback, 0); VER_READ(version, 23, 0xff, &inst->fm_harmonic, 0); VER_READ(version, 23, 0xff, &inst->fm_adsr, 0); VER_READ(version, 25, 0xff, &inst->fm_attack_start, 0); VER_READ(version, 23, 0xff, &inst->fm_wave, 0); #ifndef CYD_DISABLE_WAVETABLE if (wavetable_entries) { if (inst->wavetable_entry == 0xff) { inst->wavetable_entry = find_and_load_wavetable(version, ctx, wavetable_entries); } if (version >= 23) { if (inst->fm_wave == 0xff) { inst->fm_wave = find_and_load_wavetable(version, ctx, wavetable_entries); } else if (inst->fm_wave == 0xfe) { inst->fm_wave = inst->wavetable_entry; } } } #endif /* The file format is little-endian, the following only does something on big-endian machines */ FIX_ENDIAN(inst->flags); FIX_ENDIAN(inst->cydflags); FIX_ENDIAN(inst->pw); FIX_ENDIAN(inst->cutoff); FIX_ENDIAN(inst->buzz_offset); for (int i = 0 ; i < progsteps ; ++i) FIX_ENDIAN(inst->program[i]); FIX_ENDIAN(inst->fm_flags); if (version < 26) { inst->adsr.a *= ENVELOPE_SCALE; inst->adsr.d *= ENVELOPE_SCALE; inst->adsr.r *= ENVELOPE_SCALE; inst->fm_adsr.a *= ENVELOPE_SCALE; inst->fm_adsr.d *= ENVELOPE_SCALE; inst->fm_adsr.r *= ENVELOPE_SCALE; } return 1; } int mus_load_instrument_RW2(RWops *ctx, MusInstrument *inst, CydWavetableEntry *wavetable_entries) { char id[9]; id[8] = '\0'; my_RWread(ctx, id, 8, sizeof(id[0])); if (strcmp(id, MUS_INST_SIG) == 0) { Uint8 version = 0; my_RWread(ctx, &version, 1, sizeof(version)); if (version > MUS_VERSION) return 0; mus_load_instrument_RW(version, ctx, inst, wavetable_entries); return 1; } else { debug("Instrument signature does not match"); return 0; } } void mus_get_default_instrument(MusInstrument *inst) { memset(inst, 0, sizeof(*inst)); inst->flags = MUS_INST_DRUM|MUS_INST_SET_PW|MUS_INST_SET_CUTOFF; inst->pw = 0x600; inst->cydflags = CYD_CHN_ENABLE_TRIANGLE; inst->adsr.a = 1 * ENVELOPE_SCALE; inst->adsr.d = 12 * ENVELOPE_SCALE; inst->volume = MAX_VOLUME; inst->base_note = MIDDLE_C; inst->finetune = 0; inst->prog_period = 2; inst->cutoff = 2047; inst->slide_speed = 0x80; inst->vibrato_speed = 0x20; inst->vibrato_depth = 0x20; inst->vib_shape = MUS_SHAPE_SINE; inst->vib_delay = 0; for (int p = 0 ; p < MUS_PROG_LEN; ++p) inst->program[p] = MUS_FX_NOP; } void mus_set_fx(MusEngine *mus, MusSong *song) { cyd_lock(mus->cyd, 1); for(int f = 0 ; f < CYD_MAX_FX_CHANNELS ; ++f) { cydfx_set(&mus->cyd->fx[f], &song->fx[f]); } #ifndef CYD_DISABLE_INACCURACY mus->pitch_mask = (~0) << song->pitch_inaccuracy; #endif cyd_lock(mus->cyd, 0); } static void inner_load_fx(RWops *ctx, CydFxSerialized *fx, int version) { Uint8 padding; debug("fx @ %u", (Uint32)my_RWtell(ctx)); if (version >= 22) { Uint8 len = 16; my_RWread(ctx, &len, 1, 1); if (len) { memset(fx->name, 0, sizeof(fx->name)); _VER_READ(fx->name, my_min(len, sizeof(fx->name))); fx->name[sizeof(fx->name) - 1] = '\0'; } } my_RWread(ctx, &fx->flags, 1, 4); my_RWread(ctx, &fx->crush.bit_drop, 1, 1); my_RWread(ctx, &fx->chr.rate, 1, 1); my_RWread(ctx, &fx->chr.min_delay, 1, 1); my_RWread(ctx, &fx->chr.max_delay, 1, 1); my_RWread(ctx, &fx->chr.sep, 1, 1); Uint8 spread = 0; if (version < 27) my_RWread(ctx, &spread, 1, 1); if (version < 21) my_RWread(ctx, &padding, 1, 1); int taps = CYDRVB_TAPS; if (version < 27) taps = 8; for (int i = 0 ; i < taps ; ++i) { my_RWread(ctx, &fx->rvb.tap[i].delay, 2, 1); my_RWread(ctx, &fx->rvb.tap[i].gain, 2, 1); if (version >= 27) { my_RWread(ctx, &fx->rvb.tap[i].panning, 1, 1); my_RWread(ctx, &fx->rvb.tap[i].flags, 1, 1); } else { fx->rvb.tap[i].flags = 1; if (spread > 0) fx->rvb.tap[i].panning = CYD_PAN_LEFT; else fx->rvb.tap[i].panning = CYD_PAN_CENTER; } FIX_ENDIAN(fx->rvb.tap[i].gain); FIX_ENDIAN(fx->rvb.tap[i].delay); } if (version < 27) { if (spread == 0) { for (int i = 8 ; i < CYDRVB_TAPS ; ++i) { fx->rvb.tap[i].flags = 0; fx->rvb.tap[i].delay = 1000; fx->rvb.tap[i].gain = CYDRVB_LOW_LIMIT; } } else { for (int i = 8 ; i < CYDRVB_TAPS ; ++i) { fx->rvb.tap[i].flags = 1; fx->rvb.tap[i].panning = CYD_PAN_RIGHT; fx->rvb.tap[i].delay = my_min(CYDRVB_SIZE, fx->rvb.tap[i - 8].delay + (fx->rvb.tap[i - 8].delay * spread) / 2000); fx->rvb.tap[i].gain = fx->rvb.tap[i - 8].gain; } } } my_RWread(ctx, &fx->crushex.downsample, 1, 1); if (version < 19) { fx->crushex.gain = 128; } else { my_RWread(ctx, &fx->crushex.gain, 1, 1); } FIX_ENDIAN(fx->flags); } int mus_load_fx_RW(RWops *ctx, CydFxSerialized *fx) { char id[9]; id[8] = '\0'; my_RWread(ctx, id, 8, sizeof(id[0])); if (strcmp(id, MUS_FX_SIG) == 0) { Uint8 version = 0; my_RWread(ctx, &version, 1, sizeof(version)); debug("FX version = %u", version); inner_load_fx(ctx, fx, version); return 1; } else return 0; } int mus_load_fx_file(FILE *f, CydFxSerialized *fx) { RWops *rw = RWFromFP(f, 0); if (rw) { int r = mus_load_fx_RW(rw, fx); my_RWclose(rw); return r; } return 0; } int mus_load_fx(const char *path, CydFxSerialized *fx) { RWops *rw = RWFromFile(path, "rb"); if (rw) { int r = mus_load_fx_RW(rw, fx); my_RWclose(rw); return r; } return 0; } int mus_load_song_RW(RWops *ctx, MusSong *song, CydWavetableEntry *wavetable_entries) { char id[9]; id[8] = '\0'; my_RWread(ctx, id, 8, sizeof(id[0])); if (strcmp(id, MUS_SONG_SIG) == 0) { Uint8 version = 0; my_RWread(ctx, &version, 1, sizeof(version)); debug("Song version = %u", version); if (version > MUS_VERSION) { debug("Unsupported song version"); return 0; } if (version >= 6) my_RWread(ctx, &song->num_channels, 1, sizeof(song->num_channels)); else { if (version > 3) song->num_channels = 4; else song->num_channels = 3; } my_RWread(ctx, &song->time_signature, 1, sizeof(song->time_signature)); if (version >= 17) { my_RWread(ctx, &song->sequence_step, 1, sizeof(song->sequence_step)); } my_RWread(ctx, &song->num_instruments, 1, sizeof(song->num_instruments)); my_RWread(ctx, &song->num_patterns, 1, sizeof(song->num_patterns)); my_RWread(ctx, song->num_sequences, 1, sizeof(song->num_sequences[0]) * (int)song->num_channels); my_RWread(ctx, &song->song_length, 1, sizeof(song->song_length)); my_RWread(ctx, &song->loop_point, 1, sizeof(song->loop_point)); if (version >= 12) my_RWread(ctx, &song->master_volume, 1, 1); my_RWread(ctx, &song->song_speed, 1, sizeof(song->song_speed)); my_RWread(ctx, &song->song_speed2, 1, sizeof(song->song_speed2)); my_RWread(ctx, &song->song_rate, 1, sizeof(song->song_rate)); if (version > 2) my_RWread(ctx, &song->flags, 1, sizeof(song->flags)); else song->flags = 0; if (version >= 9) my_RWread(ctx, &song->multiplex_period, 1, sizeof(song->multiplex_period)); else song->multiplex_period = 3; if (version >= 16) { my_RWread(ctx, &song->pitch_inaccuracy, 1, sizeof(song->pitch_inaccuracy)); } else { song->pitch_inaccuracy = 0; } /* The file format is little-endian, the following only does something on big-endian machines */ FIX_ENDIAN(song->song_length); FIX_ENDIAN(song->loop_point); FIX_ENDIAN(song->time_signature); FIX_ENDIAN(song->sequence_step); FIX_ENDIAN(song->num_patterns); FIX_ENDIAN(song->flags); for (int i = 0 ; i < (int)song->num_channels ; ++i) FIX_ENDIAN(song->num_sequences[i]); Uint8 title_len = 16 + 1; // old length if (version >= 11) { my_RWread(ctx, &title_len, 1, 1); } if (version >= 5) { memset(song->title, 0, sizeof(song->title)); my_RWread(ctx, song->title, 1, my_min(sizeof(song->title), title_len)); song->title[sizeof(song->title) - 1] = '\0'; } Uint8 n_fx = 0; if (version >= 10) my_RWread(ctx, &n_fx, 1, sizeof(n_fx)); else if (song->flags & MUS_ENABLE_REVERB) n_fx = 1; if (n_fx > 0) { debug("Song has %u effects", n_fx); if (version >= 10) { memset(&song->fx, 0, sizeof(song->fx[0]) * n_fx); debug("Loading fx at offset %x (%d/%d)", (Uint32)my_RWtell(ctx), (int)sizeof(song->fx[0]) * n_fx, (int)sizeof(song->fx[0])); for (int fx = 0 ; fx < n_fx ; ++fx) inner_load_fx(ctx, &song->fx[fx], version); } else { for (int fx = 0 ; fx < n_fx ; ++fx) { song->fx[fx].flags = CYDFX_ENABLE_REVERB; if (song->flags & MUS_ENABLE_CRUSH) song->fx[fx].flags |= CYDFX_ENABLE_CRUSH; for (int i = 0 ; i < 8 ; ++i) { Sint32 g, d; my_RWread(ctx, &g, 1, sizeof(g)); my_RWread(ctx, &d, 1, sizeof(d)); song->fx[fx].rvb.tap[i].gain = g; song->fx[fx].rvb.tap[i].delay = d; song->fx[fx].rvb.tap[i].panning = CYD_PAN_CENTER; song->fx[fx].rvb.tap[i].flags = 1; FIX_ENDIAN(song->fx[fx].rvb.tap[i].gain); FIX_ENDIAN(song->fx[fx].rvb.tap[i].delay); } } } } for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { song->default_volume[i] = MAX_VOLUME; song->default_panning[i] = 0; } if (version >= 13) { debug("Loading default volumes at offset %x", (Uint32)my_RWtell(ctx)); my_RWread(ctx, &song->default_volume[0], sizeof(song->default_volume[0]), song->num_channels); debug("Loading default panning at offset %x", (Uint32)my_RWtell(ctx)); my_RWread(ctx, &song->default_panning[0], sizeof(song->default_panning[0]), song->num_channels); } if (song->instrument == NULL) { song->instrument = malloc((size_t)song->num_instruments * sizeof(song->instrument[0])); } for (int i = 0 ; i < song->num_instruments; ++i) { mus_load_instrument_RW(version, ctx, &song->instrument[i], NULL); } for (int i = 0 ; i < song->num_channels ; ++i) { if (song->num_sequences[i] > 0) { if (song->sequence[i] == NULL) song->sequence[i] = malloc((size_t)song->num_sequences[i] * sizeof(song->sequence[0][0])); if (version < 8) { my_RWread(ctx, song->sequence[i], song->num_sequences[i], sizeof(song->sequence[i][0])); } else { for (int s = 0 ; s < song->num_sequences[i] ; ++s) { my_RWread(ctx, &song->sequence[i][s].position, 1, sizeof(song->sequence[i][s].position)); my_RWread(ctx, &song->sequence[i][s].pattern, 1, sizeof(song->sequence[i][s].pattern)); my_RWread(ctx, &song->sequence[i][s].note_offset, 1, sizeof(song->sequence[i][s].note_offset)); } } for (int s = 0 ; s < song->num_sequences[i] ; ++s) { FIX_ENDIAN(song->sequence[i][s].position); FIX_ENDIAN(song->sequence[i][s].pattern); } } } if (song->pattern == NULL) { song->pattern = calloc((size_t)song->num_patterns, sizeof(song->pattern[0])); //memset(song->pattern, 0, (size_t)song->num_patterns * sizeof(song->pattern[0])); } for (int i = 0 ; i < song->num_patterns; ++i) { Uint16 steps; my_RWread(ctx, &steps, 1, sizeof(song->pattern[i].num_steps)); FIX_ENDIAN(steps); if (song->pattern[i].step == NULL) song->pattern[i].step = calloc((size_t)steps, sizeof(song->pattern[i].step[0])); else if (steps > song->pattern[i].num_steps) song->pattern[i].step = realloc(song->pattern[i].step, (size_t)steps * sizeof(song->pattern[i].step[0])); song->pattern[i].num_steps = steps; if (version >= 24) my_RWread(ctx, &song->pattern[i].color, 1, sizeof(song->pattern[i].color)); else song->pattern[i].color = 0; if (version < 8) { size_t s = sizeof(song->pattern[i].step[0]); if (version < 2) s = sizeof(Uint8)*3; else s = sizeof(Uint8)*3 + sizeof(Uint16) + 1; // aligment issue in version 6 songs for (int step = 0 ; step < song->pattern[i].num_steps ; ++step) { my_RWread(ctx, &song->pattern[i].step[step], 1, s); FIX_ENDIAN(song->pattern[i].step[step].command); } } else { int len = song->pattern[i].num_steps / 2 + (song->pattern[i].num_steps & 1); Uint8 *packed = malloc(sizeof(Uint8) * len); Uint8 *current = packed; my_RWread(ctx, packed, sizeof(Uint8), len); for (int s = 0 ; s < song->pattern[i].num_steps ; ++s) { Uint8 bits = (s & 1 || s == song->pattern[i].num_steps - 1) ? (*current & 0xf) : (*current >> 4); if (bits & MUS_PAK_BIT_NOTE) my_RWread(ctx, &song->pattern[i].step[s].note, 1, sizeof(song->pattern[i].step[s].note)); else song->pattern[i].step[s].note = MUS_NOTE_NONE; if (bits & MUS_PAK_BIT_INST) my_RWread(ctx, &song->pattern[i].step[s].instrument, 1, sizeof(song->pattern[i].step[s].instrument)); else song->pattern[i].step[s].instrument = MUS_NOTE_NO_INSTRUMENT; if (bits & MUS_PAK_BIT_CTRL) { my_RWread(ctx, &song->pattern[i].step[s].ctrl, 1, sizeof(song->pattern[i].step[s].ctrl)); if (version >= 14) bits |= song->pattern[i].step[s].ctrl & ~7; song->pattern[i].step[s].ctrl &= 7; } else song->pattern[i].step[s].ctrl = 0; if (bits & MUS_PAK_BIT_CMD) my_RWread(ctx, &song->pattern[i].step[s].command, 1, sizeof(song->pattern[i].step[s].command)); else song->pattern[i].step[s].command = 0; FIX_ENDIAN(song->pattern[i].step[s].command); if (bits & MUS_PAK_BIT_VOLUME) { my_RWread(ctx, &song->pattern[i].step[s].volume, 1, sizeof(song->pattern[i].step[s].volume)); } else { song->pattern[i].step[s].volume = MUS_NOTE_NO_VOLUME; } if (s & 1) ++current; } free(packed); } } for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { cyd_wave_entry_init(&wavetable_entries[i], NULL, 0, 0, 0, 0, 0); } if (version >= 12) { Uint8 max_wt = 0; my_RWread(ctx, &max_wt, 1, sizeof(Uint8)); for (int i = 0 ; i < max_wt ; ++i) { load_wavetable_entry(version, &wavetable_entries[i], ctx); } song->wavetable_names = malloc(max_wt * sizeof(char*)); if (version >= 26) { for (int i = 0 ; i < max_wt ; ++i) { Uint8 len = 0; song->wavetable_names[i] = malloc(MUS_WAVETABLE_NAME_LEN + 1); memset(song->wavetable_names[i], 0, MUS_WAVETABLE_NAME_LEN + 1); my_RWread(ctx, &len, 1, 1); my_RWread(ctx, song->wavetable_names[i], len, sizeof(char)); } } else { for (int i = 0 ; i < max_wt ; ++i) { song->wavetable_names[i] = malloc(MUS_WAVETABLE_NAME_LEN + 1); memset(song->wavetable_names[i], 0, MUS_WAVETABLE_NAME_LEN + 1); } } song->num_wavetables = max_wt; } else song->num_wavetables = 0; return 1; } return 0; } int mus_load_song(const char *path, MusSong *song, CydWavetableEntry *wavetable_entries) { RWops *ctx = RWFromFile(path, "rb"); if (ctx) { int r = mus_load_song_RW(ctx, song, wavetable_entries); my_RWclose(ctx); return r; } return 0; } void mus_free_song(MusSong *song) { free(song->instrument); for (int i = 0 ; i < MUS_MAX_CHANNELS; ++i) { free(song->sequence[i]); } for (int i = 0 ; i < song->num_patterns; ++i) { free(song->pattern[i].step); } for (int i = 0 ; i < song->num_wavetables; ++i) { free(song->wavetable_names[i]); } free(song->wavetable_names); free(song->pattern); } void mus_release(MusEngine *mus, int chan) { cyd_lock(mus->cyd, 1); cyd_enable_gate(mus->cyd, &mus->cyd->channel[chan], 0); cyd_lock(mus->cyd, 0); } int mus_load_instrument_file(Uint8 version, FILE *f, MusInstrument *inst, CydWavetableEntry *wavetable_entries) { RWops *rw = RWFromFP(f, 0); if (rw) { int r = mus_load_instrument_RW(version, rw, inst, wavetable_entries); my_RWclose(rw); return r; } return 0; } int mus_load_instrument_file2(FILE *f, MusInstrument *inst, CydWavetableEntry *wavetable_entries) { RWops *rw = RWFromFP(f, 0); if (rw) { int r = mus_load_instrument_RW2(rw, inst, wavetable_entries); my_RWclose(rw); return r; } return 0; } int mus_load_song_file(FILE *f, MusSong *song, CydWavetableEntry *wavetable_entries) { RWops *rw = RWFromFP(f, 0); if (rw) { int r = mus_load_song_RW(rw, song, wavetable_entries); my_RWclose(rw); return r; } return 0; } Uint32 mus_get_playtime_at(MusSong *song, int position) { Uint32 ticks = 0; int pos = 0; int seq_pos[MUS_MAX_CHANNELS] = {0}, pattern_pos[MUS_MAX_CHANNELS] = {0}; MusPattern *pattern[MUS_MAX_CHANNELS] = {0}; int spd1 = song->song_speed, spd2 = song->song_speed2, rate = song->song_rate; while (pos < position) { for (int t = 0 ; t < song->num_channels ; ++t) { if (seq_pos[t] < song->num_sequences[t]) { if (song->sequence[t][seq_pos[t]].position == pos) { if (seq_pos[t] < song->num_sequences[t]) { pattern_pos[t] = 0; pattern[t] = &song->pattern[song->sequence[t][seq_pos[t]].pattern]; seq_pos[t]++; } } if (pattern[t] && pattern_pos[t] < pattern[t]->num_steps) { Uint16 command = pattern[t]->step[pattern_pos[t]].command; if ((command & 0xff00) == MUS_FX_SET_SPEED) { spd1 = command & 0xf; spd2 = (command & 0xf0) >> 4; if (!spd2) spd2 = spd1; } else if ((command & 0xff00) == MUS_FX_SET_RATE) { rate = command & 0xff; if (rate < 1) rate = 1; } else if ((command & 0xff00) == MUS_FX_SKIP_PATTERN) { pos += pattern[t]->num_steps - 1 - pattern_pos[t]; } } } pattern_pos[t]++; } int spd = pos & 1 ? spd2 : spd1; ticks += (1000 * spd) / rate; ++pos; } return ticks; } void mus_set_channel_volume(MusEngine* mus, int chan, int volume) { MusChannel *chn = &mus->channel[chan]; CydChannel *cydchn = &mus->cyd->channel[chan]; MusTrackStatus *track_status = &mus->song_track[chan]; chn->volume = my_min(volume, MAX_VOLUME); update_volumes(mus, track_status, chn, cydchn, track_status->volume); } klystrack-0.20171212/klystron/src/snd/cydfx.h0000644000000000000000000000442213214501362017343 0ustar rootroot#ifndef CYDFX_H #define CYDFX_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "cydrvb.h" #include "cydchr.h" #include "cydcrush.h" #define CYD_FX_NAME_LEN 32 typedef struct { Uint32 flags; CydCrush crush; CydReverb rvb; CydChorus chr; } CydFx; /* The following is a non-aligned packed struct for saving in files */ typedef struct { char name[CYD_FX_NAME_LEN + 1]; Uint32 flags; // 4 struct { Uint8 bit_drop; // 1 } crush; struct { Uint8 rate, min_delay, max_delay, sep; // 4 } chr; struct { struct { Uint16 delay; Sint16 gain; Uint8 panning; Uint8 flags; } tap[CYDRVB_TAPS]; } rvb; struct // so we won't fuck up old versions of this struct when freading { Uint8 downsample, gain; // 2 } crushex; } __attribute__((__packed__)) CydFxSerialized; #ifdef STEREOOUTPUT void cydfx_output(CydFx *fx, Sint32 fx_l, Sint32 fx_r, Sint32 *left, Sint32 *right); #else Sint32 cydfx_output(CydFx *fx, Sint32 fx_input); #endif void cydfx_init(CydFx *fx, int rate); void cydfx_deinit(CydFx *fx); void cydfx_set(CydFx *fx, const CydFxSerialized *ser); enum { CYDFX_ENABLE_REVERB = 1, CYDFX_ENABLE_CRUSH = 2, CYDFX_ENABLE_CHORUS = 4, CYDFX_ENABLE_CRUSH_DITHER = 8, }; #endif klystrack-0.20171212/klystron/src/util/0000755000000000000000000000000013214501362016244 5ustar rootrootklystrack-0.20171212/klystron/src/util/rnd.c0000644000000000000000000001103713214501362017175 0ustar rootroot#include "rnd.h" /* ----------------------------------------------------------------------- */ /* This is the Mersenne Twister by Makoto Matsumoto and Takuji Nishimura */ /* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html */ /* ----------------------------------------------------------------------- */ /* A few very minor changes were made by me - Adam */ /* A C-program for MT19937, with initialization improved 2002/1/26. Coded by Takuji Nishimura and Makoto Matsumoto. Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length). Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any feedback is very welcome. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ /* Period parameters */ #define N 624 #define M 397 #define MATRIX_A 0x9908b0dfUL /* constant vector a */ #define UPPER_MASK 0x80000000UL /* most significant w-r bits */ #define LOWER_MASK 0x7fffffffUL /* least significant r bits */ static unsigned long mt[N]; /* the array for the state vector */ static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ /* initializes mt[N] with a seed */ void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti> 30)) + mti); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ mt[mti] &= 0xffffffffUL; /* for >32 bit machines */ } } /* generates a random number on [0,0xffffffff]-interval */ unsigned int rndu() { unsigned int y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; /* mag01[x] = x * MATRIX_A for x=0,1 */ if (mti >= N) { /* generate N words at one time */ int kk; for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; } for (;kk> 1) ^ mag01[y & 0x1UL]; } y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; /* Tempering */ y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } int rnd(int min_val,int max_val) { if (min_val==max_val) return min_val; return (unsigned int)rndu()%(unsigned int)(max_val-min_val+1)+(unsigned int)min_val; } float rndf() { return (float)rndu()/(float)0xffffffff; } long double rndl() { return (long double)rndu()/(long double)0xffffffff; } klystrack-0.20171212/klystron/src/util/bundle.c0000644000000000000000000001107213214501362017662 0ustar rootroot#include "bundle.h" #include #include "macros.h" #include #include typedef struct { SDL_RWops *handle; BundleFile *file; Uint32 pos; } RWOpsBundle; int bnd_open(Bundle *bundle, const char * filename) { SDL_RWops *rw = SDL_RWFromFile(filename, "rb"); if (rw) { if (!bnd_open_RW(bundle, rw)) { SDL_RWclose(rw); return 0; } bundle->close_handle = true; //SDL_FreeRW(rw); return 1; } else { warning("Can't open bundle '%s'", filename); return 0; } } int bnd_open_RW(Bundle *bundle, SDL_RWops *ctx) { memset(bundle, 0, sizeof(*bundle)); char sig[5] = { 0 }; SDL_RWread(ctx, sig, strlen(BND_SIG), sizeof(char)); if (strncmp(sig, BND_SIG, strlen(BND_SIG)) != 0) { warning("Bundle sig does not match '"BND_SIG"'"); return 0; } SDL_RWread(ctx, &bundle->flags, 1, sizeof(bundle->flags)); FIX_ENDIAN(bundle->flags); if (bundle->flags != 0) warning("Unsupported bundle mode"); SDL_RWread(ctx, &bundle->n_files, 1, sizeof(bundle->n_files)); FIX_ENDIAN(bundle->n_files); bundle->file = calloc(sizeof(bundle->file[0]), bundle->n_files); Uint32 origin = 0; for (int i = 0 ; i < bundle->n_files ; ++i) { char name[BND_MAX_NAME_SIZE]; memset(name, 0, sizeof(name)); char c; int l = 0; do { SDL_RWread(ctx, &c, 1, 1); if (l < BND_MAX_NAME_SIZE-1) { name[l] = c; ++l; } else warning("Bundle name too long"); } while (c); bundle->file[i].name = strdup(name); SDL_RWread(ctx, &bundle->file[i].size, 1, sizeof(bundle->file[i].size)); FIX_ENDIAN(bundle->file[i].size); bundle->file[i].offset = origin; origin += bundle->file[i].size; } Uint32 header_size = SDL_RWtell(ctx); for (int i = 0 ; i < bundle->n_files ; ++i) { bundle->file[i].offset += header_size; } bundle->handle = ctx; debug("Opened bundle (%d files)", bundle->n_files); return 1; } void bnd_free(Bundle *bundle) { for (int i = 0 ; i < bundle->n_files ; ++i) { free(bundle->file[i].name); } if (bundle->close_handle) { SDL_RWclose(bundle->handle); } free(bundle->file); memset(bundle, 0, sizeof(*bundle)); } static Sint64 bnd_seek(struct SDL_RWops *context, Sint64 offset, int whence) { RWOpsBundle *b = context->hidden.unknown.data1; switch (whence) { case SEEK_SET: SDL_RWseek(b->handle, b->file->offset + offset, SEEK_SET); break; case SEEK_CUR: SDL_RWseek(b->handle, offset, SEEK_CUR); break; case SEEK_END: SDL_RWseek(b->handle, b->file->offset + b->file->size - offset, SEEK_SET); break; } if (SDL_RWtell(b->handle) < b->file->offset) SDL_RWseek(b->handle, b->file->offset, SEEK_SET); if (SDL_RWtell(b->handle) > b->file->offset + b->file->size) SDL_RWseek(b->handle, b->file->offset + b->file->size, SEEK_SET); return b->pos = (SDL_RWtell(b->handle) - b->file->offset); } #if SDL_VERSION_ATLEAST(1,3,0) static size_t bnd_read(struct SDL_RWops *context, void *ptr, size_t size, size_t num) #else static int bnd_read(struct SDL_RWops *context, void *ptr, int size, int num) #endif { RWOpsBundle *b = context->hidden.unknown.data1; SDL_RWseek(b->handle, b->file->offset + b->pos, SEEK_SET); if (size * num > b->file->size - (SDL_RWtell(b->handle) - b->file->offset)) num = (b->file->size - (SDL_RWtell(b->handle) - b->file->offset)) / size; b->pos += size * num; return SDL_RWread(b->handle, ptr, size, num); } static int bnd_close(struct SDL_RWops *context) { RWOpsBundle *b = context->hidden.unknown.data1; free(b); SDL_FreeRW(context); return 0; } SDL_RWops *SDL_RWFromBundle(Bundle *bundle, const char *filename) { SDL_RWops *rwops; RWOpsBundle * b = calloc(1, sizeof(RWOpsBundle)); b->handle = bundle->handle; for (int i = 0 ; i < bundle->n_files ; ++i) { if (strcmp(bundle->file[i].name, filename) == 0) { b->file = &bundle->file[i]; break; } } if (!b->file) { free(b); return NULL; } rwops = SDL_AllocRW(); if (rwops != NULL) { rwops->seek = bnd_seek; rwops->read = bnd_read; rwops->write = NULL; rwops->close = bnd_close; rwops->hidden.unknown.data1 = b; rwops->seek(rwops, 0, SEEK_SET); } else { free(b); } return rwops; } int bnd_exists(const Bundle *bundle, const char *filename) { for (int i = 0 ; i < bundle->n_files ; ++i) { if (strcmp(bundle->file[i].name, filename) == 0) { return 1; } } return 0; } klystrack-0.20171212/klystron/src/util/rnd.h0000644000000000000000000000501313214501362017177 0ustar rootroot#pragma once /* ----------------------------------------------------------------------- */ /* This is the Mersenne Twister by Makoto Matsumoto and Takuji Nishimura */ /* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html */ /* ----------------------------------------------------------------------- */ /* A few very minor changes were made by me - Adam */ /* A C-program for MT19937, with initialization improved 2002/1/26. Coded by Takuji Nishimura and Makoto Matsumoto. Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length). Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any feedback is very welcome. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ void init_genrand(unsigned long s); unsigned int rndu(); int rnd(int min_val,int max_val); float rndf(); long double rndl(); klystrack-0.20171212/klystron/src/util/bundle.h0000644000000000000000000000361213214501362017670 0ustar rootroot#ifndef BUNDLE_H #define BUNDLE_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include #include #include "SDL_rwops.h" #define BND_SIG "bnd!" #define BND_MAX_NAME_SIZE 256 #define bnd_cycle_key(key) (key = ((key << 2) ^ (key * 13)) | 1) typedef struct { char * name; Uint32 offset, size; } BundleFile; typedef struct { Uint32 flags; SDL_RWops *handle; BundleFile *file; Uint32 n_files; bool close_handle; } Bundle; #define BND_FLAG_CRYPTED 1 int bnd_open(Bundle *bundle, const char * filename); int bnd_open_RW(Bundle *bundle, SDL_RWops * rw); int bnd_open_file(Bundle *bundle, FILE *f, const char * filename); void bnd_free(Bundle *bundle); int bnd_exists(const Bundle *bundle, const char *filename); SDL_RWops *SDL_RWFromBundle(Bundle *bundle, const char *filename); #endif klystrack-0.20171212/klystron/src/macros.h0000644000000000000000000000707613214501362016736 0ustar rootroot#ifndef MACROS_H #define MACROS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "SDL_endian.h" #define SQR(x) ((x)*(x)) #define my_min(a,b) (((a)<(b))?(a):(b)) #define my_max(a,b) (((a)>(b))?(a):(b)) #define my_lock(s) do { if (SDL_MUSTLOCK(s)) SDL_LockSurface(s); } while(0) #define my_unlock(s) do { if (SDL_MUSTLOCK(s)) SDL_UnlockSurface(s); } while(0) #define VER(file_version, first_version, last_version, block)\ if ((((Uint16)file_version) >= ((Uint16)first_version)) && (((Uint16)file_version) <= ((Uint16)last_version)))\ {\ block;\ } #define VER_READ(file_version, first_version, last_version, var, size) VER(file_version, first_version, last_version, SDL_RWread(ctx, var, !size ? sizeof(*var) : size, 1)); #define _VER_READ(x, size) VER_READ(version, 0, MUS_VERSION, x, size) #define _VER_WRITE(x, size) fwrite(x, !size ? sizeof(*x) : size, 1, f) #ifndef ANDROID #ifdef DEBUG # define debug(...) do { printf("[DEBUG] "); printf(__VA_ARGS__); printf("\n"); } while(0) #else # define debug(...) do {} while(0) #endif // Only define warning messages if not optimizing for size (CFG=size) #ifndef REDUCESIZE #define warning(...) do { fputs("[WARNING] ", stderr); fprintf(stderr, __VA_ARGS__); fputs("\n", stderr); } while(0) #define fatal(...) do { fputs("[FATAL] ", stderr); fprintf(stderr, __VA_ARGS__); fputs("\n", stderr); } while(0) #else #define warning(...) do {} while(0) #define fatal(...) do {} while(0) #endif #else #include #ifdef DEBUG # define debug(...) do { __android_log_print(ANDROID_LOG_DEBUG, "klystron", __VA_ARGS__); } while(0) #else # define debug(...) do {} while(0) #endif #define warning(...) do { __android_log_print(ANDROID_LOG_WARN, "klystron", __VA_ARGS__); } while(0) #define fatal(...) do { __android_log_print(ANDROID_LOG_ERROR, "klystron", __VA_ARGS__); } while(0) #endif # define dumpvar(x) debug(#x " = %d", x) #define FIX_ENDIAN(x) do { x = (sizeof(x) < 2 ? x : (sizeof(x) == 2 ? SDL_SwapLE16(x) : SDL_SwapLE32(x))); } while(0) // Makes "warning: cast to pointer from integer of different size" disappear #define CASTPTR(t,x) (*(t*)&x) #ifdef __i386__ # define CASTTOPTR(t,x) (t*)x #else # define CASTTOPTR(t,x) (t*)(Uint64)x #endif #if __i386__ #define MAKEPTR(x) ((void*)(Uint32)(x)) #else #define MAKEPTR(x) ((void*)(Uint64)(x)) #endif #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define clamp(val, add, _min, _max) val = my_min(_max, my_max(_min, (int)val + add)) #endif klystrack-0.20171212/klystron/src/sllhdr.h0000644000000000000000000000640013214501362016730 0ustar rootroot#ifndef SLLHDR_H #define SLLHDR_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #define SLLHDR \ void *next; typedef struct { SLLHDR; } SllHdr; #define SLL_LIST(type)\ struct\ {\ type *used;\ type *reserve;\ } /*---------------*/ typedef SLL_LIST(void) SllList; static inline SllHdr* sllhdr_pop(SllHdr **queue) { SllHdr *ptr = *queue; if (*queue != NULL) *queue = (*queue)->next; return ptr; } #define sllhdr_walk(ptr,head,block)\ {\ ptr = (void*)head;\ while (ptr)\ {\ block;\ ptr = (void*)ptr->next;\ }\ } #define sllhdr_insert_after(queue, obj)\ if (queue != NULL)\ {\ (obj)->next = (queue)->next;\ (queue)->next = obj;\ }\ else\ {\ (queue) = obj;\ (obj)->next = NULL;\ } #define sllhdr_insert_before(queue, obj)\ if (queue != NULL)\ {\ (obj)->next = (void*)queue;\ queue = (void*)obj;\ }\ else\ {\ (queue) = (void*)obj;\ (obj)->next = NULL;\ } #define sllhdr_update_list(basetype, ptr, unused_head, in_use_head, foreach, kill_if, on_death)\ {\ ptr = (void*)in_use_head;\ basetype *prev = NULL;\ while (ptr)\ {\ foreach;\ basetype *next;\ if (kill_if)\ {\ on_death;\ if ((basetype*)in_use_head == (basetype*)ptr)\ {\ in_use_head = ptr->next;\ next = ptr->next;\ }\ else\ {\ if (prev)\ {\ prev->next = ptr->next;\ }\ next = ptr->next;\ }\ ptr->next = unused_head;\ unused_head = (basetype*)ptr;\ }\ else\ {\ prev = (basetype*)ptr;\ next = ptr->next;\ }\ ptr = (void*)next;\ }\ } #define slllist_alloc(list) sllhdr_pop((SllHdr**)&(list).reserve); #define slllist_insert_front(list, item) sllhdr_insert_before((list).used, (SllHdr*)item); #define slllist_walk(ptr,list,block)\ sllhdr_walk(ptr,list.used,block) #define slllist_update(list, basetype, ptr, foreach, kill_if, on_death) \ sllhdr_update_list(basetype, ptr, (list).reserve, (list).used, foreach, kill_if, on_death); #define slllist_init(list, data, n_items)\ {\ int i;\ for(i = 0 ; i < n_items-1 ; ++i) data[i].next = (SllHdr*)&data[i+1];\ data[i].next = NULL;\ list.reserve = (void*)&data[0];\ list.used = NULL;\ } #endif klystrack-0.20171212/klystron/src/version.in0000644000000000000000000000025113214501362017302 0ustar rootroot#ifndef KLYSTRON_VERSION_H #define KLYSTRON_VERSION_H #define KLYSTRON_REVISION "r$WCREV$" #define KLYSTRON_VERSION_STRING "klystron " KLYSTRON_REVISION #endif klystrack-0.20171212/klystron/tools/0000755000000000000000000000000013214501362015640 5ustar rootrootklystrack-0.20171212/klystron/tools/makebundle/0000755000000000000000000000000013214501362017747 5ustar rootrootklystrack-0.20171212/klystron/tools/makebundle/makebundle.c0000644000000000000000000001207313214501362022225 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "util/bundle.h" #include "macros.h" #include #include #include #include #define BS 1024*4 #define TEMP_NAME "makebundle.temp.$$$" #undef main int cwrite(void *ptr, int size, int num, FILE *f, Uint32 key) { if (key == 0) return fwrite(ptr, size, num, f); else { int n = 0; for (int i = 0 ; i < num*size ; ++i) { Uint8 d = ((Uint8*)ptr)[i] ^ key; n += fwrite(&d, 1, 1, f); bnd_cycle_key(key); } return n/size; } } void copydata(FILE *dest, const char *src, off_t size, Uint32 key) { FILE *f = fopen(src, "rb"); if (f) { for (int p = 0 ; p < size ; p += BS) { unsigned char buffer[BS]; int r = fread(buffer, 1, BS, f); if (cwrite(buffer, 1, r, dest, key) != r) { fputs("Error while writing data.\n", stderr); break; } } fclose(f); fprintf(stderr, "%u bytes written.\n", (Uint32)size); } else { fputs("Error while opening file.\n", stderr); } } int do_dir(char *dirname, char *basepath, FILE *bundle, FILE *data, Uint32 key) { int nf = 0; DIR *dir = opendir(dirname); struct dirent *de; struct stat attribute; while ((de = readdir(dir)) != NULL) { char apath[500]; sprintf(apath, "%s/%s", dirname, de->d_name); if( stat( apath, &attribute ) != -1 && ( attribute.st_mode & S_IFDIR )) { if (de->d_name[0] != '.') do_dir(apath, basepath, bundle, data, key); } else { fprintf(stderr, "%s: ", apath); if (attribute.st_size > 0) { Uint32 o = attribute.st_size; FIX_ENDIAN(o); char wpath[500]; strcpy(wpath, apath + strlen(basepath) + 1); cwrite(wpath, sizeof(char), strlen(wpath)+1, bundle, key); cwrite(&o, sizeof(o), 1, bundle, key); copydata(data, apath, attribute.st_size, 0); ++nf; } else { fputs("Skipping zero-length file.\n", stderr); } } } closedir(dir); return nf; } int main(int argc, char **argv) { int first_path = 1; Uint32 key = 0; for (first_path = 1 ; first_path < argc ; ++first_path) { if (argv[first_path][0] == '-') { ++first_path; if (first_path < argc) { for (int s =0 ; argv[first_path][s] ; ++s) { key = (key << 2) ^ ((Uint32)(argv[first_path][s])*13); bnd_cycle_key(key); } fprintf(stderr,"Using key %08x\n",key); } else { return 1; } } else break; } if (argc - first_path < 2) { fprintf(stderr, "Usage: %s [-k key] \n\n", argv[0]); return 1; } FILE *bundle = fopen(argv[first_path], "wb"); if (!bundle) { fputs("Cannot create bundle file\n", stderr); return 1; } fwrite(BND_SIG, strlen(BND_SIG), sizeof(char), bundle); Uint32 flags = key != 0 ? BND_FLAG_CRYPTED : 0; FIX_ENDIAN(flags); Uint32 num_files = 0; fwrite(&flags, 1, sizeof(flags), bundle); Uint32 num_pos = ftell(bundle); fwrite(&num_files, 1, sizeof(num_files), bundle); //write dummy value FILE *data = fopen(TEMP_NAME, "wb"); if (!data) { fputs("Cannot create temp file\n", stderr); return 1; } for (int i = first_path+1 ; i < argc ; ++i) num_files += do_dir(argv[i], argv[i], bundle, data, key); fclose(data); int err_code = 0; if (num_files == 0) { fputs("No files found, no file created.\n", stderr); err_code = 1; } else { struct stat attribute; if (stat( TEMP_NAME, &attribute ) != -1) { fputs("Copying data to bundle: ", stderr); copydata(bundle, TEMP_NAME, attribute.st_size, key); } else { fputs("Error while opening temp file.\n", stderr); } fseek(bundle, num_pos, SEEK_SET); FIX_ENDIAN(num_files); fwrite(&num_files, 1, sizeof(num_files), bundle); //write real value } fclose(bundle); fputs("Cleaning up.\n", stderr); unlink(TEMP_NAME); return err_code; } klystrack-0.20171212/klystron/tools/makebundle/Makefile0000644000000000000000000000042513214501362021410 0ustar rootrootTARGET = ../bin/makebundle.exe ifdef COMSPEC SDL = -I /mingw/include/sdl else SDL = `sdl2-config --cflags` endif $(TARGET): makebundle.c ../../src/util/bundle.h @mkdir -p ../bin gcc -o $(TARGET) -D_XOPEN_SOURCE makebundle.c -std=c99 -I ../../src $(SDL) -Wall -O3klystrack-0.20171212/klystron/tools/editor/0000755000000000000000000000000013214501362017126 5ustar rootrootklystrack-0.20171212/klystron/tools/editor/src/0000755000000000000000000000000013214501362017715 5ustar rootrootklystrack-0.20171212/klystron/tools/editor/src/export.h0000644000000000000000000000227313214501362021413 0ustar rootroot#ifndef EXPORT_H #define EXPORT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "editor.h" void level_export(Level *level); #endif klystrack-0.20171212/klystron/tools/editor/src/editor.h0000644000000000000000000000302313214501362021352 0ustar rootroot#ifndef EDITOR_H #define EDITOR_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "gfx/background.h" #include "gfx/levelbase.h" #define MAX_LAYERS 16 typedef struct { Uint8 n_layers; Background layer[MAX_LAYERS+2]; Uint16 n_events; LevEvent *event; } Level; void level_load(Level *level, FILE *f); void level_save(Level *level, FILE *f); void layer_load(Background *layer, FILE *f); void layer_save(Background *layer, FILE *f); #endif klystrack-0.20171212/klystron/tools/editor/src/main.c0000644000000000000000000011203613214501362021010 0ustar rootroot#include "editor.h" #include "export.h" #include "gfx/gfx.h" #include "gfx/font.h" #include "gui/toolutil.h" #include #include #include #include #define LIBCONFIG_STATIC #include #define MAGICK_LAYER MAX_LAYERS #define BRUSH_LAYER MAX_LAYERS+1 #define CLIPBOARDSIZE 32 enum { EM_LEVEL, EM_EVENTS }; Level level; int screen_width = 640, screen_height = 480, screen_scale; int pf_width = 640, pf_height = 480; int saved_layer = 0; int current_layer = 0; int selected_tile = 0; int selected_param = 0; int scroll_x = 0, scroll_y = 0; int drag_x = -1, drag_y = -1, drag_event = -1, selected_event = -1; int edit_mode = EM_LEVEL; int ev_drag_start_x, ev_drag_start_y, drag_start_x, drag_start_y; Uint32 bg_color = 0; GfxDomain *domain = NULL; Font font; GfxSurface *gfx = NULL; typedef enum { EVPAR_INT, EVPAR_ENUM } EvParType; typedef struct { const char *name; EvParType type; const char **enums; int int_min, int_max; int default_val; } EvParDesc; typedef struct { const char *name; Uint32 color; EvParDesc param[EV_PARAMS]; } EvDesc; static EvDesc *ev_desc = NULL; static int n_ev_desc = 0; static const char *tileset = ""; TileDescriptor *descriptor; config_t cfg; void load_dialog() { FILE *f = open_dialog("rb", "Load level", "lev", domain, gfx, &font, &font, NULL); if (f) { level_load(&level, f); fclose(f); for (int i = 0 ; i < MAX_LAYERS+2 ; ++i) { level.layer[i].tiles = descriptor; } } } void load_level(const char *path) { FILE *f = fopen(path, "rb"); if (f) { level_load(&level, f); fclose(f); for (int i = 0 ; i < MAX_LAYERS+2 ; ++i) { level.layer[i].tiles = descriptor; } } } void load_defs(const char *fn) { FILE *f = fn ? fopen(fn, "r") : open_dialog("r", "Load project defs", "cfg", domain, gfx, &font, &font, NULL); if (f) { int r = config_read(&cfg, f); fclose(f); if (r) { if (!config_lookup_string(&cfg, "tileset", &tileset)) warning("No tileset defined"); if (!config_lookup_int(&cfg, "bg_color", (Sint32*)&bg_color)) warning("No bg_color defined"); config_lookup_int(&cfg, "screen.width", &screen_width); config_lookup_int(&cfg, "screen.height", &screen_height); config_lookup_int(&cfg, "screen.scale", &screen_scale); config_lookup_int(&cfg, "playfield.width", &pf_width); config_lookup_int(&cfg, "playfield.height", &pf_height); config_setting_t *e = config_lookup(&cfg, "events"); if (e) { n_ev_desc = config_setting_length(e); ev_desc = calloc(n_ev_desc, sizeof(ev_desc[0])); for (int i = 0 ; i < n_ev_desc ; ++i) { config_setting_t *elem = config_setting_get_elem(e, i); config_setting_lookup_string(elem, "name", &ev_desc[i].name); config_setting_t *params = config_setting_get_member(elem, "params"); EvDesc *ed = &ev_desc[i]; ed->color = 0x00ff00; config_setting_lookup_int(elem, "color", (Sint32*)&ev_desc[i].color); if (params && config_setting_type(params) == CONFIG_TYPE_LIST) { int n_p = config_setting_length(params); for (int i = 0 ; i < n_p && i < EV_PARAMS - 3 ; ++i) { EvParDesc *p = &ed->param[i + 1]; config_setting_t *elem = config_setting_get_elem(params, i); config_setting_lookup_string(elem, "name", &p->name); config_setting_t *enums = config_setting_get_member(elem, "enum"); if (enums && config_setting_type(enums) == CONFIG_TYPE_ARRAY) { p->type = EVPAR_ENUM; p->int_min = 0; p->int_max = config_setting_length(enums); p->enums = calloc(p->int_max, sizeof(p->enums[0])); for (int e = 0 ; e < p->int_max ; ++e) { p->enums[e] = config_setting_get_string_elem(enums, e); } p->int_max--; } else { p->type = EVPAR_INT; config_setting_t *range = config_setting_get_member(elem, "range"); if (range && config_setting_type(range) == CONFIG_TYPE_ARRAY) { p->int_min = config_setting_get_int_elem(range, 0); p->int_max = config_setting_get_int_elem(range, 1); } else { p->int_min = 0; p->int_max = 65535; } } } } } } else { warning("No events defined"); } } else { warning("Could not read config: (%d) %s", config_error_line(&cfg), config_error_text(&cfg)); } } else { warning("cfgfile not found"); } } int save_dialog() { FILE *f = open_dialog("wb", "Save level", "lev", domain, gfx, &font, &font, NULL); if (f) { level.n_layers = MAX_LAYERS; level_save(&level, f); fclose(f); return 1; } else { return 0; } } void draw_rect(GfxDomain *s, int x1, int y1, int x2, int y2, Uint32 color) { if (x1 > x2) { int temp = x2; x2 = x1; x1 = temp; } if (y1 > y2) { int temp = y2; y2 = y1; y1 = temp; } { SDL_Rect rect = {x1, y1, x2-x1, 1}; gfx_rect(s, &rect, color); } { SDL_Rect rect = {x1, y2, x2-x1, 1}; gfx_rect(s, &rect, color); } { SDL_Rect rect = {x1, y1, 1, y2-y1}; gfx_rect(s, &rect, color); } { SDL_Rect rect = {x2, y1, 1, y2-y1}; gfx_rect(s, &rect, color); } } void vector(GfxDomain *screen, int x0, int y0, int x1, int y1, Uint32 color) { gfx_line(screen, x0, y0, x1, y1, color); int dx = (x0 - x1); int dy = (y0 - y1); int d = sqrt(dx*dx+dy*dy); if (d == 0) return; dx = dx*16/d; dy = dy*16/d; gfx_line(screen, x1, y1, x1 + dy + dx, y1 - dx + dy, color); gfx_line(screen, x1, y1, x1 - dy + dx, y1 + dx + dy, color); } void draw(GfxDomain *screen, int mouse_x, int mouse_y, int draw_all) { if (draw_all) { for (int i = 0 ; i < MAX_LAYERS ; ++i) { if (level.layer[i].flags & BG_PARALLAX) bg_draw(screen, NULL, &level.layer[i], scroll_x / my_max(1, level.layer[i].prx_mlt_x), scroll_y / my_max(1, level.layer[i].prx_mlt_y)); else bg_draw(screen, NULL, &level.layer[i], scroll_x, scroll_y); } } else { int _scroll_x = scroll_x; int _scroll_y = scroll_y; int _drag_x = drag_x; int _drag_y = drag_y; if (current_layer >= MAGICK_LAYER) { _scroll_x = my_max(0, my_min(scroll_x, level.layer[current_layer].w * CELLSIZE - screen_width)); _scroll_y = my_max(0, my_min(scroll_y, level.layer[current_layer].h * CELLSIZE - screen_height)); } mouse_x = (mouse_x + ((_scroll_x) & (CELLSIZE-1))) / CELLSIZE; mouse_y = (mouse_y + ((_scroll_y) & (CELLSIZE-1))) / CELLSIZE; _drag_x = (_drag_x + ((_scroll_x) & (CELLSIZE-1))) / CELLSIZE; _drag_y = (_drag_y + ((_scroll_y) & (CELLSIZE-1))) / CELLSIZE; bg_draw(screen, NULL, &level.layer[current_layer], _scroll_x, _scroll_y); draw_rect(screen, -_scroll_x-1, -_scroll_y-1, -_scroll_x + level.layer[current_layer].w*CELLSIZE, -_scroll_y + level.layer[current_layer].h*CELLSIZE, 0xffffff); if (edit_mode == EM_LEVEL) { if (drag_x != -1) { draw_rect(screen, (_drag_x)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (_drag_y)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)), (mouse_x+1)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (mouse_y+1)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)), 0xffffff); } else { draw_rect(screen, (mouse_x)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (mouse_y)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)), (mouse_x+level.layer[BRUSH_LAYER].w)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (mouse_y+level.layer[BRUSH_LAYER].h)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)), 0xffffff); } } else { for (int i = 0 ; i < level.n_events ; ++i) { for (int s = 0 ; s < 4 ; s+=2) draw_rect(screen, s + level.event[i].x * CELLSIZE - _scroll_x, s + level.event[i].y * CELLSIZE - _scroll_y, level.event[i].w * CELLSIZE + level.event[i].x * CELLSIZE - _scroll_x - s, level.event[i].h * CELLSIZE + level.event[i].y * CELLSIZE - _scroll_y - s, i == selected_event ? 0xffffff : ev_desc[level.event[i].param[0]].color); if (level.event[i].param[EV_NEXT] != -1 && level.event[i].param[EV_NEXT] < level.n_events) { vector(screen, level.event[i].x * CELLSIZE + level.event[i].w*CELLSIZE/2 - _scroll_x, level.event[i].y * CELLSIZE + level.event[i].h*CELLSIZE/2 - _scroll_y, level.event[level.event[i].param[EV_NEXT]].x * CELLSIZE + level.event[level.event[i].param[EV_NEXT]].w*CELLSIZE/2 - _scroll_x, level.event[level.event[i].param[EV_NEXT]].y * CELLSIZE + level.event[level.event[i].param[EV_NEXT]].h*CELLSIZE/2 - _scroll_y, 0xffffff); } if (level.event[i].param[EV_TRGPARENT] != -1 && level.event[i].param[EV_TRGPARENT] < level.n_events) { vector(screen, level.event[level.event[i].param[EV_TRGPARENT]].x * CELLSIZE - _scroll_x, level.event[level.event[i].param[EV_TRGPARENT]].y * CELLSIZE - _scroll_y, level.event[i].x * CELLSIZE - _scroll_x, level.event[i].y * CELLSIZE - _scroll_y, 0xff0000); } } } } if (current_layer < MAGICK_LAYER) draw_rect(screen, screen->screen_w / 2 - pf_width / 2, screen->screen_h / 2 - pf_height / 2, screen->screen_w / 2 + pf_width / 2, screen->screen_h / 2 + pf_height / 2, 0xa0a040); } void set_flags(int flip) { if (current_layer < MAGICK_LAYER) level.layer[current_layer].flags ^= flip; } void resize_layer(int w, int h) { if (current_layer == MAGICK_LAYER) return; Background *layer = &level.layer[current_layer]; if (w <= 0 || h <= 0) { layer->w = my_max(0, layer->w); layer->h = my_max(0, layer->h); if (layer->data) free (layer->data); layer->data = NULL; } BgCell * temp = layer->data; layer->data = malloc(sizeof(BgCell)*w*h); memset(layer->data, 0, sizeof(BgCell)*w*h); if (temp) { for (int y = 0 ; y < h && y < layer->h ; ++y) { for (int x = 0 ; x < w && x < layer->w ; ++x) { memcpy(&layer->data[w*y+x], &temp[x+y*layer->w], sizeof(layer->data[0])); } } free(temp); } layer->w = w; layer->h = h; } void get_tile(int x, int y) { if (current_layer != MAGICK_LAYER) { x += scroll_x; y += scroll_y; } x /= CELLSIZE; y /= CELLSIZE; if (saved_layer == BRUSH_LAYER || current_layer == BRUSH_LAYER) { if (!(x >= level.layer[current_layer].w || x < 0 || y >= level.layer[current_layer].h || y < 0)); selected_tile = level.layer[current_layer].data[x + y*level.layer[current_layer].w].tile; return; } if (level.layer[current_layer].flags & BG_REPEAT_X) x = (x % level.layer[current_layer].w + level.layer[current_layer].w) % level.layer[current_layer].w; if (level.layer[current_layer].flags & BG_REPEAT_Y) y = (y % level.layer[current_layer].h + level.layer[current_layer].h) % level.layer[current_layer].h; if (!(x >= level.layer[current_layer].w || x < 0 || y >= level.layer[current_layer].h || y < 0)) { int temp = current_layer; current_layer = BRUSH_LAYER; resize_layer(1,1); current_layer = temp; selected_tile = level.layer[BRUSH_LAYER].data[0].tile = level.layer[current_layer].data[x+y*level.layer[current_layer].w].tile; } } void set_tile(int ax, int ay) { if (current_layer == MAGICK_LAYER) return; if (current_layer == BRUSH_LAYER) { ax /= CELLSIZE; ay /= CELLSIZE; if (!(ax >= level.layer[current_layer].w || ax < 0 || ay >= level.layer[current_layer].h || ay < 0)) level.layer[current_layer].data[ax + ay*level.layer[current_layer].w].tile = selected_tile; return; } ax += scroll_x; ay += scroll_y; int fx = ax < 0; int fy = ay < 0; ax /= CELLSIZE; ay /= CELLSIZE; for (int y = 0 ; y < level.layer[BRUSH_LAYER].h ; ++y) { for (int x = 0 ; x < level.layer[BRUSH_LAYER].w ; ++x) { int _x = x+ax-fx, _y = y+ay-fy; if (level.layer[current_layer].flags & BG_REPEAT_X) _x = (_x % level.layer[current_layer].w + level.layer[current_layer].w) % level.layer[current_layer].w; if (level.layer[current_layer].flags & BG_REPEAT_Y) _y = (_y % level.layer[current_layer].h + level.layer[current_layer].h) % level.layer[current_layer].h; if (!(_x >= level.layer[current_layer].w || _x < 0 || _y >= level.layer[current_layer].h || _y < 0)) level.layer[current_layer].data[_x + _y*level.layer[current_layer].w].tile = level.layer[BRUSH_LAYER].data[x+y*level.layer[BRUSH_LAYER].w].tile; } } } int has_pixels(TileDescriptor *desc) { my_lock(desc->surface->surface); int result = 0; #if SDL_VERSION_ATLEAST(1,3,0) Uint32 key; SDL_GetColorKey(desc->surface->surface, &key); #else const Uint32 key = desc->surface->surface->format->colorkey; #endif for (int y = 0 ; y < desc->rect.h ; ++y) { Uint8 *p = (Uint8 *)desc->surface->surface->pixels + ((int)desc->rect.y + y) * desc->surface->surface->pitch + (int)desc->rect.x * desc->surface->surface->format->BytesPerPixel; for (int x = 0 ; x < desc->rect.w ; ++x) { //printf("%08x", *(Uint32*)p); if ((*((Uint32*)p)&0xffffff) != key) { ++result; } p+=desc->surface->surface->format->BytesPerPixel; } } my_unlock(desc->surface->surface); return result; } void init_magic_layer(int w, int h, TileDescriptor *desc, int tiles) { level.layer[BRUSH_LAYER].w = 1; level.layer[BRUSH_LAYER].h = 1; level.layer[BRUSH_LAYER].data = malloc(level.layer[BRUSH_LAYER].w*level.layer[BRUSH_LAYER].h*sizeof(level.layer[BRUSH_LAYER].data[0])); memset(level.layer[BRUSH_LAYER].data, 0, level.layer[BRUSH_LAYER].w*level.layer[BRUSH_LAYER].h*sizeof(level.layer[BRUSH_LAYER].data[0])); level.layer[BRUSH_LAYER].data[0].tile = selected_tile; level.layer[MAGICK_LAYER].w = w / CELLSIZE; level.layer[MAGICK_LAYER].h = h / CELLSIZE; level.layer[MAGICK_LAYER].data = malloc(level.layer[MAGICK_LAYER].w*level.layer[MAGICK_LAYER].h*sizeof(level.layer[MAGICK_LAYER].data[0])); memset(level.layer[MAGICK_LAYER].data, 0, level.layer[MAGICK_LAYER].w*level.layer[MAGICK_LAYER].h*sizeof(level.layer[MAGICK_LAYER].data[0])); for (int i = 0 ; i < tiles ; ++i) { int x = desc[i].rect.x / CELLSIZE; int y = desc[i].rect.y / CELLSIZE; level.layer[MAGICK_LAYER].data[x+y*level.layer[MAGICK_LAYER].w].tile = has_pixels(&desc[i]) ? i+1 : 0; } } void clear_layer() { if (current_layer >= MAGICK_LAYER) return; memset(level.layer[current_layer].data, 0, level.layer[current_layer].w*level.layer[current_layer].h*sizeof(level.layer[current_layer].data[0])); } void get_brush(int x1, int y1, int x2, int y2) { if (current_layer == BRUSH_LAYER) return; if (current_layer < MAGICK_LAYER) { x1 += scroll_x; y1 += scroll_y; x2 += scroll_x; y2 += scroll_y; } x1 /= CELLSIZE; y1 /= CELLSIZE; x2 /= CELLSIZE; y2 /= CELLSIZE; if (x1 > x2) { int temp = x2; x2 = x1; x1 = temp; } if (y1 > y2) { int temp = y2; y2 = y1; y1 = temp; } free(level.layer[BRUSH_LAYER].data); level.layer[BRUSH_LAYER].w = x2 - x1 + 1; level.layer[BRUSH_LAYER].h = y2 - y1 + 1; level.layer[BRUSH_LAYER].data = malloc(level.layer[BRUSH_LAYER].w * level.layer[BRUSH_LAYER].h * sizeof(level.layer[BRUSH_LAYER].data[0])); memset(level.layer[BRUSH_LAYER].data, 0, level.layer[BRUSH_LAYER].w * level.layer[BRUSH_LAYER].h * sizeof(level.layer[BRUSH_LAYER].data[0])); for (int y = 0 ; y < level.layer[BRUSH_LAYER].h ; ++y) { for (int x = 0 ; x < level.layer[BRUSH_LAYER].w ; ++x) { int _x = x + x1; int _y = y + y1; if (level.layer[current_layer].flags & BG_REPEAT_X) _x = (_x % level.layer[current_layer].w + level.layer[current_layer].w) % level.layer[current_layer].w; else if (_x >= level.layer[current_layer].w) break; if (level.layer[current_layer].flags & BG_REPEAT_Y) _y = (_y % level.layer[current_layer].h + level.layer[current_layer].h) % level.layer[current_layer].h; else if (_y >= level.layer[current_layer].h) break; level.layer[BRUSH_LAYER].data[x+y*level.layer[BRUSH_LAYER].w].tile = level.layer[current_layer].data[_x+_y*level.layer[current_layer].w].tile; } } } void swap(void *a, void *b, size_t size) { void * ptr = malloc(size); memcpy(ptr, a, size); memcpy(a, b, size); memcpy(b, ptr, size); free(ptr); } int get_event(int x, int y) { x += scroll_x; y += scroll_y; if (x < 0) x-=CELLSIZE; if (y < 0) y-=CELLSIZE; x /= CELLSIZE; y /= CELLSIZE; // check for clicks on border const int border = 1; for (int i = 0 ; i < level.n_events ; ++i) { if (((int)level.event[i].x <= x && (int)level.event[i].y <= y && (int)level.event[i].x+(int)level.event[i].w > x && (int)level.event[i].y+(int)level.event[i].h > y ) && !((int)level.event[i].x + border <= x && (int)level.event[i].y + border <= y && (int)level.event[i].x+(int)level.event[i].w - border > x && (int)level.event[i].y+(int)level.event[i].h - border > y )) return i; } // check for clicks inside the full area for (int i = 0 ; i < level.n_events ; ++i) { if ((int)level.event[i].x <= x && (int)level.event[i].y <= y && (int)level.event[i].x+(int)level.event[i].w > x && (int)level.event[i].y+(int)level.event[i].h > y ) return i; } return -1; } void move_ev_pos(int x, int y) { if (drag_event == -1) return; level.event[drag_event].x+=x; level.event[drag_event].y+=y; } void add_event(int x, int y) { level.event = realloc(level.event, (level.n_events + 1) * sizeof(*level.event)); x += scroll_x; y += scroll_y; x /= CELLSIZE; y /= CELLSIZE; level.event[level.n_events].x = x; level.event[level.n_events].y = y; level.event[level.n_events].w = 1; level.event[level.n_events].h = 1; if (drag_event != -1) { level.event[level.n_events].w = level.event[drag_event].w; level.event[level.n_events].h = level.event[drag_event].h; memcpy(&level.event[level.n_events].param, &level.event[drag_event].param, sizeof(level.event[drag_event].param)); } else { if (n_ev_desc > 0) { for (int i = 0; i < EV_PARAMS ; ++i) level.event[level.n_events].param[i] = ev_desc[0].param[i].default_val; } level.event[level.n_events].param[EV_NEXT] = -1; level.event[level.n_events].param[EV_TRGPARENT] = -1; } selected_event = level.n_events; ++level.n_events; } void delete_event() { if (selected_event == -1) return; memcpy(&level.event[selected_event], &level.event[selected_event+1], (level.n_events - selected_event) * sizeof(*level.event)); --level.n_events; for (int i = 0 ; i < level.n_events ; ++i) { if (level.event[i].param[EV_NEXT] == selected_event) { level.event[i].param[EV_NEXT] = -1; } else if (level.event[i].param[EV_NEXT] > selected_event) { --level.event[i].param[EV_NEXT]; } if (level.event[i].param[EV_TRGPARENT] == selected_event) { level.event[i].param[EV_TRGPARENT] = -1; } else if (level.event[i].param[EV_TRGPARENT] > selected_event) { --level.event[i].param[EV_TRGPARENT]; } } if (selected_event >= level.n_events) --selected_event; } void shift_layer(int dx, int dy) { int w = level.layer[current_layer].w; int h = level.layer[current_layer].h; BgCell *temp = malloc(sizeof(BgCell)*w*h); for (int y = 0 ; y < h ; ++y) for (int x = 0 ; x < w ; ++x) { memcpy(&temp[(x + dx + w) % w + ((y + dy + h) % h) * w], &level.layer[current_layer].data[x+y*w], sizeof(BgCell)); } memcpy(level.layer[current_layer].data, temp, w * h * sizeof(BgCell)); free(temp); } void shift_events(int dx,int dy) { for (int i = 0 ; i < level.n_events ; ++i) { level.event[i].x += dx; level.event[i].y += dy; } } void double_layer() { int w = level.layer[current_layer].w; int h = level.layer[current_layer].h; BgCell *temp = malloc(sizeof(BgCell) * (w * 2) * (h * 2)); for (int y = 0 ; y < h * 2 ; ++y) for (int x = 0 ; x < w * 2 ; ++x) { memcpy(&temp[x + y * (w * 2)], &level.layer[current_layer].data[(x / 2) + (y / 2) * w], sizeof(BgCell)); } BgCell *temp2 = level.layer[current_layer].data; level.layer[current_layer].data = temp; level.layer[current_layer].w *= 2; level.layer[current_layer].h *= 2; free(temp2); } void insert_rowcol(int sx, int sy, int dx, int dy) { debug("Inserting row/col at %d,%d", sx, sy); resize_layer(level.layer[current_layer].w + dx, level.layer[current_layer].h + dy); for (int x = level.layer[current_layer].w - 1 ; x >= sx + dx ; --x) { for (int y = 0 ; y < level.layer[current_layer].h ; ++y) { level.layer[current_layer].data[x + y * level.layer[current_layer].w].tile = level.layer[current_layer].data[x + y * level.layer[current_layer].w - dx].tile; } } for (int x = 0 ; x < level.layer[current_layer].w ; ++x) { for (int y = level.layer[current_layer].h - 1 ; y >= sy + dy ; --y) { level.layer[current_layer].data[x + y * level.layer[current_layer].w].tile = level.layer[current_layer].data[x + (y - dy) * level.layer[current_layer].w].tile; } } } void resize_event(int dx,int dy) { if (selected_event == -1) return; if (dx < 0 && level.event[selected_event].w > 1) level.event[selected_event].w += dx; if (dy < 0 && level.event[selected_event].h > 1) level.event[selected_event].h += dy; if (dx > 0 && level.event[selected_event].w < 65535) level.event[selected_event].w += dx; if (dy > 0 && level.event[selected_event].h < 65535) level.event[selected_event].h += dy; } #undef main int main(int argc, char **argv) { SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE); atexit(SDL_Quit); domain = gfx_create_domain("Editor", 0, 640, 480, 1); domain->screen_w = 640; domain->screen_h = 480; domain->fps = 20; domain->scale = 1; gfx_domain_update(domain, true); gfx = gfx_load_surface(domain, "bevel.bmp", GFX_KEYED); font_load_file(domain, &font, "8x8.fnt"); config_init(&cfg); load_defs(argc > 1 ? argv[1] : NULL); if (strcmp(tileset,"") == 0) { fatal("no tileset specified"); return 1; } if (argc > 2) load_level(argv[2]); domain->screen_w = screen_width; domain->screen_h = screen_height; domain->scale = screen_scale; gfx_domain_update(domain, true); GfxSurface *tiles = gfx_load_surface(domain, tileset, GFX_KEYED); if (!tiles) { fatal("tileset not found"); return 2; } descriptor = gfx_build_tiledescriptor(tiles, CELLSIZE, CELLSIZE, NULL); for (int i = 0 ; i < MAX_LAYERS+2 ; ++i) { level.layer[i].tiles = descriptor; } level.n_layers = MAX_LAYERS; init_magic_layer(tiles->surface->w, tiles->surface->h, descriptor, (tiles->surface->w/CELLSIZE) * (tiles->surface->h/CELLSIZE)); int done = 0; while (1) { SDL_Event e; int got_event = 0; while (SDL_PollEvent(&e)) { got_event = 1; switch (e.type) { case SDL_QUIT: done = 1; break; case SDL_MOUSEMOTION: { if (e.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT)) { scroll_x -= e.motion.x/domain->scale - drag_start_x; scroll_y -= e.motion.y/domain->scale - drag_start_y; drag_start_x = e.button.x / domain->scale; drag_start_y = e.button.y / domain->scale; } if (edit_mode == EM_LEVEL && e.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT) && drag_x == -1) { set_tile(e.motion.x / domain->scale, e.motion.y / domain->scale); } else if (edit_mode == EM_EVENTS && e.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT) && drag_event != -1) { move_ev_pos(e.motion.x / CELLSIZE / domain->scale - ev_drag_start_x, e.motion.y / CELLSIZE / domain->scale - ev_drag_start_y); ev_drag_start_x = e.motion.x / CELLSIZE / domain->scale; ev_drag_start_y = e.motion.y / CELLSIZE / domain->scale; } } break; case SDL_MOUSEBUTTONUP: { if (edit_mode == EM_LEVEL && drag_x != -1) { get_brush(drag_x, drag_y, e.button.x / domain->scale, e.button.y / domain->scale); drag_x = -1; selected_event = drag_event = -1; } else if (edit_mode == EM_EVENTS && drag_event != -1) { drag_event = -1; } } break; case SDL_MOUSEBUTTONDOWN: drag_start_x = e.button.x / domain->scale; drag_start_y = e.button.y / domain->scale; if (edit_mode == EM_LEVEL) { selected_event = drag_event = -1; if (e.button.button == (SDL_BUTTON_LEFT)) { const Uint8 * keys = SDL_GetKeyboardState(NULL); if (keys[SDL_SCANCODE_LSHIFT]||keys[SDL_SCANCODE_RSHIFT]) { drag_x = e.button.x / domain->scale; drag_y = e.button.y / domain->scale; } else { set_tile(e.button.x / domain->scale, e.button.y / domain->scale); } } if ((e.button.button == (SDL_BUTTON_LEFT) && current_layer == MAGICK_LAYER)) { get_tile(e.button.x / domain->scale, e.button.y / domain->scale); } } else { const Uint8 * keys = SDL_GetKeyboardState(NULL); if (selected_event != -1 && (keys[SDL_SCANCODE_LCTRL]||keys[SDL_SCANCODE_RCTRL])) { level.event[selected_event].param[(keys[SDL_SCANCODE_LSHIFT]||keys[SDL_SCANCODE_RSHIFT])?EV_TRGPARENT:EV_NEXT] = get_event(e.button.x / domain->scale, e.button.y / domain->scale); } else { drag_event = selected_event = get_event(e.button.x / domain->scale, e.button.y / domain->scale); ev_drag_start_x = e.button.x / CELLSIZE / domain->scale; ev_drag_start_y = e.button.y / CELLSIZE / domain->scale; } } break; case SDL_KEYDOWN: if ((e.key.keysym.mod & KMOD_SHIFT) && (e.key.keysym.mod & KMOD_CTRL)) { if (e.key.keysym.sym == SDLK_i) { int x,y; SDL_GetMouseState(&x, &y); insert_rowcol((x / domain->scale + scroll_x) / CELLSIZE, (y / domain->scale + scroll_y) / CELLSIZE, 1, 0); } else if (edit_mode == EM_EVENTS) { switch (e.key.keysym.sym) { default:break; case SDLK_UP: shift_events(0,-1); break; case SDLK_DOWN: shift_events(0,1); break; case SDLK_LEFT: shift_events(-1,0); break; case SDLK_RIGHT: shift_events(1,0); break; } } else { switch (e.key.keysym.sym) { default:break; case SDLK_UP: shift_layer(0,-1); break; case SDLK_DOWN: shift_layer(0,1); break; case SDLK_LEFT: shift_layer(-1,0); break; case SDLK_RIGHT: shift_layer(1,0); break; } } } else if (e.key.keysym.mod & KMOD_CTRL) { if (e.key.keysym.sym == SDLK_F9) level_export(&level); else if (e.key.keysym.sym == SDLK_s) save_dialog(); else if (e.key.keysym.sym == SDLK_o) load_dialog(); else if (e.key.keysym.sym == SDLK_i) { int x,y; SDL_GetMouseState(&x, &y); insert_rowcol((x / domain->scale + scroll_x) / CELLSIZE, (y / domain->scale + scroll_y) / CELLSIZE, 0, 1); } else if (edit_mode == EM_EVENTS) { switch (e.key.keysym.sym) { default:break; case SDLK_UP: resize_event(0,-1); break; case SDLK_DOWN: resize_event(0,1); break; case SDLK_LEFT: resize_event(-1,0); break; case SDLK_RIGHT: resize_event(1,0); break; } } else { switch (e.key.keysym.sym) { case SDLK_UP: if (level.layer[current_layer].h > 0) resize_layer(level.layer[current_layer].w, level.layer[current_layer].h-1); break; case SDLK_DOWN: resize_layer(level.layer[current_layer].w, level.layer[current_layer].h+1); break; case SDLK_LEFT: if (level.layer[current_layer].w > 0) resize_layer(level.layer[current_layer].w-1, level.layer[current_layer].h); break; case SDLK_RIGHT: resize_layer(level.layer[current_layer].w+1, level.layer[current_layer].h); break; case SDLK_F10: clear_layer(); break; default: break; } } } else { if (edit_mode == EM_LEVEL) { switch (e.key.keysym.sym) { case SDLK_h: double_layer(); break; case SDLK_PAGEUP: { if (current_layer > 0) { swap(&level.layer[current_layer], &level.layer[current_layer-1], sizeof(level.layer[current_layer])); --current_layer; } } break; case SDLK_PAGEDOWN: { if (current_layer < MAX_LAYERS - 1) { swap(&level.layer[current_layer], &level.layer[current_layer+1], sizeof(level.layer[current_layer])); ++current_layer; } } break; case SDLK_e: edit_mode = edit_mode == EM_LEVEL ? EM_EVENTS : EM_LEVEL; break; case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: case SDLK_5: case SDLK_6: case SDLK_7: case SDLK_8: current_layer = e.key.keysym.sym-SDLK_1; break; case SDLK_b: current_layer = BRUSH_LAYER; break; case SDLK_RALT: case SDLK_LALT: if (e.key.repeat) break; saved_layer = current_layer; current_layer = MAGICK_LAYER; break; case SDLK_UP: scroll_y -= 4; break; case SDLK_DOWN: scroll_y += 4; break; case SDLK_LEFT: scroll_x -= 4; break; case SDLK_RIGHT: scroll_x += 4; break; case SDLK_m: level.layer[current_layer].prx_mlt_x = (level.layer[current_layer].prx_mlt_x + 1) % 17; break; case SDLK_n: level.layer[current_layer].prx_mlt_y = (level.layer[current_layer].prx_mlt_y + 1) % 17; break; case SDLK_p: set_flags(BG_PARALLAX); break; case SDLK_x: set_flags(BG_REPEAT_X); break; case SDLK_y: set_flags(BG_REPEAT_Y); break; default: break; } } else { { switch (e.key.keysym.sym) { case SDLK_e: edit_mode = edit_mode == EM_LEVEL ? EM_EVENTS : EM_LEVEL; break; case SDLK_INSERT: { int x,y; SDL_GetMouseState(&x, &y); add_event(x / domain->scale, y / domain->scale); } break; case SDLK_DELETE: delete_event(); break; case SDLK_PERIOD: case SDLK_COMMA: if (selected_event == -1) break; level.event[selected_event].param[selected_param] += e.key.keysym.sym == SDLK_COMMA ? -1 : 1; if (selected_param == 0) { level.event[selected_event].param[selected_param] = my_max(0, my_min(n_ev_desc - 1,level.event[selected_event].param[selected_param])); for (int i = 1 ; i < EV_PARAMS - 2 ; ++i) level.event[selected_event].param[i] = my_max(ev_desc[level.event[selected_event].param[0]].param[i].int_min, my_min(ev_desc[level.event[selected_event].param[0]].param[i].int_max ,level.event[selected_event].param[i])); } else { if (selected_param != EV_NEXT && selected_param != EV_TRGPARENT) level.event[selected_event].param[selected_param] = my_max(ev_desc[level.event[selected_event].param[0]].param[selected_param].int_min, my_min(ev_desc[level.event[selected_event].param[0]].param[selected_param].int_max ,level.event[selected_event].param[selected_param])); } break; case SDLK_PAGEUP: selected_param = (selected_param - 1) & (EV_PARAMS-1); break; case SDLK_PAGEDOWN: selected_param = (selected_param + 1) & (EV_PARAMS-1); break; case SDLK_UP: scroll_y -= 4; break; case SDLK_DOWN: scroll_y += 4; break; case SDLK_LEFT: scroll_x -= 4; break; case SDLK_RIGHT: scroll_x += 4; break; default: break; } } } } break; case SDL_KEYUP: if(edit_mode == EM_LEVEL) { switch (e.key.keysym.sym) { case SDLK_RALT: case SDLK_LALT: current_layer = saved_layer; break; default: break; } } break; } } if (got_event) { const Uint8 * keys = SDL_GetKeyboardState(NULL); int x,y; SDL_GetMouseState(&x, &y); int show_all_layers = keys[SDL_SCANCODE_A]; gfx_rect(domain, NULL, bg_color); draw(domain, x / domain->scale, y / domain->scale, show_all_layers); static const char *layer_names[] = { "Tiles", "Brush" }; char text[100], si[10]; SDL_Rect textpos = {domain->screen_w - 400,0, 1000, 1000}; if (edit_mode == EM_LEVEL) { //if (current_layer < MAGICK_LAYER) { sprintf(si, "%d", current_layer); sprintf(text, "[L %s] prx(%s) pos(%d,%d) size(%dx%d,%dx%d)\n", show_all_layers?"All":(current_layer>=MAGICK_LAYER?layer_names[current_layer-MAGICK_LAYER]:si), level.layer[current_layer].flags&BG_PARALLAX?"ON":"OFF", scroll_x/CELLSIZE, scroll_y/CELLSIZE, level.layer[current_layer].w, level.layer[current_layer].prx_mlt_x, level.layer[current_layer].h, level.layer[current_layer].prx_mlt_y); font_write(&font, domain, &textpos, text); textpos.y += font.h; } } else { if (selected_event == -1) { sprintf(text, "[EV] pos(%d,%d)\n", scroll_x/CELLSIZE, scroll_y/CELLSIZE); font_write(&font, domain, &textpos, text); textpos.y += font.h; } else { sprintf(text, "[EV:%02x(%d,%d %d,%d)] pos(%d,%d)\n", selected_event, level.event[selected_event].x, level.event[selected_event].y, level.event[selected_event].w, level.event[selected_event].h, scroll_x/CELLSIZE, scroll_y/CELLSIZE); font_write(&font, domain, &textpos, text); textpos.y += font.h; for (int i = 0 ; i < EV_PARAMS ; ++i) { char s = ' '; if (i == selected_param) s = ''; if (i == 0) { snprintf(text, 100, "%-9s: %s", "Type", ev_desc[level.event[selected_event].param[i]].name); } else if (i == EV_TRGPARENT) { snprintf(text, 100, "%-9s: %4d", "TrgParent", level.event[selected_event].param[i]); } else if (i == EV_NEXT) { snprintf(text, 100, "%-9s: %4d", "Next", level.event[selected_event].param[i]); } else { if (ev_desc[level.event[selected_event].param[0]].param[i].type == EVPAR_ENUM) snprintf(text, 100, "%-9s: %s", ev_desc[level.event[selected_event].param[0]].param[i].name, ev_desc[level.event[selected_event].param[0]].param[i].enums[level.event[selected_event].param[i]]); else snprintf(text, 100, "%-9s: %4d", ev_desc[level.event[selected_event].param[0]].param[i].name, level.event[selected_event].param[i]); } font_write_args(&font, domain, &textpos, "%c%s", s, text); textpos.y += font.h; } } } gfx_domain_flip(domain); } else { SDL_Delay(1); } if (done) { int r = confirm_ync(domain, gfx, &font, "Save level?"); if (r == 0) done = 0; if (r == -1) goto out; if (r == 1) { if (!save_dialog()) done = 0; else break; } } } out: font_destroy(&font); config_destroy(&cfg); free(ev_desc); return 0; } klystrack-0.20171212/klystron/tools/editor/src/export.c0000644000000000000000000001133713214501362021407 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "export.h" #include "gfx/levelbase.h" #include "gui/toolutil.h" #define export(ptr, f) { fwrite(ptr, 1, sizeof(*ptr) ,f); } extern Font font; extern GfxDomain *domain; extern GfxSurface *gfx; void export_opcode(int opcode, int repeat, FILE *f) { LevOpCode op = { opcode, repeat }; export(&op.opcode, f); export(&op.repeat, f); } void export_layer(LevLayer *layer, FILE *f) { export(&layer->flags, f); export(&layer->w, f); export(&layer->h, f); export(&layer->prx_mlt_x, f); export(&layer->prx_mlt_y, f); export(&layer->off_x, f); export(&layer->off_y, f); } void export_tile(LevTile *tile, FILE *f) { export(&tile->type, f); } void export_rep(LevRepTile *tile, FILE *f) { export(&tile->repeat, f); export(&tile->type, f); } void export_event(LevEvent *event, FILE *f) { export(&event->x, f); export(&event->y, f); export(&event->w, f); export(&event->h, f); export(&event->param, f); } void level_export(Level *level) { FILE *f = open_dialog("wb", "Export level", "exp", domain, gfx, &font, &font, NULL); for (int i = 0 ; i < level->n_layers ; ++i) { if (level->layer[i].w > 0 && level->layer[i].h > 0) { export_opcode(LOP_LAYER, 1, f); LevLayer header; header.flags = level->layer[i].flags; header.w = level->layer[i].w; header.h = level->layer[i].h; header.prx_mlt_x = level->layer[i].prx_mlt_x; header.prx_mlt_y = level->layer[i].prx_mlt_y; header.off_x = level->layer[i].off_x; header.off_y = level->layer[i].off_y; export_layer(&header, f); //export_opcode(LOP_TILE, level->layer[i].w * level->layer[i].h, f); int * lut = calloc(level->layer[i].h*level->layer[i].w+1, sizeof(int)); int lutp = 0; int prev = level->layer[i].data[0].tile; int count = 0; for (int x = 0 ; x < level->layer[i].h*level->layer[i].w ; ++x) { if (x != level->layer[i].h*level->layer[i].w-1 && prev == level->layer[i].data[x].tile) { ++count; } else { lut[lutp] = count; ++lutp; count = 1; prev = level->layer[i].data[x].tile; } } prev = lut[0]; count = 1; lutp = 0; LevOpCode * lut2 = calloc(level->layer[i].h*level->layer[i].w+1, sizeof(LevOpCode)); for (int x = 0 ; x == 0 || lut[x-1] ; ++x) { if (lut[x] != 0 && (prev > 1) == (lut[x] > 1)) { ++count; } else { lut2[lutp].opcode = lut[x-1] > 1 ? LOP_REP_TILE : LOP_TILE; lut2[lutp].repeat = count; ++lutp; count = 1; prev = lut[x]; } } lut2[lutp].opcode = LOP_END; BgCell *dptr = level->layer[i].data; int c = level->layer[i].w * level->layer[i].h; for (int x = 0 ; lut2[x].opcode != LOP_END ; ++x) { export_opcode(lut2[x].opcode, lut2[x].repeat, f); for (int r = 0 ; r < lut2[x].repeat ; ++r) { switch (lut2[x].opcode) { case LOP_TILE: { LevTile tile = { dptr->tile }; export_tile(&tile, f); ++dptr; --c; } break; case LOP_REP_TILE: { LevRepTile tile = { 0, dptr->tile }; int count = 0; while (dptr->tile == tile.type && c > 0) { ++dptr; --c; ++count; }; tile.repeat = count; export_rep(&tile, f); } break; } } } free(lut); free(lut2); } } if (level->n_events > 0) { export_opcode(LOP_EVENT, level->n_events, f); for (int i = 0 ; i < level->n_events ; ++i) { export_event(&level->event[i], f); } } export_opcode(LOP_END, 0, f); fclose(f); } klystrack-0.20171212/klystron/tools/editor/src/editor.c0000644000000000000000000000464213214501362021355 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "editor.h" void layer_load(Background *layer, FILE *f) { int size = 0; fread(&size, 1, sizeof(int), f); fread(layer, 1, size, f); if (layer->h > 0 && layer->w > 0) { layer->data = malloc(layer->w*layer->h*sizeof(layer->data[0])); fread(layer->data, layer->w*layer->h, sizeof(layer->data[0]), f); } } void layer_save(Background *layer, FILE *f) { int size = sizeof(*layer); fwrite(&size, 1, sizeof(int), f); fwrite(layer, 1, size, f); fwrite(layer->data, layer->w*layer->h, sizeof(layer->data[0]), f); } void level_load(Level *level, FILE *f) { fread(&level->n_layers, 1, sizeof(int), f); for (int i = 0 ; i < level->n_layers ; ++i) layer_load(&level->layer[i], f); fread(&level->n_events, 1, sizeof(int), f); level->event = NULL; if (level->n_events > 0) { level->event = malloc(sizeof(*level->event)*level->n_events); for (int i = 0 ; i < level->n_events ; ++i) fread(&level->event[i], 1, sizeof(level->event[0]), f); } } void level_save(Level *level, FILE *f) { fwrite(&level->n_layers, 1, sizeof(int), f); for (int i = 0 ; i < level->n_layers ; ++i) layer_save(&level->layer[i], f); fwrite(&level->n_events, 1, sizeof(int), f); for (int i = 0 ; i < level->n_events ; ++i) fwrite(&level->event[i], 1, sizeof(level->event[0]), f); } klystrack-0.20171212/klystron/tools/editor/Makefile0000644000000000000000000000520413214501362020567 0ustar rootrootTARGET=editor.exe VPATH=src:src ECHO = echo CFG = debug MACHINE = -march=pentium2 # The directories containing the source files, separated by ':' # To make "debug" the default (if invoked with just "make"): # # ifeq ($(CFG),) # CFG=debug # endif # The source files: regardless of where they reside in # the source tree, VPATH will locate them... Group0_SRC = $(notdir ${wildcard src/*.c}) # Build a Dependency list and an Object list, by replacing # the .cpp extension to .d for dependency files, and .o for # object files. Group0_DEP = $(patsubst %.c, deps/Group0_%.d, ${Group0_SRC}) Group0_OBJ = $(patsubst %.c, objs.$(CFG)/Group0_%.o, \ ${Group0_SRC}) # What compiler to use for generating dependencies: # it will be invoked with -MM CXX = gcc -std=c99 --no-strict-aliasing CXXDEP = gcc -E -std=c99 # What include flags to pass to the compiler CXXFLAGS = $(MACHINE) -ftree-vectorize ifdef COMSPEC CXXFLAGS += -mthreads INCLUDEFLAGS := -I ../Common -I src -I /MinGW/include/SDL2 -I ../../src else INCLUDEFLAGS := `sdl-config --cflags` -U_FORTIFY_SOURCE -I ../../src endif LDFLAGS = -L ../../bin.$(CFG) -lengine_gfx -lengine_util -lengine_gui -lmingw32 -lSDL2_image -lSDLmain -lSDL2 -lconfig # Separate compile options per configuration ifeq ($(CFG),debug) CXXFLAGS += -O3 -g -Wall ${INCLUDEFLAGS} -DDEBUG else ifeq ($(CFG),profile) CXXFLAGS += -O3 -g -pg -Wall ${INCLUDEFLAGS} else ifeq ($(CFG),release) CXXFLAGS += -O3 -g -Wall ${INCLUDEFLAGS} else @$(ECHO) "Invalid configuration "$(CFG)" specified." @$(ECHO) "You must specify a configuration when " @$(ECHO) "running make, e.g. make CFG=debug" @$(ECHO) "Possible choices for configuration are " @$(ECHO) "'release', 'profile' and 'debug'" @exit 1 exit endif endif endif all: inform bin.$(CFG)/${TARGET} inform: @echo "Configuration "$(CFG) @echo "------------------------" bin.$(CFG)/${TARGET}: ${Group0_OBJ} | inform @mkdir -p bin.$(CFG) $(CXX) $(CXXFLAGS) -o $@ $^ ${LDFLAGS} objs.$(CFG)/Group0_%.o: %.c @mkdir -p objs.$(CFG) $(CXX) $(CXXFLAGS) -c $(CXXFLAGS) -o $@ $< deps/Group0_%.d: %.c @mkdir -p deps @$(ECHO) "Generating dependencies for $<" @set -e ; $(CXXDEP) -MM $(INCLUDEFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,objs.$(CFG)\/Group0_\1.o $@ : ,g' \ < $@.$$$$ > $@; \ rm -f $@.$$$$ clean: @rm -rf deps objs.$(CFG) bin.$(CFG) # Unless "make clean" is called, include the dependency files # which are auto-generated. Don't fail if they are missing # (-include), since they will be missing in the first # invocation! ifneq ($(MAKECMDGOALS),clean) -include ${Group0_DEP} endif klystrack-0.20171212/klystron/README.md0000644000000000000000000000163013214501362015757 0ustar rootroot# klystron This is a simple framework designed for remaking Thrust, the best game that was ever created. So far the biggest project using the framework is [klystrack](https://github.com/kometbomb/klystrack), a chiptune tracker that uses the klystron sound engine for great success. Some selling points: * Sound synthesis for music and effects * Low system requirements (the audio engine uses about 20 % CPU time on a 366 MHz Dingoo, at 22 Khz) * Pixel-accurate sprite-sprite and sprite-background collision checking * C99 (GNU99) * SDL * GUI stuff for simple mouse control In short: the feature set is something that could be found inside an generic video game console circa 1991. The API is relatively simple, yet uses some (stupid) tricks. The main goal is to provide pixel-accurate collisions which is a very important feature for a thrustlike game. The synth and the music routine are thrown in just for fun. klystrack-0.20171212/klystron/Makefile0000644000000000000000000001511713214501362016145 0ustar rootrootTARGET=engine VPATH=src:src ECHO = echo CFG = debug REV = cp -f MACHINE = util_SRC = $(notdir ${wildcard src/util/*.c}) util_DEP = $(patsubst %.c, deps/util_$(CFG)_%.d, ${util_SRC}) util_OBJ = $(patsubst %.c, objs.$(CFG)/util_%.o, ${util_SRC}) snd_SRC = $(notdir ${wildcard src/snd/*.c}) snd_DEP = $(patsubst %.c, deps/snd_$(CFG)_%.d, ${snd_SRC}) snd_OBJ = $(patsubst %.c, objs.$(CFG)/snd_%.o, ${snd_SRC}) gfx_SRC = $(notdir ${wildcard src/gfx/*.c}) gfx_DEP = $(patsubst %.c, deps/gfx_$(CFG)_%.d, ${gfx_SRC}) gfx_OBJ = $(patsubst %.c, objs.$(CFG)/gfx_%.o, ${gfx_SRC}) gui_SRC = $(notdir ${wildcard src/gui/*.c}) gui_DEP = $(patsubst %.c, deps/gui_$(CFG)_%.d, ${gui_SRC}) gui_OBJ = $(patsubst %.c, objs.$(CFG)/gui_%.o, ${gui_SRC}) $(util_OBJ) $(gfx_OBJ) lib_SRC = $(notdir ${wildcard src/lib/*.c}) lib_DEP = $(patsubst %.c, deps/lib_$(CFG)_%.d, ${lib_SRC}) lib_OBJ = $(patsubst %.c, objs.$(CFG)/lib_%.o, ${lib_SRC}) CC = gcc -shared -std=gnu99 --no-strict-aliasing CDEP = gcc -E -std=gnu99 ifndef CFLAGS CFLAGS = $(MACHINE) -ftree-vectorize endif # What include flags to pass to the compiler ifdef COMSPEC SDLFLAGS = -I /MinGW/include/SDL2 -lSDL2 -lwinmm else SDLFLAGS = `sdl2-config --cflags` -U_FORTIFY_SOURCE endif INCLUDEFLAGS= -I ../Common -I src $(SDLFLAGS) -I src/gfx -I src/snd -I src/util -I src/gui $(EXTFLAGS) # Separate compile options per configuration ifeq ($(CFG),debug) CFLAGS += -O3 -g -Wall ${INCLUDEFLAGS} -DDEBUG -fno-inline else ifeq ($(CFG),profile) CFLAGS += -O3 -pg -Wall ${INCLUDEFLAGS} else ifeq ($(CFG),release) CFLAGS += -O3 -Wall ${INCLUDEFLAGS} -s else ifeq ($(CFG),size) CFLAGS += -Os -Wall ${INCLUDEFLAGS} -s -ffast-math -fomit-frame-pointer -DREDUCESIZE else @$(ECHO) "Invalid configuration "$(CFG)" specified." @$(ECHO) "You must specify a configuration when " @$(ECHO) "running make, e.g. make CFG=debug" @$(ECHO) "Possible choices for configuration are " @$(ECHO) "'release', 'profile', 'size' and 'debug'" @exit 1 endif endif endif endif # A common link flag for all configurations LDFLAGS = .PHONY: tools all build build: Makefile @echo '#ifndef KLYSTRON_VERSION_H' > ./src/version.h @echo '#define KLYSTRON_VERSION_H' >> ./src/version.h @echo -n '#define KLYSTRON_REVISION "' >> ./src/version.h @date +"%Y%m%d" | tr -d '\n' >> ./src/version.h @echo '"' >> ./src/version.h @echo '#define KLYSTRON_VERSION_STRING "klystron " KLYSTRON_REVISION' >> ./src/version.h @echo '#endif' >> ./src/version.h make all CFG=$(CFG) all: bin.$(CFG)/lib${TARGET}_snd.a bin.$(CFG)/lib${TARGET}_gfx.a bin.$(CFG)/lib${TARGET}_util.a bin.$(CFG)/lib${TARGET}_gui.a tools ksnd: bin.$(CFG)/libksndstatic.a bin.$(CFG)/ksnd.dll ifdef COMSPEC tools: tools/bin/makebundle.exe tools/bin/editor.exe else tools: tools/bin/makebundle.exe endif inform: @echo "Configuration "$(CFG) @echo "------------------------" bin.$(CFG)/lib${TARGET}_snd.a: ${snd_OBJ} | inform @$(ECHO) "Linking "$(TARGET)"..." @mkdir -p bin.$(CFG) @ar rcs $@ $^ bin.$(CFG)/lib${TARGET}_gfx.a: ${gfx_OBJ} | inform @$(ECHO) "Linking "$(TARGET)"..." @mkdir -p bin.$(CFG) @ar rcs $@ $^ bin.$(CFG)/lib${TARGET}_util.a: ${util_OBJ} | inform @$(ECHO) "Linking "$(TARGET)"..." @mkdir -p bin.$(CFG) @ar rcs $@ $^ bin.$(CFG)/lib${TARGET}_gui.a: ${gui_OBJ} | inform @$(ECHO) "Linking "$(TARGET)"..." @mkdir -p bin.$(CFG) @ar rcs $@ $^ bin.$(CFG)/libksndstatic.a: objs.$(CFG)/lib_ksnd.o ${snd_OBJ} | inform @$(ECHO) "Linking "$(TARGET)"..." @mkdir -p bin.$(CFG) @ar rcs $@ $^ ifdef COMSPEC @$(ECHO) "Building ksndstatic.lib..." @-lib /OUT:bin.$(CFG)/ksndstatic.lib $^ endif bin.$(CFG)/ksnd.dll: objs.$(CFG)/lib_ksnd.o ${snd_OBJ} src/lib/ksnd.def | inform @$(ECHO) "Linking ksnd.dll..." @mkdir -p bin.$(CFG) @$(CC) -shared -o $@ objs.$(CFG)/lib_ksnd.o src/lib/ksnd.def ${snd_OBJ} $(CFLAGS) $(INCLUDEFLAGS) -DDLLEXPORT -Wl,--out-implib,bin.$(CFG)/libksnd.a ifdef COMSPEC @$(ECHO) "Building ksnd.lib..." @-lib /DEF:src/lib/ksnd.def /OUT:bin.$(CFG)/ksnd.lib endif objs.$(CFG)/snd_%.o: snd/%.c @$(ECHO) "Compiling "$(notdir $<)"..." @mkdir -p objs.$(CFG) @$(CC) -c $(CFLAGS) -o $@ $< objs.$(CFG)/gfx_%.o: gfx/%.c @$(ECHO) "Compiling "$(notdir $<)"..." @mkdir -p objs.$(CFG) @$(CC) -c $(CFLAGS) -o $@ $< objs.$(CFG)/util_%.o: util/%.c @$(ECHO) "Compiling "$(notdir $<)"..." @mkdir -p objs.$(CFG) @$(CC) -c $(CFLAGS) -o $@ $< objs.$(CFG)/gui_%.o: gui/%.c @$(ECHO) "Compiling "$(notdir $<)"..." @mkdir -p objs.$(CFG) @$(CC) -c $(CFLAGS) -o $@ $< objs.$(CFG)/lib_%.o: lib/%.c @$(ECHO) "Compiling "$(notdir $<)"..." @mkdir -p objs.$(CFG) @$(CC) -c $(CFLAGS) -o $@ $< deps/snd_$(CFG)_%.d: snd/%.c @mkdir -p deps @$(ECHO) "Generating dependencies for $<" @set -e ; $(CDEP) -MM $(INCLUDEFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,objs.$(CFG)\/snd_\1.o $@ : ,g' \ < $@.$$$$ > $@; \ rm -f $@.$$$$ deps/gfx_$(CFG)_%.d: gfx/%.c @mkdir -p deps @$(ECHO) "Generating dependencies for $<" @set -e ; $(CDEP) -MM $(INCLUDEFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,objs.$(CFG)\/gfx_\1.o $@ : ,g' \ < $@.$$$$ > $@; \ rm -f $@.$$$$ deps/util_$(CFG)_%.d: util/%.c @mkdir -p deps @$(ECHO) "Generating dependencies for $<" @set -e ; $(CDEP) -MM $(INCLUDEFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,objs.$(CFG)\/util_\1.o $@ : ,g' \ < $@.$$$$ > $@; \ rm -f $@.$$$$ deps/gui_$(CFG)_%.d: gui/%.c @mkdir -p deps @$(ECHO) "Generating dependencies for $<" @set -e ; $(CDEP) -MM $(INCLUDEFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,objs.$(CFG)\/gui_\1.o $@ : ,g' \ < $@.$$$$ > $@; \ rm -f $@.$$$$ deps/lib_$(CFG)_%.d: lib/%.c @mkdir -p deps @$(ECHO) "Generating dependencies for $<" @set -e ; $(CDEP) -MM $(INCLUDEFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,objs.$(CFG)\/gui_\1.o $@ : ,g' \ < $@.$$$$ > $@; \ rm -f $@.$$$$ clean: @rm -rf deps objs.release objs.debug objs.profile objs.size bin.release bin.debug bin.profile bin.size # Unless "make clean" is called, include the dependency files # which are auto-generated. Don't fail if they are missing # (-include), since they will be missing in the first # invocation! ifneq ($(MAKECMDGOALS),clean) -include ${snd_DEP} -include ${gfx_DEP} -include ${util_DEP} -include ${gui_DEP} -include ${lib_DEP} endif tools/bin/makebundle.exe: tools/makebundle/*.c make -C tools/makebundle ifdef COMSPEC tools/bin/editor.exe: tools/editor/src/* make -C tools/editor cp tools/editor/bin.$(CFG)/editor.exe tools/bin/editor.exe endif klystrack-0.20171212/klystrack/0000755000000000000000000000000013214501362014622 5ustar rootrootklystrack-0.20171212/klystrack/key/0000755000000000000000000000000013214501362015412 5ustar rootrootklystrack-0.20171212/klystrack/key/n00bstar0000644000000000000000000000070213214501362016765 0ustar rootroot# n00bstar's convoluted keymap # inspired by protracker and fasttracker [global] #play/stop K_RALT = M_SHIFT K_F6 K_RCTRL = K_F6 M_LALT K_RCTRL = K_F5 #windows K_F2 = M_SHIFT K_F4 K_F4 = M_SHIFT K_F3 K_F5 = K_F2 K_F6 = K_F4 K_F7 = M_SHIFT K_F2 K_COMMA = K_Q K_L = K_2 K_PERIOD = K_W K_SEMICOLON = K_3 K_SLASH = K_E [pattern] #tab move M_LSHIFT K_TAB = M_CTRL K_LEFT K_TAB = M_CTRL K_RIGHT [sequence] #tab move M_LSHIFT K_TAB = K_LEFT K_TAB = K_RIGHT klystrack-0.20171212/klystrack/key/AZERTY0000644000000000000000000000016013214501362016350 0ustar rootroot# Fix problems with AZERTY keyboards [pattern] K_A = K_Q K_Q = K_A K_W = K_Z K_Z = K_W K_WORLD_34 = K_2 klystrack-0.20171212/klystrack/key/FT20000644000000000000000000000014213214501362015725 0ustar rootroot# Fasttracker 2 key shortcuts [pattern] M_LSHIFT K_TAB = M_CTRL K_LEFT K_TAB = M_CTRL K_RIGHT klystrack-0.20171212/klystrack/key/DVORAK0000644000000000000000000000102513214501362016321 0ustar rootroot# Dvorak layout [global] K_QUOTE = K_Q K_LESS = K_W K_COMMA = K_W K_GREATER = K_E K_PERIOD = K_E K_P = K_R K_Y = K_T K_F = K_Y K_G = K_U K_C = K_I K_R = K_O K_L = K_L K_QUESTION = K_LEFTBRACKET K_PLUS = K_RIGHTBRACKET K_O = K_S K_E = K_D K_U = K_F K_I = K_G K_D = K_H K_H = K_J K_T = K_K K_N = K_L K_S = K_SEMICOLON K_MINUS = K_QUOTE K_SEMICOLON = K_Z K_Q = K_X K_J = K_C K_K = K_V K_X = K_B K_B = K_N K_W = K_COMMA K_V = K_PERIOD K_Z = K_SLASH K_LEFTBRACKET = K_MINUS K_RIGHTBRACKET = K_EQUALS klystrack-0.20171212/klystrack/OSX_Xcode/0000755000000000000000000000000013214501362016415 5ustar rootrootklystrack-0.20171212/klystrack/OSX_Xcode/English.lproj/0000755000000000000000000000000013214501362021133 5ustar rootrootklystrack-0.20171212/klystrack/OSX_Xcode/English.lproj/InfoPlist.strings0000644000000000000000000000125213214501362024455 0ustar rootroot/* Localized versions of Info.plist keys */ CFBundleName = "Klystrack"; CFBundleShortVersionString = "Klystrack version 1.5.1"; CFBundleGetInfoString = "Klystrack version 1.5.1, Copyright 2010 Tero Lindeman (kometbomb)."; NSHumanReadableCopyright = "Copyright 2010 Tero Lindeman (kometbomb).\nOSX Port by Christopher O'Neill (Deltafire)"; klystrack-0.20171212/klystrack/OSX_Xcode/SDLMain.m0000644000000000000000000002570513214501362020033 0ustar rootroot/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #include "SDL.h" #include "SDLMain.h" #include /* for MAXPATHLEN */ #include /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, but the method still is there and works. To avoid warnings, we declare it ourselves here. */ @interface NSApplication(SDL_Missing_Methods) - (void)setAppleMenu:(NSMenu *)menu; @end /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 0 /* Use this flag to determine whether we use CPS (docking) or not */ #define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { UInt32 lo; UInt32 hi; } CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; static NSString *getApplicationName(void) { const NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif @interface SDLApplication : NSApplication @end @implementation SDLApplication /* Invoked from the Quit menu item */ - (void)terminate:(id)sender { /* Post a SDL_QUIT event */ SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } @end /* The main class of the application, the application's delegate */ @implementation SDLMain /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { if (shouldChdir) { char parentdir[MAXPATHLEN]; CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) { chdir(parentdir); /* chdir to the binary app's parent */ } CFRelease(url); CFRelease(url2); } } #if SDL_USE_NIB_FILE /* Fix menu to contain the real app name instead of "SDL App" */ - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName { NSRange aRange; NSEnumerator *enumerator; NSMenuItem *menuItem; aRange = [[aMenu title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; enumerator = [[aMenu itemArray] objectEnumerator]; while ((menuItem = [enumerator nextObject])) { aRange = [[menuItem title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; if ([menuItem hasSubmenu]) [self fixMenu:[menuItem submenu] withAppName:appName]; } [ aMenu sizeToFit ]; } #else static void setApplicationMenu(void) { /* warning: this code is very odd */ NSMenu *appleMenu; NSMenuItem *menuItem; NSString *title; NSString *appName; appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; /* Finally give up our references to the objects */ [appleMenu release]; [menuItem release]; } /* Create a window menu */ static void setupWindowMenu(void) { NSMenu *windowMenu; NSMenuItem *windowMenuItem; NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:menuItem]; [menuItem release]; /* Put menu into the menubar */ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [windowMenuItem setSubmenu:windowMenu]; [[NSApp mainMenu] addItem:windowMenuItem]; /* Tell the application object that this is now the window menu */ [NSApp setWindowsMenu:windowMenu]; /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; } /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; /* Ensure the application object is initialised */ [SDLApplication sharedApplication]; #ifdef SDL_USE_CPS { CPSProcessSerNum PSN; /* Tell the dock about us */ if (!CPSGetCurrentProcess(&PSN)) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [SDLApplication sharedApplication]; } #endif /* SDL_USE_CPS */ /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; setApplicationMenu(); setupWindowMenu(); /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; /* Start the main event loop */ [NSApp run]; [sdlMain release]; [pool release]; } #endif /* * Catch document open requests...this lets us notice files when the app * was launched by double-clicking a document, or when a document was * dragged/dropped on the app's icon. You need to have a * CFBundleDocumentsType section in your Info.plist to get this message, * apparently. * * Files are added to gArgv, so to the app, they'll look like command line * arguments. Previously, apps launched from the finder had nothing but * an argv[0]. * * This message may be received multiple times to open several docs on launch. * * This message is ignored once the app's mainline has been called. */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = SDL_strlen(temparg) + 1; arg = (char *) SDL_malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { SDL_free(arg); return FALSE; } gArgv = newargv; SDL_strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } /* Called when the internal event loop has just started running */ - (void) applicationDidFinishLaunching: (NSNotification *) note { int status; /* Set the working directory to the .app's parent directory */ [self setupWorkingDirectory:gFinderLaunch]; #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif /* Hand off to main application code */ gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ exit(status); } @end @implementation NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString { unsigned int bufferSize; unsigned int selfLen = [self length]; unsigned int aStringLen = [aString length]; unichar *buffer; NSRange localRange; NSString *result; bufferSize = selfLen + aStringLen - aRange.length; buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar)); /* Get first part into buffer */ localRange.location = 0; localRange.length = aRange.location; [self getCharacters:buffer range:localRange]; /* Get middle part into buffer */ localRange.location = 0; localRange.length = aStringLen; [aString getCharacters:(buffer+aRange.location) range:localRange]; /* Get last part into buffer */ localRange.location = aRange.location + aRange.length; localRange.length = selfLen - localRange.location; [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; /* Build output string */ result = [NSString stringWithCharacters:buffer length:bufferSize]; NSDeallocateMemoryPages(buffer, bufferSize); return result; } @end /* Main entry point to executable */ int SDL_main (int argc, char **argv) { /* Copy the arguments into a global variable */ /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) SDL_malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } #if SDL_USE_NIB_FILE [SDLApplication poseAsClass:[NSApplication class]]; NSApplicationMain (argc, argv); #else CustomApplicationMain (argc, argv); #endif return 0; } klystrack-0.20171212/klystrack/OSX_Xcode/OSX_Xcode.xcodeproj/0000755000000000000000000000000013214501362022204 5ustar rootrootklystrack-0.20171212/klystrack/OSX_Xcode/OSX_Xcode.xcodeproj/project.pbxproj0000644000000000000000000022324213214501362025265 0ustar rootroot// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 002F3A2E09D0888800EBEB88 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A2C09D0888800EBEB88 /* SDLMain.m */; }; 690F323C1ED4BB0A0011FD0E /* hubbard.c in Sources */ = {isa = PBXBuildFile; fileRef = 690F32381ED4BB0A0011FD0E /* hubbard.c */; }; 690F323D1ED4BB0A0011FD0E /* hubdialog.c in Sources */ = {isa = PBXBuildFile; fileRef = 690F323A1ED4BB0A0011FD0E /* hubdialog.c */; }; 690F32471ED4BB240011FD0E /* memwriter.c in Sources */ = {isa = PBXBuildFile; fileRef = 690F323E1ED4BB240011FD0E /* memwriter.c */; }; 690F32481ED4BB240011FD0E /* stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 690F32411ED4BB240011FD0E /* stats.c */; }; 690F32491ED4BB240011FD0E /* wavewriter.c in Sources */ = {isa = PBXBuildFile; fileRef = 690F32431ED4BB240011FD0E /* wavewriter.c */; }; 690F324A1ED4BB240011FD0E /* zap.c in Sources */ = {isa = PBXBuildFile; fileRef = 690F32451ED4BB240011FD0E /* zap.c */; }; 8343837F19F2C341001EDF56 /* res in Resources */ = {isa = PBXBuildFile; fileRef = 8343837E19F2C341001EDF56 /* res */; }; 83722F13167AAA8F00336AFC /* key in Resources */ = {isa = PBXBuildFile; fileRef = 83722F0F167AAA8F00336AFC /* key */; }; 8377DBE919F2A24500994874 /* makebundle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DBE819F2A24500994874 /* makebundle.c */; }; 8377DD1F19F2A5A500994874 /* action.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCC719F2A5A500994874 /* action.c */; }; 8377DD2019F2A5A500994874 /* clipboard.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCC919F2A5A500994874 /* clipboard.c */; }; 8377DD2119F2A5A500994874 /* command.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCCB19F2A5A500994874 /* command.c */; }; 8377DD2219F2A5A500994874 /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCCD19F2A5A500994874 /* config.c */; }; 8377DD2319F2A5A500994874 /* console.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCCF19F2A5A500994874 /* console.c */; }; 8377DD2419F2A5A500994874 /* copypaste.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCD119F2A5A500994874 /* copypaste.c */; }; 8377DD2519F2A5A500994874 /* diskop.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCD319F2A5A500994874 /* diskop.c */; }; 8377DD2619F2A5A500994874 /* edit.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCD519F2A5A500994874 /* edit.c */; }; 8377DD2719F2A5A500994874 /* event.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCD719F2A5A500994874 /* event.c */; }; 8377DD2819F2A5A500994874 /* export.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCD919F2A5A500994874 /* export.c */; }; 8377DD2919F2A5A500994874 /* help.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCDB19F2A5A500994874 /* help.c */; }; 8377DD2A19F2A5A500994874 /* ahx.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCDE19F2A5A500994874 /* ahx.c */; }; 8377DD2B19F2A5A500994874 /* import.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCE019F2A5A500994874 /* import.c */; }; 8377DD2C19F2A5A500994874 /* mod.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCE219F2A5A500994874 /* mod.c */; }; 8377DD2D19F2A5A500994874 /* org.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCE419F2A5A500994874 /* org.c */; }; 8377DD2E19F2A5A500994874 /* xm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCE619F2A5A500994874 /* xm.c */; }; 8377DD2F19F2A5A500994874 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCE819F2A5A500994874 /* key.c */; }; 8377DD3019F2A5A500994874 /* keytab.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCEA19F2A5A500994874 /* keytab.c */; }; 8377DD3119F2A5A500994874 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCEC19F2A5A500994874 /* main.c */; }; 8377DD3219F2A5A500994874 /* menudefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCED19F2A5A500994874 /* menudefs.c */; }; 8377DD3319F2A5A500994874 /* midi.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCEE19F2A5A500994874 /* midi.c */; }; 8377DD3419F2A5A500994874 /* mused.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCF019F2A5A500994874 /* mused.c */; }; 8377DD3519F2A5A500994874 /* nostalgy.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCF419F2A5A500994874 /* nostalgy.c */; }; 8377DD3619F2A5A500994874 /* optimize.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCF619F2A5A500994874 /* optimize.c */; }; 8377DD3719F2A5A500994874 /* shortcutdefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCF819F2A5A500994874 /* shortcutdefs.c */; }; 8377DD3819F2A5A500994874 /* theme.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCFA19F2A5A500994874 /* theme.c */; }; 8377DD3919F2A5A500994874 /* undo.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DCFC19F2A5A500994874 /* undo.c */; }; 8377DD3A19F2A5A500994874 /* version in Resources */ = {isa = PBXBuildFile; fileRef = 8377DCFE19F2A5A500994874 /* version */; }; 8377DD3B19F2A5A500994874 /* version.in in Resources */ = {isa = PBXBuildFile; fileRef = 8377DD0119F2A5A500994874 /* version.in */; }; 8377DD3C19F2A5A500994874 /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD0319F2A5A500994874 /* pattern.c */; }; 8377DD3D19F2A5A500994874 /* sequence.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD0519F2A5A500994874 /* sequence.c */; }; 8377DD3E19F2A5A500994874 /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD0719F2A5A500994874 /* timer.c */; }; 8377DD3F19F2A5A500994874 /* visu.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD0919F2A5A500994874 /* visu.c */; }; 8377DD4019F2A5A500994874 /* wavetableview.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD0B19F2A5A500994874 /* wavetableview.c */; }; 8377DD4619F2A5A500994874 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD1719F2A5A500994874 /* view.c */; }; 8377DD4719F2A5A500994874 /* wave_action.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD1919F2A5A500994874 /* wave_action.c */; }; 8377DD4819F2A5A500994874 /* wave.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD1B19F2A5A500994874 /* wave.c */; }; 8377DD4919F2A5A500994874 /* wavegen.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD1D19F2A5A500994874 /* wavegen.c */; }; 8377DDFE19F2A5D800994874 /* ksnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD9419F2A5D800994874 /* ksnd.c */; }; 8377DE0219F2A5D800994874 /* cyd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DD9D19F2A5D800994874 /* cyd.c */; }; 8377DE0319F2A5D800994874 /* cydchr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDA019F2A5D800994874 /* cydchr.c */; }; 8377DE0419F2A5D800994874 /* cydcrush.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDA219F2A5D800994874 /* cydcrush.c */; }; 8377DE0519F2A5D800994874 /* cydentry.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDA519F2A5D800994874 /* cydentry.c */; }; 8377DE0619F2A5D800994874 /* cydflt.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDA719F2A5D800994874 /* cydflt.c */; }; 8377DE0719F2A5D800994874 /* cydfm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDA919F2A5D800994874 /* cydfm.c */; }; 8377DE0819F2A5D800994874 /* cydfx.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDAB19F2A5D800994874 /* cydfx.c */; }; 8377DE0919F2A5D800994874 /* cydosc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDAD19F2A5D800994874 /* cydosc.c */; }; 8377DE0A19F2A5D800994874 /* cydrvb.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDAF19F2A5D800994874 /* cydrvb.c */; }; 8377DE0B19F2A5D800994874 /* cydwave.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDB219F2A5D800994874 /* cydwave.c */; }; 8377DE0C19F2A5D800994874 /* freqs.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDB419F2A5D800994874 /* freqs.c */; }; 8377DE0D19F2A5D800994874 /* music.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDB619F2A5D800994874 /* music.c */; }; 8377DE0E19F2A5D800994874 /* pack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DDB819F2A5D800994874 /* pack.c */; }; 8377DE6719F2A6A300994874 /* background.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE2019F2A6A200994874 /* background.c */; }; 8377DE6819F2A6A300994874 /* bgcell.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE2219F2A6A200994874 /* bgcell.c */; }; 8377DE6919F2A6A300994874 /* font.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE2419F2A6A200994874 /* font.c */; }; 8377DE6A19F2A6A300994874 /* gfx.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE2619F2A6A200994874 /* gfx.c */; }; 8377DE6B19F2A6A300994874 /* levelbase.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE2919F2A6A200994874 /* levelbase.c */; }; 8377DE6C19F2A6A300994874 /* objhdr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE2B19F2A6A200994874 /* objhdr.c */; }; 8377DE7319F2A6A300994874 /* bevel.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE3E19F2A6A200994874 /* bevel.c */; }; 8377DE7419F2A6A300994874 /* dialog.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4019F2A6A200994874 /* dialog.c */; }; 8377DE7519F2A6A300994874 /* filebox.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4219F2A6A200994874 /* filebox.c */; }; 8377DE7619F2A6A300994874 /* menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4419F2A6A200994874 /* menu.c */; }; 8377DE7719F2A6A300994874 /* mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4619F2A6A200994874 /* mouse.c */; }; 8377DE7819F2A6A300994874 /* msgbox.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4819F2A6A200994874 /* msgbox.c */; }; 8377DE7919F2A6A300994874 /* shortcuts.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4A19F2A6A200994874 /* shortcuts.c */; }; 8377DE7A19F2A6A300994874 /* slider.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4C19F2A6A200994874 /* slider.c */; }; 8377DE7B19F2A6A300994874 /* toolutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE4E19F2A6A200994874 /* toolutil.c */; }; 8377DE7C19F2A6A300994874 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE5019F2A6A200994874 /* view.c */; }; 8377DE8C19F2A74D00994874 /* bundle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE8819F2A74D00994874 /* bundle.c */; }; 8377DE8D19F2A74D00994874 /* rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377DE8A19F2A74D00994874 /* rnd.c */; }; 8378C75C19A0EC9300AFBD43 /* SDL2.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 8378C75B19A0EC9300AFBD43 /* SDL2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8378C7CA19A0F17300AFBD43 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8378C75B19A0EC9300AFBD43 /* SDL2.framework */; }; 83C75C6812BBF7B20067F040 /* 256x256.icns in Resources */ = {isa = PBXBuildFile; fileRef = 83C75C6712BBF7B20067F040 /* 256x256.icns */; }; 83D5E10B19F2951F003F2ED5 /* SDL2_image.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D5E10A19F2951F003F2ED5 /* SDL2_image.framework */; }; 83D5E10D19F29528003F2ED5 /* SDL2_image.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 83D5E10A19F2951F003F2ED5 /* SDL2_image.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 8343837B19F2B411001EDF56 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 8377DBE019F2A19900994874; remoteInfo = make_bundle; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 8378C75C19A0EC9300AFBD43 /* SDL2.framework in Copy Frameworks into .app bundle */, 83D5E10D19F29528003F2ED5 /* SDL2_image.framework in Copy Frameworks into .app bundle */, ); name = "Copy Frameworks into .app bundle"; runOnlyForDeploymentPostprocessing = 0; }; 8377DBDF19F2A19900994874 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/share/man/man1/; dstSubfolderSpec = 0; files = ( ); runOnlyForDeploymentPostprocessing = 1; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 002F3A2B09D0888800EBEB88 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = SOURCE_ROOT; }; 002F3A2C09D0888800EBEB88 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = SOURCE_ROOT; }; 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 690F32381ED4BB0A0011FD0E /* hubbard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hubbard.c; path = ../src/import/hubbard.c; sourceTree = ""; }; 690F32391ED4BB0A0011FD0E /* hubbard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hubbard.h; path = ../src/import/hubbard.h; sourceTree = ""; }; 690F323A1ED4BB0A0011FD0E /* hubdialog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hubdialog.c; path = ../src/import/hubdialog.c; sourceTree = ""; }; 690F323B1ED4BB0A0011FD0E /* hubdialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hubdialog.h; path = ../src/import/hubdialog.h; sourceTree = ""; }; 690F323E1ED4BB240011FD0E /* memwriter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memwriter.c; path = ../src/memwriter.c; sourceTree = ""; }; 690F323F1ED4BB240011FD0E /* memwriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = memwriter.h; path = ../src/memwriter.h; sourceTree = ""; }; 690F32401ED4BB240011FD0E /* songstats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = songstats.h; path = ../src/songstats.h; sourceTree = ""; }; 690F32411ED4BB240011FD0E /* stats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stats.c; path = ../src/stats.c; sourceTree = ""; }; 690F32421ED4BB240011FD0E /* stats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stats.h; path = ../src/stats.h; sourceTree = ""; }; 690F32431ED4BB240011FD0E /* wavewriter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wavewriter.c; path = ../src/wavewriter.c; sourceTree = ""; }; 690F32441ED4BB240011FD0E /* wavewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wavewriter.h; path = ../src/wavewriter.h; sourceTree = ""; }; 690F32451ED4BB240011FD0E /* zap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zap.c; path = ../src/zap.c; sourceTree = ""; }; 690F32461ED4BB240011FD0E /* zap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zap.h; path = ../src/zap.h; sourceTree = ""; }; 8343837E19F2C341001EDF56 /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = ""; }; 83722F0F167AAA8F00336AFC /* key */ = {isa = PBXFileReference; lastKnownFileType = folder; name = key; path = ../key; sourceTree = SOURCE_ROOT; }; 8377DBE119F2A19900994874 /* make_bundle */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = make_bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 8377DBE819F2A24500994874 /* makebundle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = makebundle.c; path = ../../../klystron/tools/makebundle/makebundle.c; sourceTree = ""; }; 8377DCC719F2A5A500994874 /* action.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = action.c; path = ../src/action.c; sourceTree = ""; }; 8377DCC819F2A5A500994874 /* action.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = action.h; path = ../src/action.h; sourceTree = ""; }; 8377DCC919F2A5A500994874 /* clipboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = clipboard.c; path = ../src/clipboard.c; sourceTree = ""; }; 8377DCCA19F2A5A500994874 /* clipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = clipboard.h; path = ../src/clipboard.h; sourceTree = ""; }; 8377DCCB19F2A5A500994874 /* command.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = command.c; path = ../src/command.c; sourceTree = ""; }; 8377DCCC19F2A5A500994874 /* command.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = command.h; path = ../src/command.h; sourceTree = ""; }; 8377DCCD19F2A5A500994874 /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config.c; path = ../src/config.c; sourceTree = ""; }; 8377DCCE19F2A5A500994874 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../src/config.h; sourceTree = ""; }; 8377DCCF19F2A5A500994874 /* console.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = console.c; path = ../src/console.c; sourceTree = ""; }; 8377DCD019F2A5A500994874 /* console.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = console.h; path = ../src/console.h; sourceTree = ""; }; 8377DCD119F2A5A500994874 /* copypaste.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = copypaste.c; path = ../src/copypaste.c; sourceTree = ""; }; 8377DCD219F2A5A500994874 /* copypaste.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = copypaste.h; path = ../src/copypaste.h; sourceTree = ""; }; 8377DCD319F2A5A500994874 /* diskop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = diskop.c; path = ../src/diskop.c; sourceTree = ""; }; 8377DCD419F2A5A500994874 /* diskop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = diskop.h; path = ../src/diskop.h; sourceTree = ""; }; 8377DCD519F2A5A500994874 /* edit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = edit.c; path = ../src/edit.c; sourceTree = ""; }; 8377DCD619F2A5A500994874 /* edit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = edit.h; path = ../src/edit.h; sourceTree = ""; }; 8377DCD719F2A5A500994874 /* event.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = event.c; path = ../src/event.c; sourceTree = ""; }; 8377DCD819F2A5A500994874 /* event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = event.h; path = ../src/event.h; sourceTree = ""; }; 8377DCD919F2A5A500994874 /* export.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = export.c; path = ../src/export.c; sourceTree = ""; }; 8377DCDA19F2A5A500994874 /* export.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = export.h; path = ../src/export.h; sourceTree = ""; }; 8377DCDB19F2A5A500994874 /* help.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = help.c; path = ../src/help.c; sourceTree = ""; }; 8377DCDC19F2A5A500994874 /* help.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = help.h; path = ../src/help.h; sourceTree = ""; }; 8377DCDE19F2A5A500994874 /* ahx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ahx.c; sourceTree = ""; }; 8377DCDF19F2A5A500994874 /* ahx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ahx.h; sourceTree = ""; }; 8377DCE019F2A5A500994874 /* import.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = import.c; sourceTree = ""; }; 8377DCE119F2A5A500994874 /* import.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = import.h; sourceTree = ""; }; 8377DCE219F2A5A500994874 /* mod.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mod.c; sourceTree = ""; }; 8377DCE319F2A5A500994874 /* mod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mod.h; sourceTree = ""; }; 8377DCE419F2A5A500994874 /* org.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = org.c; sourceTree = ""; }; 8377DCE519F2A5A500994874 /* org.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = org.h; sourceTree = ""; }; 8377DCE619F2A5A500994874 /* xm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xm.c; sourceTree = ""; }; 8377DCE719F2A5A500994874 /* xm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xm.h; sourceTree = ""; }; 8377DCE819F2A5A500994874 /* key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = key.c; path = ../src/key.c; sourceTree = ""; }; 8377DCE919F2A5A500994874 /* key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = key.h; path = ../src/key.h; sourceTree = ""; }; 8377DCEA19F2A5A500994874 /* keytab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = keytab.c; path = ../src/keytab.c; sourceTree = ""; }; 8377DCEB19F2A5A500994874 /* keytab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = keytab.h; path = ../src/keytab.h; sourceTree = ""; }; 8377DCEC19F2A5A500994874 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../src/main.c; sourceTree = ""; }; 8377DCED19F2A5A500994874 /* menudefs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = menudefs.c; path = ../src/menudefs.c; sourceTree = ""; }; 8377DCEE19F2A5A500994874 /* midi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = midi.c; path = ../src/midi.c; sourceTree = ""; }; 8377DCEF19F2A5A500994874 /* midi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = midi.h; path = ../src/midi.h; sourceTree = ""; }; 8377DCF019F2A5A500994874 /* mused.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mused.c; path = ../src/mused.c; sourceTree = ""; }; 8377DCF119F2A5A500994874 /* mused.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mused.h; path = ../src/mused.h; sourceTree = ""; }; 8377DCF219F2A5A500994874 /* mybevdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mybevdefs.h; path = ../src/mybevdefs.h; sourceTree = ""; }; 8377DCF319F2A5A500994874 /* mymsg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mymsg.h; path = ../src/mymsg.h; sourceTree = ""; }; 8377DCF419F2A5A500994874 /* nostalgy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nostalgy.c; path = ../src/nostalgy.c; sourceTree = ""; }; 8377DCF519F2A5A500994874 /* nostalgy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nostalgy.h; path = ../src/nostalgy.h; sourceTree = ""; }; 8377DCF619F2A5A500994874 /* optimize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = optimize.c; path = ../src/optimize.c; sourceTree = ""; }; 8377DCF719F2A5A500994874 /* optimize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = optimize.h; path = ../src/optimize.h; sourceTree = ""; }; 8377DCF819F2A5A500994874 /* shortcutdefs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = shortcutdefs.c; path = ../src/shortcutdefs.c; sourceTree = ""; }; 8377DCF919F2A5A500994874 /* shortcutdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = shortcutdefs.h; path = ../src/shortcutdefs.h; sourceTree = ""; }; 8377DCFA19F2A5A500994874 /* theme.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = theme.c; path = ../src/theme.c; sourceTree = ""; }; 8377DCFB19F2A5A500994874 /* theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = theme.h; path = ../src/theme.h; sourceTree = ""; }; 8377DCFC19F2A5A500994874 /* undo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = undo.c; path = ../src/undo.c; sourceTree = ""; }; 8377DCFD19F2A5A500994874 /* undo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = undo.h; path = ../src/undo.h; sourceTree = ""; }; 8377DCFE19F2A5A500994874 /* version */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = version; path = ../src/version; sourceTree = ""; }; 8377DCFF19F2A5A500994874 /* version_number.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = version_number.h; path = ../src/version_number.h; sourceTree = ""; }; 8377DD0019F2A5A500994874 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = version.h; path = ../src/version.h; sourceTree = ""; }; 8377DD0119F2A5A500994874 /* version.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = version.in; path = ../src/version.in; sourceTree = ""; }; 8377DD0319F2A5A500994874 /* pattern.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pattern.c; sourceTree = ""; }; 8377DD0419F2A5A500994874 /* pattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pattern.h; sourceTree = ""; }; 8377DD0519F2A5A500994874 /* sequence.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sequence.c; sourceTree = ""; }; 8377DD0619F2A5A500994874 /* sequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sequence.h; sourceTree = ""; }; 8377DD0719F2A5A500994874 /* timer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = timer.c; sourceTree = ""; }; 8377DD0819F2A5A500994874 /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = ""; }; 8377DD0919F2A5A500994874 /* visu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = visu.c; sourceTree = ""; }; 8377DD0A19F2A5A500994874 /* visu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = visu.h; sourceTree = ""; }; 8377DD0B19F2A5A500994874 /* wavetableview.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wavetableview.c; sourceTree = ""; }; 8377DD0C19F2A5A500994874 /* wavetableview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wavetableview.h; sourceTree = ""; }; 8377DD1719F2A5A500994874 /* view.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = view.c; path = ../src/view.c; sourceTree = ""; }; 8377DD1819F2A5A500994874 /* view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = view.h; path = ../src/view.h; sourceTree = ""; }; 8377DD1919F2A5A500994874 /* wave_action.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wave_action.c; path = ../src/wave_action.c; sourceTree = ""; }; 8377DD1A19F2A5A500994874 /* wave_action.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wave_action.h; path = ../src/wave_action.h; sourceTree = ""; }; 8377DD1B19F2A5A500994874 /* wave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wave.c; path = ../src/wave.c; sourceTree = ""; }; 8377DD1C19F2A5A500994874 /* wave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wave.h; path = ../src/wave.h; sourceTree = ""; }; 8377DD1D19F2A5A500994874 /* wavegen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wavegen.c; path = ../src/wavegen.c; sourceTree = ""; }; 8377DD1E19F2A5A500994874 /* wavegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wavegen.h; path = ../src/wavegen.h; sourceTree = ""; }; 8377DD9419F2A5D800994874 /* ksnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ksnd.c; sourceTree = ""; }; 8377DD9619F2A5D800994874 /* ksnd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ksnd.h; sourceTree = ""; }; 8377DD9D19F2A5D800994874 /* cyd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cyd.c; sourceTree = ""; }; 8377DD9E19F2A5D800994874 /* cyd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cyd.h; sourceTree = ""; }; 8377DD9F19F2A5D800994874 /* cydadsr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydadsr.h; sourceTree = ""; }; 8377DDA019F2A5D800994874 /* cydchr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydchr.c; sourceTree = ""; }; 8377DDA119F2A5D800994874 /* cydchr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydchr.h; sourceTree = ""; }; 8377DDA219F2A5D800994874 /* cydcrush.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydcrush.c; sourceTree = ""; }; 8377DDA319F2A5D800994874 /* cydcrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydcrush.h; sourceTree = ""; }; 8377DDA419F2A5D800994874 /* cyddefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cyddefs.h; sourceTree = ""; }; 8377DDA519F2A5D800994874 /* cydentry.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydentry.c; sourceTree = ""; }; 8377DDA619F2A5D800994874 /* cydentry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydentry.h; sourceTree = ""; }; 8377DDA719F2A5D800994874 /* cydflt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydflt.c; sourceTree = ""; }; 8377DDA819F2A5D800994874 /* cydflt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydflt.h; sourceTree = ""; }; 8377DDA919F2A5D800994874 /* cydfm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydfm.c; sourceTree = ""; }; 8377DDAA19F2A5D800994874 /* cydfm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydfm.h; sourceTree = ""; }; 8377DDAB19F2A5D800994874 /* cydfx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydfx.c; sourceTree = ""; }; 8377DDAC19F2A5D800994874 /* cydfx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydfx.h; sourceTree = ""; }; 8377DDAD19F2A5D800994874 /* cydosc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydosc.c; sourceTree = ""; }; 8377DDAE19F2A5D800994874 /* cydosc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydosc.h; sourceTree = ""; }; 8377DDAF19F2A5D800994874 /* cydrvb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydrvb.c; sourceTree = ""; }; 8377DDB019F2A5D800994874 /* cydrvb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydrvb.h; sourceTree = ""; }; 8377DDB119F2A5D800994874 /* cydtypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydtypes.h; sourceTree = ""; }; 8377DDB219F2A5D800994874 /* cydwave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cydwave.c; sourceTree = ""; }; 8377DDB319F2A5D800994874 /* cydwave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cydwave.h; sourceTree = ""; }; 8377DDB419F2A5D800994874 /* freqs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = freqs.c; sourceTree = ""; }; 8377DDB519F2A5D800994874 /* freqs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = freqs.h; sourceTree = ""; }; 8377DDB619F2A5D800994874 /* music.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = music.c; sourceTree = ""; }; 8377DDB719F2A5D800994874 /* music.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = music.h; sourceTree = ""; }; 8377DDB819F2A5D800994874 /* pack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pack.c; sourceTree = ""; }; 8377DDB919F2A5D800994874 /* pack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pack.h; sourceTree = ""; }; 8377DDDC19F2A5D800994874 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = version.h; path = ../../klystron/src/version.h; sourceTree = ""; }; 8377DE2019F2A6A200994874 /* background.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = background.c; sourceTree = ""; }; 8377DE2119F2A6A200994874 /* background.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = background.h; sourceTree = ""; }; 8377DE2219F2A6A200994874 /* bgcell.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bgcell.c; sourceTree = ""; }; 8377DE2319F2A6A200994874 /* bgcell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bgcell.h; sourceTree = ""; }; 8377DE2419F2A6A200994874 /* font.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = font.c; sourceTree = ""; }; 8377DE2519F2A6A200994874 /* font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font.h; sourceTree = ""; }; 8377DE2619F2A6A200994874 /* gfx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gfx.c; sourceTree = ""; }; 8377DE2719F2A6A200994874 /* gfx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gfx.h; sourceTree = ""; }; 8377DE2819F2A6A200994874 /* gfxsurf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gfxsurf.h; sourceTree = ""; }; 8377DE2919F2A6A200994874 /* levelbase.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = levelbase.c; sourceTree = ""; }; 8377DE2A19F2A6A200994874 /* levelbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = levelbase.h; sourceTree = ""; }; 8377DE2B19F2A6A200994874 /* objhdr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = objhdr.c; sourceTree = ""; }; 8377DE2C19F2A6A200994874 /* objhdr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objhdr.h; sourceTree = ""; }; 8377DE2D19F2A6A200994874 /* tiledescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tiledescriptor.h; sourceTree = ""; }; 8377DE3D19F2A6A200994874 /* bevdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bevdefs.h; sourceTree = ""; }; 8377DE3E19F2A6A200994874 /* bevel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bevel.c; sourceTree = ""; }; 8377DE3F19F2A6A200994874 /* bevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bevel.h; sourceTree = ""; }; 8377DE4019F2A6A200994874 /* dialog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dialog.c; sourceTree = ""; }; 8377DE4119F2A6A200994874 /* dialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dialog.h; sourceTree = ""; }; 8377DE4219F2A6A200994874 /* filebox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filebox.c; sourceTree = ""; }; 8377DE4319F2A6A200994874 /* filebox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filebox.h; sourceTree = ""; }; 8377DE4419F2A6A200994874 /* menu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = menu.c; sourceTree = ""; }; 8377DE4519F2A6A200994874 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = ""; }; 8377DE4619F2A6A200994874 /* mouse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mouse.c; sourceTree = ""; }; 8377DE4719F2A6A200994874 /* mouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mouse.h; sourceTree = ""; }; 8377DE4819F2A6A200994874 /* msgbox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = msgbox.c; sourceTree = ""; }; 8377DE4919F2A6A200994874 /* msgbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = msgbox.h; sourceTree = ""; }; 8377DE4A19F2A6A200994874 /* shortcuts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = shortcuts.c; sourceTree = ""; }; 8377DE4B19F2A6A200994874 /* shortcuts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shortcuts.h; sourceTree = ""; }; 8377DE4C19F2A6A200994874 /* slider.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = slider.c; sourceTree = ""; }; 8377DE4D19F2A6A200994874 /* slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slider.h; sourceTree = ""; }; 8377DE4E19F2A6A200994874 /* toolutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = toolutil.c; sourceTree = ""; }; 8377DE4F19F2A6A200994874 /* toolutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = toolutil.h; sourceTree = ""; }; 8377DE5019F2A6A200994874 /* view.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = view.c; sourceTree = ""; }; 8377DE5119F2A6A200994874 /* view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = view.h; sourceTree = ""; }; 8377DE8819F2A74D00994874 /* bundle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bundle.c; sourceTree = ""; }; 8377DE8919F2A74D00994874 /* bundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bundle.h; sourceTree = ""; }; 8377DE8A19F2A74D00994874 /* rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rnd.c; sourceTree = ""; }; 8377DE8B19F2A74D00994874 /* rnd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rnd.h; sourceTree = ""; }; 8378C75B19A0EC9300AFBD43 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; 83C75C6712BBF7B20067F040 /* 256x256.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = 256x256.icns; path = ../icon/256x256.icns; sourceTree = SOURCE_ROOT; }; 83D5E10A19F2951F003F2ED5 /* SDL2_image.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2_image.framework; path = /Library/Frameworks/SDL2_image.framework; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Klystrack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Klystrack.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 8377DBDE19F2A19900994874 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 8D11072E0486CEB800E47090 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 83D5E10B19F2951F003F2ED5 /* SDL2_image.framework in Frameworks */, 8378C7CA19A0F17300AFBD43 /* SDL2.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( 002F3A2B09D0888800EBEB88 /* SDLMain.h */, 002F3A2C09D0888800EBEB88 /* SDLMain.m */, ); name = Classes; sourceTree = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 83D5E10A19F2951F003F2ED5 /* SDL2_image.framework */, 8378C75B19A0EC9300AFBD43 /* SDL2.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 8D1107320486CEB800E47090 /* Klystrack.app */, 8377DBE119F2A19900994874 /* make_bundle */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* OSX_Xcode */ = { isa = PBXGroup; children = ( 8377DD4A19F2A5AB00994874 /* Klystron */, 8377DCC619F2A59200994874 /* Klystrack */, 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 8377DBE219F2A19900994874 /* make_bundle */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = OSX_Xcode; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 8343837E19F2C341001EDF56 /* res */, 83722F0F167AAA8F00336AFC /* key */, 83C75C6712BBF7B20067F040 /* 256x256.icns */, 8D1107310486CEB800E47090 /* Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 8377DBE219F2A19900994874 /* make_bundle */ = { isa = PBXGroup; children = ( 8377DBE819F2A24500994874 /* makebundle.c */, ); path = make_bundle; sourceTree = ""; }; 8377DCC619F2A59200994874 /* Klystrack */ = { isa = PBXGroup; children = ( 690F323E1ED4BB240011FD0E /* memwriter.c */, 690F323F1ED4BB240011FD0E /* memwriter.h */, 690F32401ED4BB240011FD0E /* songstats.h */, 690F32411ED4BB240011FD0E /* stats.c */, 690F32421ED4BB240011FD0E /* stats.h */, 690F32431ED4BB240011FD0E /* wavewriter.c */, 690F32441ED4BB240011FD0E /* wavewriter.h */, 690F32451ED4BB240011FD0E /* zap.c */, 690F32461ED4BB240011FD0E /* zap.h */, 690F32381ED4BB0A0011FD0E /* hubbard.c */, 690F32391ED4BB0A0011FD0E /* hubbard.h */, 690F323A1ED4BB0A0011FD0E /* hubdialog.c */, 690F323B1ED4BB0A0011FD0E /* hubdialog.h */, 8377DCC719F2A5A500994874 /* action.c */, 8377DCC819F2A5A500994874 /* action.h */, 8377DCC919F2A5A500994874 /* clipboard.c */, 8377DCCA19F2A5A500994874 /* clipboard.h */, 8377DCCB19F2A5A500994874 /* command.c */, 8377DCCC19F2A5A500994874 /* command.h */, 8377DCCD19F2A5A500994874 /* config.c */, 8377DCCE19F2A5A500994874 /* config.h */, 8377DCCF19F2A5A500994874 /* console.c */, 8377DCD019F2A5A500994874 /* console.h */, 8377DCD119F2A5A500994874 /* copypaste.c */, 8377DCD219F2A5A500994874 /* copypaste.h */, 8377DCD319F2A5A500994874 /* diskop.c */, 8377DCD419F2A5A500994874 /* diskop.h */, 8377DCD519F2A5A500994874 /* edit.c */, 8377DCD619F2A5A500994874 /* edit.h */, 8377DCD719F2A5A500994874 /* event.c */, 8377DCD819F2A5A500994874 /* event.h */, 8377DCD919F2A5A500994874 /* export.c */, 8377DCDA19F2A5A500994874 /* export.h */, 8377DCDB19F2A5A500994874 /* help.c */, 8377DCDC19F2A5A500994874 /* help.h */, 8377DCDD19F2A5A500994874 /* import */, 8377DCE819F2A5A500994874 /* key.c */, 8377DCE919F2A5A500994874 /* key.h */, 8377DCEA19F2A5A500994874 /* keytab.c */, 8377DCEB19F2A5A500994874 /* keytab.h */, 8377DCEC19F2A5A500994874 /* main.c */, 8377DCED19F2A5A500994874 /* menudefs.c */, 8377DCEE19F2A5A500994874 /* midi.c */, 8377DCEF19F2A5A500994874 /* midi.h */, 8377DCF019F2A5A500994874 /* mused.c */, 8377DCF119F2A5A500994874 /* mused.h */, 8377DCF219F2A5A500994874 /* mybevdefs.h */, 8377DCF319F2A5A500994874 /* mymsg.h */, 8377DCF419F2A5A500994874 /* nostalgy.c */, 8377DCF519F2A5A500994874 /* nostalgy.h */, 8377DCF619F2A5A500994874 /* optimize.c */, 8377DCF719F2A5A500994874 /* optimize.h */, 8377DCF819F2A5A500994874 /* shortcutdefs.c */, 8377DCF919F2A5A500994874 /* shortcutdefs.h */, 8377DCFA19F2A5A500994874 /* theme.c */, 8377DCFB19F2A5A500994874 /* theme.h */, 8377DCFC19F2A5A500994874 /* undo.c */, 8377DCFD19F2A5A500994874 /* undo.h */, 8377DCFE19F2A5A500994874 /* version */, 8377DCFF19F2A5A500994874 /* version_number.h */, 8377DD0019F2A5A500994874 /* version.h */, 8377DD0119F2A5A500994874 /* version.in */, 8377DD0219F2A5A500994874 /* view */, 8377DD1719F2A5A500994874 /* view.c */, 8377DD1819F2A5A500994874 /* view.h */, 8377DD1919F2A5A500994874 /* wave_action.c */, 8377DD1A19F2A5A500994874 /* wave_action.h */, 8377DD1B19F2A5A500994874 /* wave.c */, 8377DD1C19F2A5A500994874 /* wave.h */, 8377DD1D19F2A5A500994874 /* wavegen.c */, 8377DD1E19F2A5A500994874 /* wavegen.h */, ); name = Klystrack; sourceTree = ""; }; 8377DCDD19F2A5A500994874 /* import */ = { isa = PBXGroup; children = ( 8377DCDE19F2A5A500994874 /* ahx.c */, 8377DCDF19F2A5A500994874 /* ahx.h */, 8377DCE019F2A5A500994874 /* import.c */, 8377DCE119F2A5A500994874 /* import.h */, 8377DCE219F2A5A500994874 /* mod.c */, 8377DCE319F2A5A500994874 /* mod.h */, 8377DCE419F2A5A500994874 /* org.c */, 8377DCE519F2A5A500994874 /* org.h */, 8377DCE619F2A5A500994874 /* xm.c */, 8377DCE719F2A5A500994874 /* xm.h */, ); name = import; path = ../src/import; sourceTree = ""; }; 8377DD0219F2A5A500994874 /* view */ = { isa = PBXGroup; children = ( 8377DD0319F2A5A500994874 /* pattern.c */, 8377DD0419F2A5A500994874 /* pattern.h */, 8377DD0519F2A5A500994874 /* sequence.c */, 8377DD0619F2A5A500994874 /* sequence.h */, 8377DD0719F2A5A500994874 /* timer.c */, 8377DD0819F2A5A500994874 /* timer.h */, 8377DD0919F2A5A500994874 /* visu.c */, 8377DD0A19F2A5A500994874 /* visu.h */, 8377DD0B19F2A5A500994874 /* wavetableview.c */, 8377DD0C19F2A5A500994874 /* wavetableview.h */, ); name = view; path = ../src/view; sourceTree = ""; }; 8377DD4A19F2A5AB00994874 /* Klystron */ = { isa = PBXGroup; children = ( 8377DE8719F2A74D00994874 /* util */, 8377DE1F19F2A6A200994874 /* gfx */, 8377DE3C19F2A6A200994874 /* gui */, 8377DD9319F2A5D800994874 /* lib */, 8377DD9C19F2A5D800994874 /* snd */, 8377DDDC19F2A5D800994874 /* version.h */, ); name = Klystron; sourceTree = ""; }; 8377DD9319F2A5D800994874 /* lib */ = { isa = PBXGroup; children = ( 8377DD9419F2A5D800994874 /* ksnd.c */, 8377DD9619F2A5D800994874 /* ksnd.h */, ); name = lib; path = ../../klystron/src/lib; sourceTree = ""; }; 8377DD9C19F2A5D800994874 /* snd */ = { isa = PBXGroup; children = ( 8377DD9D19F2A5D800994874 /* cyd.c */, 8377DD9E19F2A5D800994874 /* cyd.h */, 8377DD9F19F2A5D800994874 /* cydadsr.h */, 8377DDA019F2A5D800994874 /* cydchr.c */, 8377DDA119F2A5D800994874 /* cydchr.h */, 8377DDA219F2A5D800994874 /* cydcrush.c */, 8377DDA319F2A5D800994874 /* cydcrush.h */, 8377DDA419F2A5D800994874 /* cyddefs.h */, 8377DDA519F2A5D800994874 /* cydentry.c */, 8377DDA619F2A5D800994874 /* cydentry.h */, 8377DDA719F2A5D800994874 /* cydflt.c */, 8377DDA819F2A5D800994874 /* cydflt.h */, 8377DDA919F2A5D800994874 /* cydfm.c */, 8377DDAA19F2A5D800994874 /* cydfm.h */, 8377DDAB19F2A5D800994874 /* cydfx.c */, 8377DDAC19F2A5D800994874 /* cydfx.h */, 8377DDAD19F2A5D800994874 /* cydosc.c */, 8377DDAE19F2A5D800994874 /* cydosc.h */, 8377DDAF19F2A5D800994874 /* cydrvb.c */, 8377DDB019F2A5D800994874 /* cydrvb.h */, 8377DDB119F2A5D800994874 /* cydtypes.h */, 8377DDB219F2A5D800994874 /* cydwave.c */, 8377DDB319F2A5D800994874 /* cydwave.h */, 8377DDB419F2A5D800994874 /* freqs.c */, 8377DDB519F2A5D800994874 /* freqs.h */, 8377DDB619F2A5D800994874 /* music.c */, 8377DDB719F2A5D800994874 /* music.h */, 8377DDB819F2A5D800994874 /* pack.c */, 8377DDB919F2A5D800994874 /* pack.h */, ); name = snd; path = ../../klystron/src/snd; sourceTree = ""; }; 8377DE1F19F2A6A200994874 /* gfx */ = { isa = PBXGroup; children = ( 8377DE2019F2A6A200994874 /* background.c */, 8377DE2119F2A6A200994874 /* background.h */, 8377DE2219F2A6A200994874 /* bgcell.c */, 8377DE2319F2A6A200994874 /* bgcell.h */, 8377DE2419F2A6A200994874 /* font.c */, 8377DE2519F2A6A200994874 /* font.h */, 8377DE2619F2A6A200994874 /* gfx.c */, 8377DE2719F2A6A200994874 /* gfx.h */, 8377DE2819F2A6A200994874 /* gfxsurf.h */, 8377DE2919F2A6A200994874 /* levelbase.c */, 8377DE2A19F2A6A200994874 /* levelbase.h */, 8377DE2B19F2A6A200994874 /* objhdr.c */, 8377DE2C19F2A6A200994874 /* objhdr.h */, 8377DE2D19F2A6A200994874 /* tiledescriptor.h */, ); name = gfx; path = ../../klystron/src/gfx; sourceTree = ""; }; 8377DE3C19F2A6A200994874 /* gui */ = { isa = PBXGroup; children = ( 8377DE3D19F2A6A200994874 /* bevdefs.h */, 8377DE3E19F2A6A200994874 /* bevel.c */, 8377DE3F19F2A6A200994874 /* bevel.h */, 8377DE4019F2A6A200994874 /* dialog.c */, 8377DE4119F2A6A200994874 /* dialog.h */, 8377DE4219F2A6A200994874 /* filebox.c */, 8377DE4319F2A6A200994874 /* filebox.h */, 8377DE4419F2A6A200994874 /* menu.c */, 8377DE4519F2A6A200994874 /* menu.h */, 8377DE4619F2A6A200994874 /* mouse.c */, 8377DE4719F2A6A200994874 /* mouse.h */, 8377DE4819F2A6A200994874 /* msgbox.c */, 8377DE4919F2A6A200994874 /* msgbox.h */, 8377DE4A19F2A6A200994874 /* shortcuts.c */, 8377DE4B19F2A6A200994874 /* shortcuts.h */, 8377DE4C19F2A6A200994874 /* slider.c */, 8377DE4D19F2A6A200994874 /* slider.h */, 8377DE4E19F2A6A200994874 /* toolutil.c */, 8377DE4F19F2A6A200994874 /* toolutil.h */, 8377DE5019F2A6A200994874 /* view.c */, 8377DE5119F2A6A200994874 /* view.h */, ); name = gui; path = ../../klystron/src/gui; sourceTree = ""; }; 8377DE8719F2A74D00994874 /* util */ = { isa = PBXGroup; children = ( 8377DE8819F2A74D00994874 /* bundle.c */, 8377DE8919F2A74D00994874 /* bundle.h */, 8377DE8A19F2A74D00994874 /* rnd.c */, 8377DE8B19F2A74D00994874 /* rnd.h */, ); name = util; path = ../../klystron/src/util; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 8377DBE019F2A19900994874 /* make_bundle */ = { isa = PBXNativeTarget; buildConfigurationList = 8377DBE519F2A19900994874 /* Build configuration list for PBXNativeTarget "make_bundle" */; buildPhases = ( 8377DBDD19F2A19900994874 /* Sources */, 8377DBDE19F2A19900994874 /* Frameworks */, 8377DBDF19F2A19900994874 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = make_bundle; productName = make_bundle; productReference = 8377DBE119F2A19900994874 /* make_bundle */; productType = "com.apple.product-type.tool"; }; 8D1107260486CEB800E47090 /* Klystrack */ = { isa = PBXNativeTarget; buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Klystrack" */; buildPhases = ( 83EBEA2A12BC0D3E00263A0E /* Version files */, 8343837D19F2B440001EDF56 /* Bundle theme resources */, 8D1107290486CEB800E47090 /* Resources */, 8D11072C0486CEB800E47090 /* Sources */, 8D11072E0486CEB800E47090 /* Frameworks */, 002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */, 8378C7E119A0F46A00AFBD43 /* Fix frameworks */, ); buildRules = ( ); dependencies = ( 8343837C19F2B411001EDF56 /* PBXTargetDependency */, ); name = Klystrack; productInstallPath = "$(HOME)/Applications"; productName = OSX_Xcode; productReference = 8D1107320486CEB800E47090 /* Klystrack.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0600; ORGANIZATIONNAME = "Zorin Heavy Industries"; TargetAttributes = { 8377DBE019F2A19900994874 = { CreatedOnToolsVersion = 6.0.1; }; }; }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "OSX_Xcode" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* OSX_Xcode */; projectDirPath = ""; projectRoots = ( "", .., ); targets = ( 8D1107260486CEB800E47090 /* Klystrack */, 8377DBE019F2A19900994874 /* make_bundle */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D1107290486CEB800E47090 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 8377DD3A19F2A5A500994874 /* version in Resources */, 83C75C6812BBF7B20067F040 /* 256x256.icns in Resources */, 8343837F19F2C341001EDF56 /* res in Resources */, 8377DD3B19F2A5A500994874 /* version.in in Resources */, 83722F13167AAA8F00336AFC /* key in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 8343837D19F2B440001EDF56 /* Bundle theme resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/../themes/AHX", "$(SRCROOT)/../themes/Blacklyst", "$(SRCROOT)/../themes/C64", "$(SRCROOT)/../themes/Classic", "$(SRCROOT)/../themes/Default", "$(SRCROOT)/../themes/Gameboy", "$(SRCROOT)/../themes/Golden_Brown", ); name = "Bundle theme resources"; outputPaths = ( "$(DERIVED_FILE_DIR)/res/AHX", "$(DERIVED_FILE_DIR)/res/Blacklyst", "$(DERIVED_FILE_DIR)/res/C64", "$(DERIVED_FILE_DIR)/res/Classic", "$(DERIVED_FILE_DIR)/res/Default", "$(DERIVED_FILE_DIR)/res/Gameboy", "$(DERIVED_FILE_DIR)/res/Golden_Brown", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "THEMES=\"AHX Blacklyst C64 Classic Default Gameboy Golden_Brown\"\nTHEMEDIR=$SRCROOT/../themes\nMAKEBUNDLE=$BUILT_PRODUCTS_DIR/make_bundle\n\nfunction cpie {\n if [ -f $1 ]; then\n cp -f $1 $2\n fi\n}\n\nfor theme in $THEMES; do\necho \"Building theme $theme...\"\nmkdir -p res\nmkdir -p themetemp\ncpie $THEMEDIR/$theme/colors.txt themetemp\ncpie $THEMEDIR/$theme/bevel.* themetemp\ncpie $THEMEDIR/$theme/vu.* themetemp\ncpie $THEMEDIR/$theme/analyzor.* themetemp\ncpie $THEMEDIR/$theme/logo.* themetemp\ncpie $THEMEDIR/$theme/catometer.* themetemp\nif test -d $THEMEDIR/$theme/font; then $MAKEBUNDLE themetemp/8x8.fnt $THEMEDIR/$theme/font ; fi\nif test -d $THEMEDIR/$theme/font7x6; then $MAKEBUNDLE themetemp/7x6.fnt $THEMEDIR/$theme/font7x6 ; fi\nif test -d $THEMEDIR/$theme/tiny; then $MAKEBUNDLE themetemp/4x6.fnt $THEMEDIR/$theme/tiny ; fi\n$MAKEBUNDLE res/$theme themetemp\nrm -rf themetemp\ndone"; }; 8378C7E119A0F46A00AFBD43 /* Fix frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Fix frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "function relocateLibraryInCurrentApp() {\n install_name_tool -change $1$2 @executable_path/../Frameworks/$2 $CONFIGURATION_BUILD_DIR/$EXECUTABLE_PATH\n}\nrelocateLibraryInCurrentApp @rpath/ SDL2_image.framework/Versions/A/SDL2_image\nrelocateLibraryInCurrentApp @rpath/ SDL2.framework/Versions/A/SDL2"; }; 83EBEA2A12BC0D3E00263A0E /* Version files */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/../src/version", ); name = "Version files"; outputPaths = ( "$(DERIVED_FILE_DIR)/../src/version_number.h", "$(DERIVED_FILE_DIR)/../src/version.h", "$(DERIVED_FILE_DIR)/../../klystron/src/version.h", "$(DERIVED_FILE_DIR)/myfile", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "cat > ../src/version_number.h < ../src/version.h < ../../klystron/src/version.h < Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #ifndef _SDLMain_h_ #define _SDLMain_h_ #import @interface SDLMain : NSObject @end #endif /* _SDLMain_h_ */ klystrack-0.20171212/klystrack/OSX_Xcode/Info.plist0000644000000000000000000000202313214501362020362 0ustar rootroot CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile 256x256 CFBundleIdentifier com.yourcompany.Klystrack CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 1.0 NSMainNibFile SDLMain NSPrincipalClass NSApplication LSMinimumSystemVersionByArchitecture x86_64 10.6.0 i386 10.4.0 ppc 10.4.0 klystrack-0.20171212/klystrack/doc/0000755000000000000000000000000013214501362015367 5ustar rootrootklystrack-0.20171212/klystrack/doc/KlystrackGCLogo.png0000644000000000000000000002614113214501362021103 0ustar rootrootPNG  IHDR`GfӅ 7iCCPPhotoshop ICC profilexwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~gAMA|Q cHRMz%u._:oi+!IDATxb? Fp0& FS( FS( FS( FS( FS( FS( FS( FS( FS( FS( FS( FS( ^xqܹ={Ç߼yׯ. FS( iz )))AAAWx߿ڙ@ +`JݻwoƌFFF` """//)SlٲX}h`R60h-P150Me˖%@-'O@ ,rF!p "`а@s͛wĉAR`M (f`"FV`'`nd{`IdHlBZ 1onι>@CO4Hdh{oRrεVjS4Dwl3cxJI)5wG|`Qa(ꠃX\(@pH ,}N]EyI\D6=Zc{v0R*' ֩@Ijq%jG;EXHw4jRR.D7@?7لl!~.c@9XX䇝P_(@EI-r7>A-  ̮+!d{}hsDa턐Q"p;JR]5vL91^[ka.R.^1u売p|[b/70\93kK%+&Q^okL*̲9 d.+V|4gCq-ʋ0^Qs[ctmH[{ObT)Q*Maʀ1CCY[2nJtڥYJ]qWkQxgCB?~( 0 @QtD'pp@PŋJi4$+aUbHa h]GKs!bM]ͥK.u7C#ʚY-t6ŢPp$XMJÍDqА-!`ںAMNq鹵&ʜk#YǾˬEeB~{Ka0S[E7f? !d2ݯl $wyWi%q| ӐzDAbe#c"R cik_pN[Lfd'@)^) hK9-MQ|!Y bX1=aa䘒c{CngACm)hRWYa5 خ_)r fmV~|8$QYŃ'ͱ?Zk-T\x2zD—L??s69Gz; l]`W5ͼE!sQ414_iK#\ΠZbw{$AED殄^we[50=Elj70 YNDD-შxAAj7M{Fԥ.vz Ζeӯ:q<}Uwz%҂ZH uڈQ ͦWNp 3Ik2 T{OV$T.|݌l18$c5Ma赼!VR1E׏t?;Rb*'ٴ&SG}/ (?L:Gɶ%xW>5DAf5 ѩ=h|@#%oo1><4h_̓uT=jD:js}ǯKV @?y/,`^-$5~%$5 82V+P}*a81a(Uԑ09Oôί79~q{LLr@۲pRCKQ;MVG;#rRpv-f .G7!u@/ƺuml`+UiJH@1gAz )jla`kا#'Zl!&͐[j9󺚤:[Zw5E:HqxX(dG S";RjήlU3ZW%4gĨ _zE>)Y`SY/$Lg6 輥,1h]ս]BJEìc$F:LGq{vO~GEc1->E>($FQ"v4s9 U҂`Vm-@0$aēsIH1U̖ܥ8Ld_G L*sl|9'jIv,Ƚ7KF=0dWGׂ2 aU$JO`Wp!Gv @1tp!_/g#hkM <9hw)|a6*,nop/47 |u99qwWNk)cDr9K{悠3׎8?niuX,`w%r@CJ o}d H""""m֭c~9(;;$[+C [yfU&\;iyImxQ1Yɺdқpx n;[Vt@ߓo =8GR`c ^"A%$yMS͒ =wf&['ݐ $[uힵ:*bg%9ar>>#Qe,Y+fx@Ba%\= 0 ŗ>_dJTwX[&$U-8~K6<>`2Բ^8l' kJ1&{;Ll na;~PvgCENvJvZH0P=afxe Q*dq0"¨YD ,&>Ī4܆yxy2OʆW HA+ufDNX>% Ii̔5M#CKų K`PQQL JxvFU,O1cى SQ$0+rcm Y1ro2Y%MLk$׏fE𔍖1*CKܘ(ۀ5L6ı"4Oz8)bgggl~MOO6N0$X @q`6ſt ? jlKjƥ1+h"S6JT Bbl+\ F\)m9A0S5r&U&!&ecql̨6CCCŀme`_>HE@IKK3%+)WɊX^p٘uBȔVgS6D2)LbR6aNb,nTf:ܒƕ12' 1kldK`Xׁ"kGK@A`ؘ D۔S6l`HXπk9"r?Ȕ U1Y?ƨf)5qjlxڅցЈ2m+Tb4 TfkkK#< Ӵ&&e[^zIȅ o`MHD=Q`ʞ.Lgȩ#XKeH`/؊,nq"^̔ /S1N#!&L lč"4ITuKS `ggg9`"alxҷ@m@ȔmmY"1` @l`c$65) o¦Z q>"CF^Ā4' ۂTA̾ Mg,,m6"lxZ z_II*L8r1E5fFxl<ѢLUS2 BKِN\l`E^^X4=...VfM%CVBb~@KЯdWUfc:k?cP&)iӃjt>A% w"!vTdU={$iG68b+RgAK$$iy럪[Qav 5rmP3^82 5qF UB0e@뜜h}k5@Q-eCVk~FSXD$DmBMLs=l0 xR6|%?@?#h~@)))J !Kb54ؙIYYYKl zUSfID{! H\b?b̼S3'ZZ|$6ǀq"#',`! Q`-`|B(,؀I 8QD`%`(,,Tƅ\`JtIhh( ===N0$4 IMu% <#ܛ-[pׯ1cց&zuttZ/=CkI]z) kg0CQQ&-2223rԳ*+VQ C16&q=M@iV'儤}ˢ0f3y1 Kݱ/ c8,8Dk<@{i0*0!u1)zR1B2iȹjrx&w#!y[ JsŶ]+` U0yx=>wv7 0@NՅ:W1p/*RBX1?  WdSs힓%`6)t{a",te䠜5Z6he"BNEnB5z/(LB OlLt71/?9b ;+l8%T>C6ώ(Yvh A S" /FƐzBMd $BnAUBxK!5ZsQK1%CpZ+)~M)\=̄!Zʐʿ814-,ΉQ :0m1<'6f󄔧4 @ @KGJW|)#yi$2J1sw gAVKU:FPi 8XvQO>kTE.ݴlT$ Z (w:iFFCX_}N@J-9w@P{t> (XiSMgW7Ws&HfDb+ GiWv_k(*C:ǔ}`7.l,&V eqv@cNƁ;! wSUr^+{Zke:+!fϓ-s.rdm[dWFQt4nu4NǺzӸ}xA=L:!Hyo|GXo 0=?WI@8AMSd#m|-A+ N J3]¯2D(48*ٍ <V=!OEfh`7mZ>i": X-q'tpI(F+0CxHXZ'&)7`6- i5vu;`LtMR 0[KŁ4d/((X;sm u@J {llKh`3 ց= `ǜ h`?!h9= h )F1F@)eQ@g@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O@){ O`N;S R+IENDB`klystrack-0.20171212/klystrack/doc/inst_editor.png0000644000000000000000000005525113214501362020430 0ustar rootrootPNG  IHDRKgAMA a pHYsodZKIDATx^1%9ҝk!n˜m?θcLA_S޸2f)chQ6zdhxD)*N0L&\||Or=йT`L{-b Ǻk ̳쯀 `~Yw#.Wk<Ճ95BˬqϖF{\ ¬p#YpH~{=X"KXdԩn8kVM$eK{0[e}|-/7&W{m#K{RGgqi6,6NJ XҝC3&P`+ ^4"qlASY=2S*3¬DLkt($[FO ˅N$<ً_ߞg׬}H x xnvC JkX<x(/ec3`X\+:!埤e b&,Xi Q$+Ϻͳk8ȳ]'F+bWy-3 f}ԡ-s4l ]IxoQރ8: t6W׀-T4^9:_`;:sVJ]6ή Gl3=3` {ƒ7A]B k7eg (@{7WPC?,/oLūޯq~s׀n]Jȼyp%= ȴd<df,Z+8"+6'С獛4> `xO VW)@|K/׮]՗k˱앿ۓ * *< `;[M}sz4W }# xcwd_ t6F P,//p|  ^u֖+9\cQÛp뾱}*ј a.~tev6< k!)5<^8Vfh 8^3]ÈֹqYjeYv8kcY<]c hg }edcZ7vݚW#@XQK{S6x."aɀVQO˽bZ?c3R]JqOCn6|wG*͇_!0ZqsȰ$T Ah9~+;*{iUp;`{OO²gA2xޛў2vq09b V `|/_>q3`xVC2`8ocC=axur"+yw(z4J#9(q޽ܥx!j|[v>T`7H.P\YOxku0`iho?lVƒ+8@FBT x]U>򍞹Lʵ%ϳ l P?ZRkdӐ9"BTQx 7$~P|mH٩/Y4 <5B0*Ш xDS %Shu| O j;wuTAwQhf!(W@V[,|`fU`{dj)B5f Mߪ>Ϩ1Xmy$;+g]`yU,hfQ ?#|۠LV;;<9F8*Ц+">*u6@/} kK&7+[Kă­sGn*, PH `HېMux `(ш lemϮ S J䕼[8ק_5`"ˀukQB7 @npꟾ|(^&;oG0V(y0P ,ˀ5 +S kr *x3{yO0Brzהߎ3`x0ׇ[oIBE+;Jxtz};c4nr&l+48>`C3bSʀ JHX>g'3X`q>`d,ln\JM;5/0ElA<TT;v |;·:R `p W hpVܕB0O`bM *@xQc@, &``ͯRSФ/8J`RX}1IɭNl8,hO\ڧwʕ:ЃK , )쳠uPQj/>tyYEl%-RC{vO50rX28CESX0(e_MV*~j뭡Vǖ򫝕H}pTSw%Ii+Em';eqV|e^uxWm]d6#Z0- {+ |-ALAW*l1C8cggv ɺ)h ɀ箭f}+gzfZ3`|ͦ `$, `OIXO@gM"K}$w geYo9YF.J=]^iwY@k,mX4=+|0 ^(đp_VjN#&:'m@;խv(@vW&r:7U!S*>/011ݮ:XShUaTUAT@h~fdU  T. yUac t}zR}4LR'&T Vr 16Q} z x8#0oC"l@V)hoS}iLW X(QT`X7Mz6oc\nu6X*9#eMep:gV^W}+\#TO| ګӗ}_&WfJVEKL*lu+v(@vWf$U@{*(`,d?nT}^2=Xpe pҞ \@;W P.hs*@g+U[f T T>;du')@B$Qc@}/|RXd[,Wz`LS- ׄN  Ǥ_l 8~phB\, 08JtC@|w8f|P:S QSE (H* XT[ u.3JTSp셖;]AS*>6MT`|S(+@` 4ׇ3 Kx ڶcQdzHc {` *8JO|l;Ad>! Z~HfRM w@ ~V2e^U~sH Aӡ?% Ԭ}+ +@|Rh[F?g|8Fj%.~?fwN.u~G6<%#~>`x`]\QXxʚPXEs/0yٕ|Җe_pKhc_[4uu.|o[mXmo3`{}̀(﮻>U%[7GQ*Y@yܭ~"Y{p"+w,meŨ@mXl}YG<ƾL5k_πOz^U%P*p$VEڕ,8pOW;Ke=@Emz &2lrW9Jx:-.hܾOz28oArn`iT Qny 4LY!ȳP5 oϴ`WCq{XoB;{Ys5ngvl޳Vz1uG9U]BCyxfy X. "0AH0B3XGs:-/c^wl;0"^7t鰬G* +L7f]z6[L㽝Ƶe=Ruk+ovWU2Op7t:y֖ώ[K'caKdYh==E~!qJ,ST`Sp^a(u Mok<`ܧ` W,EX+0@ n6sS+j+YWX)Gl6kn%xӵ/vv6eY>"zY!qa#[2`ĆZxo,ǶcXG!4}zu7f#v[:^\gxo\>Ƽ7W ]Z6cPeH;2`y 5\_3`/ۖ;Λψ-^fe ;߮ڄ{?k{NRj^[y^,0L˛gădb l| w1Խrۖ?_xw)d3"#ƃFz9`<뀔`x(V+<Ϻٞomֳq~;beQxHpFJ^ex0l/6c|ehzKobs_zmȰqk#V]c[:iҨj)hxv{Nl{6$Y,i*ݽLdFԊ9\r繓-;+{]_m6Y-bdAzx%qv$YmyiLE5Ve,6΍4(hq2Y^{xnɀ `rMBs۱@ۛa|^pn6o^%+F9n=#26x YW&Vx-qu[w%`}ݝe*w2/7xV<7ٕ>f}^;լYƕp3`kq{Lq$F+@gE{s zXv1x#Yi r7b?;C\{DFvt˗MAv4uA8ϳ!q0o[9̺ʢ7n=w\`n&,ߖMg%j+d1 dƛy̸'T y,hp,c7M0 Dzv\'X X!QGOf] x* LƹZx8 q돬eiy!yӒc 7^?ͳy~-e@gh0 x۟cyƉ·q `&^ן `x;kɏ+0>||?e,{Ə[4L)T}ZȨ;/4my^N_oGF\}쬳wx:^cYpfkL{/OAYV߽҇f_o1swc'tCJcu@6f?ӦYeFPO49k)ܧv>`l]~w)ykhˉ 8ی8ԪCէIy|, }moc^F^Nncͩwzߋ ݇_3![\gVc܆fۖIXsbc^5A|a=ߗ1GG[";2>`<В x !ޗ`aLSMp|wRǞφxbл|֝c/ogH.ڡzgeEMy !w8YȰ)k/0T}؋=6kks)rūv4nm9vgVpyk6g5Wk=.w Mo3 ch,OkV0+OP*DozJN. ބww~zOekmhc*^ 2^)h>=$$T |"z ` Hd j;e?*@p;7^w_rMXNZcm@oPA r7{O\#jtSAS*5x)h|֬2I$p{y,z&s0+౎ΣS` r.oB$O*+oqH xO7X=m({ CGa{`l'ay.h*0odXìRpKX]T Tr'[π7w >. GlJo<cp_ +ykt /sg_융||*Gez־w/yk;{0 PfE} pGǼvO}ĝ>g:g `$(Mv[=YV=6뵬..Bk{B0ޣb-Y{Ox-{lkYA3-}C@M\&~;.ϐ ;rwWb+#O}:X z;X$qݞ0D8/4#?X߸m><݆ױ2NE{c{I ΀+^vy~{au? Fx%d癴q?.xOuÓ;TB< 9y^&{4x@/cdW!{zS+D0s.esDπ;-R:/LEF s ^!=m\[xېE=G쥍g8VqYA `{0\IK{/!0>/4#Wxƨ{Eۍ{9vYّW9fiXdE|mGbmfǓvpʶNey9e|y3Wox>@0{@buȆQ*mg/^(s$ӵy7aWMpiY/[^@&Hc_]yڎ@ Xl20Ȼ钭zϵ0>$+Kq52UO_^e0l ήiXb1D?94#`pժ0~Dd@^3)Eޓ4:pP2C"P_f$0 6e{ŦFK(;]ihx66+s}l;#>zo .a$cȀ Rck(xV*~ϾM?/4{mǓ}f"/,{y>:EYޢ' q5N<{GW"LW%=/4my^&Oot+`"Z` d@aL8~~YT{`ƇYYްu$ ؎Gk^ɺYt(x 8#7?:Y)/}zUgˉ5XTC+;}AFt6}}%}MyC c%kqls2HA;րuc/*ƽ&Q1~T=6 Ԭ}[~O`|"4Ay+ o{_`[쯽 φk+({otOxf=-~/Y>!jVaxCpmCۭ^8b0,é-CGl~AzқGȈXaVy-'~mEeWb{|Wg8<-9Bs!MIv/.YgR+qe$d+}ڌ]?XU<ྋ-Ur"B yٰ*k^C`'d{bO 2:xћ~c񚐇+dgM(eqkZ]fFGXţl'K#$By,zfgMl\ SB=z1n/d[:8_Ǽ&zy0&H#E8 n?W+Q1|{:ܩ+bȽ!H<Ɍo29.aYpv]| _^ YV߽1E0l3$#u1Sn,qkXCNASw0qu %wM[@oV ብQM'jɼ R,q={ςֹo[='ݩ)y~Y^_5{,K 8lwx>6!ߏm4C2\Uq=*=mxgbUz▶E"!,ڐ x:ƒ; Sp)9%ϪwwUPk3x3##̕\H ~oq26e2oV)fzz ۺl?9ɞv߆ *kst=߱-puTP\qpy7w:kvHB!>ŗr,^=-U[]cDVӳkնuIJk sW :׆&o'>0փM03`0/ ?ٻ60qBd=\ `Bk2x8#ãROd;^Wr\$C?g̀|^=<ކ F)p]F$MXnC6${Bo^O.OCצݛ0X^{TNdTnz"! 4RC$Q8{v\, `߿soY`&5*ƪk.6u<'CO^:7^ kBIXjY?Y}'aɯrH_cY*ap#R/^GGV.nB꣏וK!=WC[Bl*X==p!j΀ `[eǽ .d0 8q`yz-,V5jH#=pMH`GCQ6k'4:{ {O܃q+t2;` #nO|*@D6$FDEwq~2 P7mHx [,/Zyz@-獧Wf]cs}i΀qq,O@w2`# L*Lj) +scJ̀qp<7vOT ":>6ΛemV2`WcXƷWJGcW σ]+4 y;-&,},=L7 T $,޾xدzxR$a͹};zGs!6ټ{v̀?xR*pbzGx_=tc[?"@YO*PQ `<#eQ1lƟ+p{)?y4NF*@@ s^MAQ5 <2+gt |X7,<Zb/P*rm5+sُ3Ϊy{2w)<XV ˿,#x>.s_x߾|T`+<4>/|בv Uee@\ʀoGރ89yZ'T t+@Bڽ!C ˧TS`NHď|o_(3bM(!ԯs X0#}k,y0=-vSG#AHmuFEV,~(>"|YO*yk;.\ญ׬}e6F=S_2#z^YYlx͖ևT[emH^`oxA0Fw_OzS/ Re0ˉӼv4nd4o[P}/< XC7lYl}hO(8>{>xKZq 0M; k+BX1#e ؆x G2=22`#kQfУmg=X y$lF+2 c*6kH֞k)B 8^gLu\PW[O0 < K#7{h{k~~)MX}f u OŠo\ႇgo E |g끒%PlWjm3lx-c9B.qHs8ZYX1;Wa=ZL ۏyp,־,^g7vf(`,x,QEO_>ދ$6&gF`}O}=l} xVܭGFzL$i>yɀT}G f>Og &>{YJyl`,^{&߿*gR ypwbT h#wX7:<3>/|_«{ `}*pR|6x^*)?vvgMXF?/_>򁞄ŠI@a5 `5[fn֟T |TήX  H{*pYP*Э +z*bלTY>X, DKV*` Pn*B[dkלT8DpJj֞Fca4qf?jխ@;ǂI9۲R?_e-_j%B~hyɘ}VО P x7ɯo!+s ҨS`Q>JeʯRncxGe[:,x:p mFkk$΀(}5i5Ͽ~o,Տڭ>(OA_}i7G8l"3݀[}-m0XNpKKR!utKYb@H|F#u*Sπ9{mWlxڭ>Ӟ d4g0 c 6s8afs,/@Wrٱc\?^Euikۡku܀΀c50ngqj]"ww}Ƃ)Yn9MB` 3Ύ0  sāQˀm7Z{;"뾺cstx+`3`ܾigdMsK ȹ>kX ! ˳P-OA[8!UR$@WrٱcZy|=8YjYπ=`oԲ]:~MܑkV2T`wcfln`86 t^yX`K߫Wꖶd .GS01{pOڂY΅)a=6ו^@K|磳Pg˹>p!(),{I<_oGy0μМ F `c RUgvmҢڛD,mVjK7\ unO]и=sRo~֎=Wg5 mHYyn], hbL;0Oh}aqH{5=rV `" R`-Ǧ}d3DɃuC[rDf=p\#kր,S+iqIW2`۽|T:KYl}ꃌ@}]С)h"Yܩs#<ԎP֗@,Pc 2-KPqn5|V2bR/[-Nt{IX>΀> `#k2 Tleـ[}iU} loP  `8Lg3`͎[Z ݯ=Pqlg#4H +>$$T |")zd TCv˄V`\mpx̺SAS* }pQ:h0o6T RلeA? { xv*ueG^/|d7ae? eK+j6V>k4h% Ԭ= :\vnI{* x,t:, X@"B~gcLk-ڭ>}-eTVInF/'"SabD{;+@{# *Э@pvMti{Җ3l*u*oٽ2+^hshmgqFkE|+jTc)h|ڍ"d=LSxK8P66,͖ ypEy ϲ{x!iF?V7 ɘ+ +^}U}l f 0AQ6)pgWa)SxZU~r4]fu;k,'vkeɀc0nߗg2 dO{*0m n{,6 y)ncG]fH*7}OJր\߶_)G 8(m d:ŻmX>6f5鶿;Nͦ 5Xe٭U7C@#ȑ:HjSvv7)j: 裐ukqv\;y.h}swA۩f{Q !>9ep'n3ca\yN76$xX7\>/ETWxU2 S_ƀFef_7W,3], OAgESK +t7VDS |/~YHW9Kwf{[[m϶wdO{*U} ze0幨@V lx= 0"?/؈=9uVClP5 p } j֞^4y*0Kv&dlboŠW(q oSx(%^sZRSbt)` GW8?t Q;q/5ja|.ΈMEH*6W= y ^#GotƼ&B\pG}Y{)h EQc l<^`mg)pK9g`}: ,Vݖ[EھC=i˫ކ̀JsvtG|m}ꃌ&r*p)h:x8gA#@SЈ=yq"c叵Gu+pK`er\$JC kb*z%{8m Hy3[gˀcK8{,ʓ:gq뺁-? گQS0!ۊ̆lYl}b<QX}|x X+@{[f-8i60 hC@&g02)LA@5`ܞ , t(pc#Z#:x6pAzgtCezY^ ZcU['a݄ %?3-y̫X< QS'y8x PMW\Q"˸T ^nLc"粎f'u^3. mV1!} jnS1I+v^sZR1MA:pw1PevhQ=x,(*+`*bMPY >!πgeo%ÞUlԢ=S} :[YPDx6 F-S1AP_rK? \H5][洤ڧ 0J{*0I_*pX(QT`Q4 V` :;2r[Yv}A˕ p G)@w݀O&,@;?C]v> .}C$1RYY: OA/<< qg}^Yr;eBT t+@sQ*`h:, PQfRÛ9y  *A_JicwOE,9 OADBs7[zwnA<pQcC5ꓭ?@VNAT(`y6Ҟ W>*-kDKnš>TSXߗ,P.݀[} z " ^>Hir g̾`=m0F+.K לT@4pm|XC* c"~/^/w{>*>rnSOS~L1r1WZ3`9J_Mھ/N#j,듭? `;!4YG"c|fUg(pK{j&%dW[8kl9cmn\NM#GY!a=[nHi^[5xچWƐqTg,n7>u ثnpB"6p6ՓOV`eeT8tjWA6> q=׬2rZkR놫X,]vB?޳ug,>;KgW{D[֟T )h:F%, nl0=*lE/cU^g`Tfp{<sVkWF,g=XA뤣`djxk)B `Ͷ_◅d/ά}%ZܭO^񔵷UTOMXl$` GxWS/dEyC,FOj_[*$둬}w.1gͺ>ZJx^͆}N*G0Ͷ] xP H]vm>I8^'a-cVzPy["G]ƴ8ggSo,d?dp()[A۟ kz/Yfȃ y9׹K>$591jkf5َD2`g{ZC)V{K mH0_cwX+x3 q oh_ ݀[} zLltv xMV"6q;OO^- G0Yʏ۾`# 8.m} I'[Sw2` Lg'*5 SS33`#r|Z)^-ܝf˟ K,"cD_0-?k<gb>`}]0'@<҃035Y ,l6㖶lN.hdz-{O֙S?Y=}*y#2{RY3޳d Z[jm=X%pvRgP0L[ݷ2;&a%PQ`)⬒ݙt,Lc4<2&q|V%㴽>[}hO{dy,vw{][ñ҃Sp ZԈ_> 'ǟƹRj)u!+=(}]Yl_͖֧> t`  (gAH^#^g$pʖl ˬ+0 z!I(krC> ȵ)IC;~ZR*ЧOeM4דq@@2? PmY&+@osY1*/JaB ?T P*ZL~V>VB9>CwfWCxSxk"3T`7*ď,Uڷ*O_>5-q]rT@ `id=g T P*0KȹٷxyxXiM|OGhz{;-O~IX#iCk ~nmH(96lT  Xr_y9?΃ o5Z PeR [Z[S5gAا&HmPZ^>#rVӸc X,%+0k^̀ @OXߧ&}jWJ>xl]Xgpt0xʬ'[rKO|>mK:#eٳgkj˾|Z|ˀ,95`|MK\y-g־q@<`;Wmv&[~H>3Z4dگ}=%]5*ݹ۽kham$pR.%z\i5l@pfmou{oY}Y 7)|" )H5 ȔFZ0qCu*+0`[~w5`g^ޏ'a!/!kY q *=RQ~㮟˖Udz\WF"πTm`/Ǎ1d-s5`aXJQâπ5ςF(޽ oW,`d# ?Y=]bp ;qld;W\=ʻ8q坭93R2X>>@{*+0`dq[re۷!Y XN|7< V`71~MEj2 6鹦?T6y, [MX ɺV=W ɀ\ܙo< ^y\T POgoŠm^\T 죀g GJ[9 xϖ\k T+YU< P*@xDdBI [Fw_6, P*PW`kLs[°̞IENDB`klystrack-0.20171212/klystrack/doc/LICENSE0000644000000000000000000000456613214501362016407 0ustar rootrootCopyright (c) 2009-2012 Tero Lindeman (kometbomb) Additional graphics copyright (c) 2010-2012 Ilija Melentijevic 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. == Graphics == 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. == 3rd party software == This software uses the Mersenne Twister random number generator. Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. klystrack-0.20171212/klystrack/doc/SDL_image.txt0000644000000000000000000000041213214501362017711 0ustar rootrootPlease include this notice with the runtime environment: This library is distributed under the terms of the GNU LGPL license: http://www.gnu.org/copyleft/lesser.html The source is available from the libraries page at the SDL website: http://www.libsdl.org/ klystrack-0.20171212/klystrack/doc/SDL.txt0000644000000000000000000000056113214501362016554 0ustar rootrootThe Simple DirectMedia Layer (SDL for short) is a cross-platform library designed to make it easy to write multi-media software, such as games and emulators. The Simple DirectMedia Layer library source code is available from: http://www.libsdl.org/ This library is distributed under the terms of the GNU LGPL license: http://www.gnu.org/copyleft/lesser.html klystrack-0.20171212/klystrack/doc/Default.kt0000644000000000000000000000032213214501362017310 0ustar rootrootcyd!song@2@@@@klystrack-0.20171212/klystrack/src/0000755000000000000000000000000013214501362015411 5ustar rootrootklystrack-0.20171212/klystrack/src/memwriter.h0000644000000000000000000000036413214501362017600 0ustar rootroot#ifndef MEMWRITER_H #define MEMWRITER_H #include typedef struct { void *data; size_t allocated, size; size_t position; FILE *flush; } MemWriter; #include "SDL_rwops.h" SDL_RWops * create_memwriter(); #endif klystrack-0.20171212/klystrack/src/theme.h0000644000000000000000000000505613214501362016672 0ustar rootroot#ifndef THEME_H #define THEME_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ enum { COLOR_SEQUENCE_COUNTER, COLOR_SEQUENCE_NORMAL, COLOR_PATTERN_SELECTED, COLOR_PATTERN_BAR, COLOR_PATTERN_BEAT, COLOR_PATTERN_INSTRUMENT, COLOR_PATTERN_INSTRUMENT_BAR, COLOR_PATTERN_INSTRUMENT_BEAT, COLOR_PATTERN_VOLUME, COLOR_PATTERN_VOLUME_BAR, COLOR_PATTERN_VOLUME_BEAT, COLOR_PATTERN_CTRL, COLOR_PATTERN_CTRL_BAR, COLOR_PATTERN_CTRL_BEAT, COLOR_PATTERN_COMMAND, COLOR_PATTERN_COMMAND_BAR, COLOR_PATTERN_COMMAND_BEAT, COLOR_PATTERN_NORMAL, COLOR_PATTERN_DISABLED, COLOR_PROGRAM_SELECTED, COLOR_PROGRAM_EVEN, COLOR_PROGRAM_ODD, COLOR_INSTRUMENT_SELECTED, COLOR_INSTRUMENT_NORMAL, COLOR_MENU_NORMAL, COLOR_MENU_SELECTED, COLOR_MENU_HEADER, COLOR_MENU_HEADER_SELECTED, COLOR_MENU_SHORTCUT, COLOR_MENU_SHORTCUT_SELECTED, COLOR_MAIN_TEXT, COLOR_SMALL_TEXT, COLOR_BACKGROUND, COLOR_BUTTON_TEXT, COLOR_TEXT_SHADOW, COLOR_PATTERN_EMPTY_DATA, COLOR_WAVETABLE_SAMPLE, COLOR_WAVETABLE_BACKGROUND, COLOR_PROGRESS_BAR, COLOR_PATTERN_SEQ_NUMBER, COLOR_CATOMETER_EYES, COLOR_STATUSBAR_TEXT, /*-------------*/ NUM_COLORS }; #include "SDL.h" extern Uint32 colors[NUM_COLORS]; void load_theme(const char *name); void enum_themes(); void free_themes(); void update_theme_menu(); Uint32 mix_colors(Uint32 a, Uint32 b); // result = a * (1.0-b_alpha) + b*(b_alpha) void init_resources_dir(void); char * query_resource_directory(void); void set_scaled_cursor(); #endif klystrack-0.20171212/klystrack/src/optimize.c0000644000000000000000000002203013214501362017412 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "optimize.h" #include "edit.h" #include "macros.h" #include "mused.h" #include bool is_pattern_used(const MusSong *song, int p) { for (int c = 0 ; c < song->num_channels ; ++c) { for (int s = 0 ; s < song->num_sequences[c] ; ++s) { if (song->sequence[c][s].pattern == p) { return true; } } } return false; } static void replace_pattern(MusSong *song, int from, int to) { for (int c = 0 ; c < song->num_channels ; ++c) { for (int s = 0 ; s < song->num_sequences[c] ; ++s) { if (song->sequence[c][s].pattern == from) { song->sequence[c][s].pattern = to; } } } } bool is_pattern_equal(const MusPattern *a, const MusPattern *b) { if (b->num_steps != a->num_steps) return false; for (int i = 0 ; i < a->num_steps ; ++i) if (a->step[i].note != b->step[i].note || a->step[i].instrument != b->step[i].instrument || a->step[i].volume != b->step[i].volume || a->step[i].ctrl != b->step[i].ctrl || a->step[i].command != b->step[i].command) return false; return true; } bool is_pattern_empty(const MusPattern *a) { for (int i = 0 ; i < a->num_steps ; ++i) if (a->step[i].note != MUS_NOTE_NONE || a->step[i].instrument != MUS_NOTE_NO_INSTRUMENT || a->step[i].volume != MUS_NOTE_NO_VOLUME || a->step[i].ctrl != 0 || a->step[i].command != 0) return false; return true; } bool is_instrument_used(const MusSong *song, int instrument) { for (int p = 0 ; p < song->num_patterns ; ++p) { for (int i = 0 ; i < song->pattern[p].num_steps ; ++i) { if (song->pattern[p].step[i].instrument == instrument) return true; } } return false; } static void remove_instrument(MusSong *song, int instrument) { for (int p = 0 ; p < song->num_patterns ; ++p) { for (int i = 0 ; i < song->pattern[p].num_steps ; ++i) { if (song->pattern[p].step[i].instrument != MUS_NOTE_NO_INSTRUMENT && song->pattern[p].step[i].instrument > instrument) song->pattern[p].step[i].instrument--; } } for (int i = instrument ; i < song->num_instruments - 1 ; ++i) memcpy(&song->instrument[i], &song->instrument[i + 1], sizeof(song->instrument[i])); kt_default_instrument(&song->instrument[song->num_instruments - 1]); } bool is_wavetable_used(const MusSong *song, int wavetable) { for (int i = 0 ; i < song->num_instruments ; ++i) { if (song->instrument[i].wavetable_entry == wavetable) { debug("Wavetable %x used by instrument %x wave", wavetable, i); return true; } if (song->instrument[i].fm_wave == wavetable) { debug("Wavetable %x used by instrument %x FM", wavetable, i); return true; } for (int p = 0 ; p < MUS_PROG_LEN ; ++p) if ((song->instrument[i].program[p] & 0x7fff) == (MUS_FX_SET_WAVETABLE_ITEM | wavetable)) { debug("Wavetable %x used by instrument %x program (step %d)", wavetable, i, p); return true; } } for (int p = 0 ; p < song->num_patterns ; ++p) { for (int i = 0 ; i < song->pattern[p].num_steps ; ++i) { if ((song->pattern[p].step[i].command) == (MUS_FX_SET_WAVETABLE_ITEM | wavetable)) { debug("Wavetable %x used by pattern %x command (step %d)", wavetable, p, i); return true; } } } return false; } static void remove_wavetable(MusSong *song, CydEngine *cyd, int wavetable) { debug("Removing wavetable item %d", wavetable); for (int i = 0 ; i < song->num_instruments ; ++i) { if (song->instrument[i].wavetable_entry > wavetable) song->instrument[i].wavetable_entry--; if (song->instrument[i].fm_wave == wavetable) song->instrument[i].fm_wave--; for (int p = 0 ; p < MUS_PROG_LEN ; ++p) if ((song->instrument[i].program[p] & 0x7f00) == MUS_FX_SET_WAVETABLE_ITEM) { Uint8 param = song->instrument[i].program[p] & 0xff; if (param > wavetable) song->instrument[i].program[p] = (song->instrument[i].program[p] & 0x8000) | MUS_FX_SET_WAVETABLE_ITEM | (param - 1); } } for (int p = 0 ; p < song->num_patterns ; ++p) { for (int i = 0 ; i < song->pattern[p].num_steps ; ++i) { if ((song->pattern[p].step[i].command & 0xff00) == MUS_FX_SET_WAVETABLE_ITEM) { Uint8 param = song->pattern[p].step[i].command & 0xff; if (param > wavetable) song->pattern[p].step[i].command = MUS_FX_SET_WAVETABLE_ITEM | (param - 1); } } } for (int i = wavetable ; i < song->num_wavetables - 1 ; ++i) { strcpy(song->wavetable_names[i], song->wavetable_names[i + 1]); cyd->wavetable_entries[i].flags = cyd->wavetable_entries[i + 1].flags; cyd->wavetable_entries[i].sample_rate = cyd->wavetable_entries[i + 1].sample_rate; cyd->wavetable_entries[i].samples = cyd->wavetable_entries[i + 1].samples; cyd->wavetable_entries[i].loop_begin = cyd->wavetable_entries[i + 1].loop_begin; cyd->wavetable_entries[i].loop_end = cyd->wavetable_entries[i + 1].loop_end; cyd->wavetable_entries[i].base_note = cyd->wavetable_entries[i + 1].base_note; cyd->wavetable_entries[i].data = realloc(cyd->wavetable_entries[i].data, cyd->wavetable_entries[i + 1].samples * sizeof(Sint16)); memcpy(cyd->wavetable_entries[i].data, cyd->wavetable_entries[i + 1].data, cyd->wavetable_entries[i + 1].samples * sizeof(Sint16)); } strcpy(song->wavetable_names[song->num_wavetables - 1], ""); cyd_wave_entry_init(&cyd->wavetable_entries[song->num_wavetables - 1], NULL, 0, 0, 0, 0, 0); } static void remove_pattern(MusSong *song, int p) { void * temp = song->pattern[p].step; for (int i = 0 ; i < song->pattern[p].num_steps ; ++i) zero_step(&song->pattern[p].step[i]); for (int a = p ; a < song->num_patterns - 1 ; ++a) { memcpy(&song->pattern[a], &song->pattern[a + 1], sizeof(song->pattern[a])); replace_pattern(song, a + 1, a); } if (song->num_patterns >= 1) song->pattern[song->num_patterns - 1].step = temp; --song->num_patterns; } void optimize_duplicate_patterns(MusSong *song) { debug("Kill unused patterns"); int orig_count = song->num_patterns; for (int a = 0 ; a < song->num_patterns ; ++a) { if (is_pattern_used(song, a)) { for (int b = a + 1 ; b < song->num_patterns ; ++b) { if (is_pattern_used(song, b) && is_pattern_equal(&song->pattern[a], &song->pattern[b])) { replace_pattern(song, b, a); } } } } for (int a = 0 ; a < song->num_patterns ; ) { if (!is_pattern_used(song, a)) { remove_pattern(song, a); } else ++a; } set_info_message("Reduced number of patterns from %d to %d", orig_count, song->num_patterns); song->num_patterns = NUM_PATTERNS; } void optimize_unused_instruments(MusSong *song) { int removed = 0; debug("Kill unused instruments"); for (int i = 0 ; i < song->num_instruments ; ++i) if (!is_instrument_used(song, i)) { remove_instrument(song, i); ++removed; } set_info_message("Removed %d unused instruments", removed); } void optimize_unused_wavetables(MusSong *song, CydEngine *cyd) { int removed = 0; debug("Kill unused wavetables"); for (int i = 0 ; i < song->num_wavetables ; ++i) if (!is_wavetable_used(song, i)) { remove_wavetable(song, cyd, i); ++removed; } set_info_message("Removed %d unused wavetables", removed); } void optimize_song(MusSong *song) { debug("Optimizing song"); optimize_duplicate_patterns(song); optimize_unused_instruments(&mused.song); optimize_unused_wavetables(&mused.song, &mused.cyd); set_info_message("Removed unused song data"); } void optimize_patterns_action(void *unused1, void *unused2, void *unused3) { optimize_duplicate_patterns(&mused.song); } void optimize_instruments_action(void *unused1, void *unused2, void *unused3) { optimize_unused_instruments(&mused.song); } void optimize_wavetables_action(void *unused1, void *unused2, void *unused3) { optimize_unused_wavetables(&mused.song, &mused.cyd); } klystrack-0.20171212/klystrack/src/config.h0000644000000000000000000000240413214501362017027 0ustar rootroot#ifndef CONFIG_H #define CONFIG_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include void load_config(const char *path, bool apply); void save_config(const char *path); void apply_config(); #endifklystrack-0.20171212/klystrack/src/keytab.c0000644000000000000000000000640713214501362017043 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "keytab.h" const KeyDef keydefs[] = { KEYDEF(BACKSPACE), KEYDEF(TAB), KEYDEF(CLEAR), KEYDEF(RETURN), KEYDEF(PAUSE), KEYDEF(ESCAPE), KEYDEF(SPACE), KEYDEF(EXCLAIM), KEYDEF(QUOTEDBL), KEYDEF(HASH), KEYDEF(DOLLAR), KEYDEF(AMPERSAND), KEYDEF(QUOTE), KEYDEF(LEFTPAREN), KEYDEF(RIGHTPAREN), KEYDEF(ASTERISK), KEYDEF(PLUS), KEYDEF(COMMA), KEYDEF(MINUS), KEYDEF(PERIOD), KEYDEF(SLASH), KEYDEF(0), KEYDEF(1), KEYDEF(2), KEYDEF(3), KEYDEF(4), KEYDEF(5), KEYDEF(6), KEYDEF(7), KEYDEF(8), KEYDEF(9), KEYDEF(COLON), KEYDEF(SEMICOLON), KEYDEF(LESS), KEYDEF(EQUALS), KEYDEF(GREATER), KEYDEF(QUESTION), KEYDEF(AT), KEYDEF(LEFTBRACKET), KEYDEF(BACKSLASH), KEYDEF(RIGHTBRACKET), KEYDEF(CARET), KEYDEF(UNDERSCORE), KEYDEF(BACKQUOTE), KEYDEF(a), KEYDEF(b), KEYDEF(c), KEYDEF(d), KEYDEF(e), KEYDEF(f), KEYDEF(g), KEYDEF(h), KEYDEF(i), KEYDEF(j), KEYDEF(k), KEYDEF(l), KEYDEF(m), KEYDEF(n), KEYDEF(o), KEYDEF(p), KEYDEF(q), KEYDEF(r), KEYDEF(s), KEYDEF(t), KEYDEF(u), KEYDEF(v), KEYDEF(w), KEYDEF(x), KEYDEF(y), KEYDEF(z), KEYDEF(DELETE), KEYDEF(KP_0), KEYDEF(KP_1), KEYDEF(KP_2), KEYDEF(KP_3), KEYDEF(KP_4), KEYDEF(KP_5), KEYDEF(KP_6), KEYDEF(KP_7), KEYDEF(KP_8), KEYDEF(KP_9), KEYDEF(KP_PERIOD), KEYDEF(KP_DIVIDE), KEYDEF(KP_MULTIPLY), KEYDEF(KP_MINUS), KEYDEF(KP_PLUS), KEYDEF(KP_ENTER), KEYDEF(KP_EQUALS), KEYDEF(UP), KEYDEF(DOWN), KEYDEF(RIGHT), KEYDEF(LEFT), KEYDEF(INSERT), KEYDEF(HOME), KEYDEF(END), KEYDEF(PAGEUP), KEYDEF(PAGEDOWN), KEYDEF(F1), KEYDEF(F2), KEYDEF(F3), KEYDEF(F4), KEYDEF(F5), KEYDEF(F6), KEYDEF(F7), KEYDEF(F8), KEYDEF(F9), KEYDEF(F10), KEYDEF(F11), KEYDEF(F12), KEYDEF(F13), KEYDEF(F14), KEYDEF(F15), KEYDEF(CAPSLOCK), KEYDEF(SCROLLLOCK), KEYDEF(RSHIFT), KEYDEF(LSHIFT), KEYDEF(RCTRL), KEYDEF(LCTRL), KEYDEF(RALT), KEYDEF(LALT), KEYDEF(MODE), KEYDEF(HELP), KEYDEF(PRINTSCREEN), KEYDEF(SYSREQ), KEYDEF(MENU), KEYDEF(POWER), KEYDEF(UNDO), {NULL,0} }; const KeyDef moddefs[] = { MODDEF(LSHIFT), MODDEF(RSHIFT), MODDEF(LCTRL), MODDEF(RCTRL), MODDEF(LALT), MODDEF(RALT), MODDEF(NUM), MODDEF(CAPS), MODDEF(MODE), MODDEF(CTRL), MODDEF(SHIFT), MODDEF(ALT), {NULL,0} }; klystrack-0.20171212/klystrack/src/import/0000755000000000000000000000000013214501362016723 5ustar rootrootklystrack-0.20171212/klystrack/src/import/hubbard.h0000644000000000000000000000167513214501362020514 0ustar rootroot#ifndef HUBBARD_H #define HUBBARD_H #include typedef struct { unsigned short int org; unsigned char data[65536]; struct { unsigned short int songtab; unsigned short int patternptrhi, patternptrlo; unsigned short int songs[16][3]; unsigned short int instruments; } addr; // decoded data struct { unsigned short int pulse_width; unsigned char waveform; unsigned char a, d, s, r; unsigned char vibrato_depth; unsigned char pwm; unsigned char fx; } instrument[256]; struct { struct { unsigned char note; unsigned char length; unsigned char legato; unsigned char instrument; char portamento; } note[256]; int length; } pattern[256]; int n_patterns; struct { unsigned char pattern[256]; int length; } track[3]; int n_tracks; int n_subsongs, n_instruments; int vib_type; } hubbard_t; int import_hubbard(FILE *f); #endif klystrack-0.20171212/klystrack/src/import/import.c0000644000000000000000000000570213214501362020405 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "mused.h" #include "event.h" #include "import.h" #include "mod.h" #include "ahx.h" #include "xm.h" #include "org.h" #include "hubbard.h" #include "gui/toolutil.h" #include "gui/msgbox.h" #include "diskop.h" #include "SDL_endian.h" #include "action.h" #include "optimize.h" extern Mused mused; extern GfxDomain *domain; void import_module(void *type, void* unused1, void* unused2) { int r; if (mused.modified) r = confirm_ync(domain, mused.slider_bevel, &mused.largefont, "Save song?"); else r = -1; if (r == 0) return; if (r == 1) { int r; open_data(MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_SAVE), &r); if (!r) return; } static const char *mod_name[] = {"a Protracker", "an AHX", "a FastTracker II", "a Cave Story", "a Rob Hubbard"}; static const char *mod_ext[] = {"mod", "ahx", "xm", "org", "sid"}; char buffer[100]; snprintf(buffer, sizeof(buffer), "Import %s song", mod_name[CASTPTR(int, type)]); FILE * f = open_dialog("rb", buffer, mod_ext[CASTPTR(int, type)], domain, mused.slider_bevel, &mused.largefont, &mused.smallfont, NULL); if (!f) return; stop(NULL, NULL, NULL); new_song(); switch (CASTPTR(int, type)) { case IMPORT_MOD: r = import_mod(f); break; case IMPORT_AHX: r = import_ahx(f); break; case IMPORT_XM: r = import_xm(f); break; case IMPORT_ORG: r = import_org(f); break; case IMPORT_HUBBARD: r = import_hubbard(f); break; } if (CASTPTR(int, type) != IMPORT_HUBBARD) { if (!r) { snprintf(buffer, sizeof(buffer), "Not %s song", mod_name[CASTPTR(int, type)]); msgbox(domain, mused.slider_bevel, &mused.largefont, buffer, MB_OK); } else { optimize_song(&mused.song); } } else { optimize_song(&mused.song); } mused.song.num_patterns = NUM_PATTERNS; fclose(f); set_channels(mused.song.num_channels); } klystrack-0.20171212/klystrack/src/import/ahx.h0000644000000000000000000000230713214501362017656 0ustar rootroot#ifndef AHX_H #define AHX_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (SDL_Surface *dest_surface, 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. */ #include int import_ahx(FILE *f); #endif klystrack-0.20171212/klystrack/src/import/hubbard.c0000644000000000000000000003202013214501362020473 0ustar rootroot#include "hubbard.h" #include "edit.h" #include "mused.h" #include "event.h" #include "SDL_endian.h" #include #include "snd/freqs.h" #include #include "hubdialog.h" extern Mused mused; #define ANY 0xFFFF typedef struct { char magicID[4]; unsigned short int version; unsigned short int dataOffset; unsigned short int loadAddress; unsigned short int initAddress; unsigned short int playAddress; unsigned short int songs; unsigned short int startSong; unsigned int speed; char title[32]; char author[32]; char released[32]; unsigned short int flags; unsigned char startPage; unsigned char pageLength; unsigned short int reserved; char data[65536]; } sid_t; static int match_byte(unsigned char haystack, unsigned short int byte) { return (byte == ANY || haystack == byte); } static int find_bytes(const unsigned char *haystack, int haystack_size, const unsigned short int *needle, int needle_size) { for (int i = 0 ; i < haystack_size - needle_size ; ++i) { for (int si = 0 ; si < needle_size ; ++si) { if (!match_byte(haystack[i + si], needle[si])) goto next_haystack; } return i; next_haystack:; } return -1; } void convert_pattern(hubbard_t *tune, int idx) { tune->pattern[idx].length = 0; unsigned short int addr = tune->data[tune->addr.patternptrhi + idx] << 8 | tune->data[tune->addr.patternptrlo + idx]; if (!addr) return; unsigned char *ptr = &tune->data[addr]; while (*ptr != 0xff) { int len = tune->pattern[idx].length; if ((*ptr & 64)) { if (len > 0) { tune->pattern[idx].note[len - 1].length += (*ptr & 31) + 1; } else { tune->pattern[idx].note[len].note = 0xff; tune->pattern[idx].note[len].length = *ptr & 31; if (tune->pattern[idx].length < 256-1) tune->pattern[idx].length++; } } else { tune->pattern[idx].note[len].length = *ptr & 31; tune->pattern[idx].note[len].legato = !!(*ptr & 32); tune->pattern[idx].note[len].instrument = 0xff; tune->pattern[idx].note[len].portamento = 0; if (*ptr & 128) { ++ptr; char byte = *ptr; if (byte < 0) { if (byte & 1) tune->pattern[idx].note[len].portamento = -(byte & 0x07e); else tune->pattern[idx].note[len].portamento = (byte & 0x07e); } else { tune->pattern[idx].note[len].instrument = byte; if (tune->n_instruments < byte + 1) tune->n_instruments = byte + 1; } } ++ptr; tune->pattern[idx].note[len].note = *ptr; if (tune->pattern[idx].length < 256-1) tune->pattern[idx].length++; } ++ptr; } } void convert_instrument(hubbard_t *tune, int idx) { unsigned char *ptr = &tune->data[tune->addr.instruments + idx * 8]; tune->instrument[idx].pulse_width = ptr[0] | ptr[1] << 8; tune->instrument[idx].waveform = ptr[2] >> 4; tune->instrument[idx].a = ptr[3] >> 4; tune->instrument[idx].d = ptr[3] & 15; tune->instrument[idx].s = ptr[4] >> 4; tune->instrument[idx].r = ptr[4] & 15; tune->instrument[idx].vibrato_depth = ptr[5]; tune->instrument[idx].pwm = ptr[6]; tune->instrument[idx].fx = ptr[7]; } void convert_track(hubbard_t *tune, int song, int track) { unsigned char *ptr = &tune->data[tune->addr.songs[song][track]]; tune->track[track].length = 0; while (*ptr < 0xfe) { tune->track[track].pattern[tune->track[track].length] = *ptr; if (tune->n_patterns < *ptr + 1) tune->n_patterns = *ptr + 1; ++ptr; if (tune->track[track].length < 255) ++tune->track[track].length; } } void determine_version(hubbard_t *tune) { const unsigned short int vibcode[] = { 0x29, 0x07, 0xC9, 0x04, 0x90, 0x02, 0x49, 0x07 }; if (find_bytes(tune->data, 65536, vibcode, sizeof(vibcode) / sizeof(vibcode[0])) != 0xffff) { tune->vib_type = 0; } else { tune->vib_type = 1; } } void convert_hub(hubbard_t *tune, int subsong) { for (int song = 0 ; song < tune->n_subsongs ; ++song) for (int i = 0 ; i < tune->n_tracks ; ++i) { tune->addr.songs[song][i] = tune->data[tune->addr.songtab + i + tune->n_tracks + tune->n_tracks * song * 2] << 8 | tune->data[tune->addr.songtab + i + tune->n_tracks * song * 2]; } determine_version(tune); for (int i = 0 ; i < tune->n_tracks ; ++i) convert_track(tune, subsong, i); for (int i = 0 ; i < tune->n_patterns ; ++i) convert_pattern(tune, i); for (int i = 0 ; i < tune->n_instruments ; ++i) convert_instrument(tune, i); } void init_addr(hubbard_t *tune) { const unsigned short int pattern_ptr_lo[] = { 0xa8, 0xb9, ANY, ANY, 0x85, ANY, 0xB9, ANY, ANY, 0x85, ANY, 0xa9, 0x00 }; const unsigned short int inst_tab[] = { 0xBD, ANY, ANY, 0x99, 0x02, 0xd4 }; int pattablo = find_bytes(tune->data, 65536, pattern_ptr_lo, sizeof(pattern_ptr_lo) / sizeof(pattern_ptr_lo[0])); int insttab = find_bytes(tune->data, 65536, inst_tab, sizeof(inst_tab) / sizeof(inst_tab[0])); int songtab; tune->addr.songtab = 0xffff; const unsigned short int songtab_pattern[] = { 0xaa, 0xbd, ANY, ANY, 0x99, ANY, ANY, 0xe8, 0xc8, 0xc0, 0x06 }; songtab = find_bytes(tune->data, 65536, songtab_pattern, sizeof(songtab_pattern) / sizeof(songtab_pattern[0])); tune->addr.songtab = songtab >= 0 ? SDL_SwapLE16(*(Uint16*)&tune->data[songtab + 2]) : 0xffff; if (tune->addr.songtab == 0xffff) { const unsigned short int songtab_pattern_single[] = { 0xD0, ANY, 0xbd, ANY, ANY, 0x85, ANY, 0xbd, ANY, ANY, 0x85, ANY, 0xDE }; songtab = find_bytes(tune->data, 65536, songtab_pattern_single, sizeof(songtab_pattern_single) / sizeof(songtab_pattern_single[0])); tune->addr.songtab = songtab >= 0 ? SDL_SwapLE16(*(Uint16*)&tune->data[songtab + 3]) : 0xffff; } tune->addr.patternptrlo = pattablo >= 0 ? SDL_SwapLE16(*(Uint16*)&tune->data[pattablo + 2]) : 0xffff; tune->addr.patternptrhi = pattablo >= 0 ? SDL_SwapLE16(*(Uint16*)&tune->data[pattablo + 7]) : 0xffff; tune->addr.instruments = insttab >= 0 ? SDL_SwapLE16(*(Uint16*)&tune->data[insttab + 1]) : 0xffff; debug("SONGS: %x", tune->addr.songtab); debug("PTNLO: %x", tune->addr.patternptrlo); debug("PTNHI: %x", tune->addr.patternptrhi); debug("INSTR: %x", tune->addr.instruments); } unsigned short int load16(FILE *f) { unsigned short int tmp16 = 0; fread(&tmp16, 1, sizeof(tmp16), f); return SDL_SwapBE16(tmp16); } sid_t * load_sid(FILE *f) { sid_t *sid = malloc(sizeof(sid_t)); fread(&sid->magicID, 1, sizeof(sid->magicID), f); sid->version = load16(f); sid->dataOffset = load16(f); sid->loadAddress = load16(f); sid->initAddress = load16(f); sid->playAddress = load16(f); sid->songs = load16(f); sid->startSong = load16(f); fread(&sid->speed, 1, sizeof(sid->speed), f); fread(&sid->title, 1, sizeof(sid->title), f); fread(&sid->author, 1, sizeof(sid->author), f); fread(&sid->released, 1, sizeof(sid->released), f); if (sid->version == 2) { fread(&sid->flags, 1, sizeof(sid->flags), f); fread(&sid->startPage, 1, sizeof(sid->startPage), f); fread(&sid->pageLength, 1, sizeof(sid->pageLength), f); fread(&sid->reserved, 1, sizeof(sid->reserved), f); } fread(&sid->data[0], 1, 65536, f); return sid; } hubbard_t * load_hubbard(sid_t *sid) { hubbard_t * hub = malloc(sizeof(hubbard_t)); memset(hub->data, 0, 65536); if (sid->loadAddress == 0) { memcpy(&hub->data[*(unsigned short int*)&sid->data[0]], &sid->data[2], 65536 - *(unsigned short int*)&sid->data[0]); hub->org = *(unsigned short int*)&sid->data[0]; } else { memcpy(&hub->data[sid->loadAddress], &sid->data[0], 65536 - sid->loadAddress); hub->org = sid->loadAddress; } hub->n_patterns = 0; hub->n_subsongs = sid->songs; hub->n_instruments = 0; hub->n_tracks = 3; init_addr(hub); return hub; } int import_hubbard(FILE *f) { sid_t *sid = load_sid(f); if (!sid) return 0; hubbard_t *hub = load_hubbard(sid); if (!hub) { free(sid); return 0; } int subtune = hub_view(hub); if (subtune < 0) { free(sid); free(hub); return 0; } debug("subtune = %d", subtune); convert_hub(hub, subtune); strncpy(mused.song.title, sid->title, 32); for (int i = 0 ; i < hub->n_patterns ; ++i) { if (!hub->pattern[i].length) continue; int total_length = 0; for (int s = 0 ; s < hub->pattern[i].length ; ++s) total_length += 1 + hub->pattern[i].note[s].length; resize_pattern(&mused.song.pattern[i], total_length); for (int s = 0 ; s < total_length ; ++s) { zero_step(&mused.song.pattern[i].step[s]); } int pos = 0; for (int s = 0 ; s < hub->pattern[i].length ; ++s) { mused.song.pattern[i].step[pos].note = hub->pattern[i].note[s].note; if (hub->pattern[i].note[s].instrument != 0xff) mused.song.pattern[i].step[pos].instrument = hub->pattern[i].note[s].instrument; if (hub->pattern[i].note[s].legato) mused.song.pattern[i].step[pos].ctrl |= MUS_CTRL_LEGATO; if (hub->pattern[i].note[s].portamento != 0) { for (int c = 0 ; c <= hub->pattern[i].note[s].length ; ++c) { if (hub->pattern[i].note[s].portamento < 0) mused.song.pattern[i].step[pos].command = MUS_FX_PORTA_DN_LOG | (((unsigned char)hub->pattern[i].note[s].portamento) & 0x7f); else mused.song.pattern[i].step[pos].command = MUS_FX_PORTA_UP_LOG | hub->pattern[i].note[s].portamento; pos++; } } else pos += 1 + hub->pattern[i].note[s].length; } } int max_pos = 0; for (int track = 0 ; track < hub->n_tracks ; ++track) { int pos = 0; for (int i = 0 ; i < hub->track[track].length ; ++i) { int total_length = 0; for (int s = 0 ; s < hub->pattern[hub->track[track].pattern[i]].length ; ++s) total_length += 1 + hub->pattern[hub->track[track].pattern[i]].note[s].length; pos += total_length; } max_pos = my_max(max_pos, pos); } for (int track = 0 ; track < hub->n_tracks ; ++track) { int pos = 0; for ( ; pos < max_pos ; ) { for (int i = 0 ; i < hub->track[track].length ; ++i) { int total_length = 0; for (int s = 0 ; s < hub->pattern[hub->track[track].pattern[i]].length ; ++s) total_length += 1 + hub->pattern[hub->track[track].pattern[i]].note[s].length; add_sequence(track, pos, hub->track[track].pattern[i], 0); pos += total_length; } } } mused.song.num_channels = hub->n_tracks; mused.song.song_speed = 2; mused.song.song_speed2 = 2; mused.song.song_length = max_pos; for (int i = 0 ; i < hub->n_instruments ; ++i) { int waveforms = 0; mused.song.instrument[i].flags &= ~MUS_INST_DRUM; mused.song.instrument[i].flags |= MUS_INST_INVERT_VIBRATO_BIT; mused.song.instrument[i].cydflags &= ~WAVEFORMS; mused.song.instrument[i].cydflags |= CYD_CHN_ENABLE_KEY_SYNC; if (hub->instrument[i].waveform & 1) waveforms |= CYD_CHN_ENABLE_TRIANGLE; if (hub->instrument[i].waveform & 2) waveforms |= CYD_CHN_ENABLE_SAW; if (hub->instrument[i].waveform & 4) waveforms |= CYD_CHN_ENABLE_PULSE; if (hub->instrument[i].waveform & 8) { waveforms |= CYD_CHN_ENABLE_NOISE; mused.song.instrument[i].base_note = MIDDLE_C + 12; } mused.song.instrument[i].cydflags |= waveforms; int pw = hub->instrument[i].pulse_width; if (pw >= 0x800) pw = 0x800 - (pw - 0x800); mused.song.instrument[i].pw = pw; const int attack_tab[] = {1, 2, 2, 3, 3, 4, 5, 5, 6, 9, 13, 16, 18, 32, 41, 52}; const int decay_tab[] = {1, 3, 4, 5, 6, 7, 8, 9, 10, 16, 22, 28, 32, 55, 63, 63}; const int sustain_tab[] = {0, 3, 6, 8, 0xa, 0xc, 0x10, 0x14, 0x1c, 0x1d, 0x1e, 0x1f, 0x1f}; mused.song.instrument[i].adsr.a = attack_tab[hub->instrument[i].a]; mused.song.instrument[i].adsr.d = decay_tab[hub->instrument[i].d]; mused.song.instrument[i].adsr.s = sustain_tab[hub->instrument[i].s]; mused.song.instrument[i].adsr.r = decay_tab[hub->instrument[i].r]; mused.song.instrument[i].prog_period = 1; mused.song.instrument[i].pwm_depth = 0x30; mused.song.instrument[i].pwm_speed = hub->instrument[i].pwm / 8; mused.song.instrument[i].vibrato_speed = 0x20; mused.song.instrument[i].vib_delay = 0; mused.song.instrument[i].vibrato_depth = hub->vib_type == 1 ? hub->instrument[i].vibrato_depth * 0x0c : hub->instrument[i].vibrato_depth; if (hub->instrument[i].fx & 1) { mused.song.instrument[i].flags |= MUS_INST_DRUM; mused.song.instrument[i].program[0] = 0x0208; mused.song.instrument[i].program[1] = 0xFF00; } if (hub->instrument[i].fx & 2) { mused.song.instrument[i].program[0] = 0x0204; mused.song.instrument[i].program[1] = 0xFF00; } if (hub->instrument[i].fx & 4) { mused.song.instrument[i].program[0] = 0x0000; mused.song.instrument[i].program[1] = 0x000C; mused.song.instrument[i].program[2] = 0xFF00; } } free(hub); free(sid); return 1; } klystrack-0.20171212/klystrack/src/import/import.h0000644000000000000000000000237613214501362020416 0ustar rootroot#ifndef IMPORT_H #define IMPORT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ enum { IMPORT_MOD, IMPORT_AHX, IMPORT_XM, IMPORT_ORG, IMPORT_HUBBARD }; void import_module(void *type, void*, void*); #endif klystrack-0.20171212/klystrack/src/import/ahx.c0000644000000000000000000003133013214501362017647 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "ahx.h" #include "edit.h" #include "mused.h" #include "event.h" #include "SDL_endian.h" #include #include "snd/freqs.h" #include extern Mused mused; static Uint8 get_cutoff(int ahx) { // Try to set klystrack cutoff so that it sounds like the ahx cutoff value ahx -= 32; if (ahx > 0) return 0x80 + ahx * 0x50 / 32; else return 0x80 + ahx * 0x78 / 32; } static Uint16 find_command_ahx(Uint8 command, Uint8 data, Uint8 *ctrl) { switch (command) { case 0xc: { if (data <= 0x40) return MUS_FX_SET_VOLUME | ((int)data * 2); else if (data >= 0x50 && data <= 0x90) return MUS_FX_SET_GLOBAL_VOLUME | ((int)(data - 0x50) * 2); // not totally correct else if (data >= 0xa0 && data <= 0xe0) return MUS_FX_SET_CHANNEL_VOLUME | ((int)(data - 0xa0) * 2); } break; case 0xa: { _0xa00: return MUS_FX_FADE_VOLUME | (my_min(0xf, (data & 0x0f) * 2)) | (my_min(0xf, ((data & 0xf0) >> 4) * 2) << 4); } break; case 0x3: { if (data < 0x20) { return MUS_FX_SLIDE | my_min(0xff, data * 16); } else { *ctrl |= MUS_CTRL_LEGATO; return 0; } } break; case 0x5: { *ctrl |= MUS_CTRL_SLIDE|MUS_CTRL_LEGATO; goto _0xa00; } break; case 0x1: { return MUS_FX_PORTA_UP | my_min(0xff, data * 8); } break; case 0x2: { return MUS_FX_PORTA_DN | my_min(0xff, data * 8); } break; case 0x4: { return MUS_FX_CUTOFF_SET_COMBINED | (get_cutoff(data & 63)); } break; case 0x9: { return MUS_FX_PW_SET | ((int)(data & 63) * 0x80 / 63); } break; case 0xf: { return MUS_FX_SET_SPEED | (data & 0xf); } break; case 0xe: { if ((data & 0xf0) == 0xc0) { return MUS_FX_EXT_NOTE_CUT | (data & 0xf); } else if ((data & 0xf0) == 0xd0) { return MUS_FX_EXT_NOTE_DELAY | (data & 0xf); } else if ((data & 0xf0) == 0x40) { return MUS_FX_VIBRATO | (data & 0xf); } else if ((data & 0xf0) == 0x10) { return MUS_FX_EXT_PORTA_UP | (data & 0xf); } else if ((data & 0xf0) == 0x20) { return MUS_FX_EXT_PORTA_DN | (data & 0xf); } else if ((data & 0xf0) == 0xa0) { return MUS_FX_EXT_FADE_VOLUME_UP | (data & 0xf); } else if ((data & 0xf0) == 0xb0) { return MUS_FX_EXT_FADE_VOLUME_DN | (data & 0xf); } } break; default: break; } return 0; } static void ahx_program(Uint8 fx1, Uint8 data1, int *pidx, MusInstrument *i, const int *pos, int *has_4xx) { switch (fx1) { case 0: i->program[*pidx] = MUS_FX_CUTOFF_SET_COMBINED | (get_cutoff(data1 & 0x3f)); break; case 1: i->program[*pidx] = MUS_FX_PORTA_UP | (data1 & 0xff); break; case 2: i->program[*pidx] = MUS_FX_PORTA_DN | (data1 & 0xff); break; case 3: i->program[*pidx] = MUS_FX_PW_SET | my_min(255, my_max(8, ((int)(data1) * 0x80 / 63))); break; case 0xf: i->program[*pidx] = MUS_FX_SET_SPEED | data1; break; case 4: *has_4xx |= data1; case 7: --*pidx; // not supported i->program[*pidx] &= ~0x8000; break; case 5: i->program[*pidx] = MUS_FX_JUMP | (pos[data1] & (MUS_PROG_LEN - 1)); if (*pidx > 0) i->program[*pidx - 1] &= ~0x8000; break; case 0xc: case 6: if (data1<=0x40) i->program[*pidx] = MUS_FX_SET_VOLUME | (data1 * 2); else if (data1>=0x50 && data1<=0x90) i->program[*pidx] = MUS_FX_SET_VOLUME | ((int)(data1 - 0x50) * 2); // should be relative but no can do break; } } int import_ahx(FILE *f) { char sig[4]; fread(sig, 1, 4, f); if (memcmp("THX\0", sig, 4) == 0) { } else if (memcmp("THX\1", sig, 4) == 0) { } else return 0; Uint8 byte; Uint16 word; fread(&word, 1, sizeof(word), f); // title offset fread(&word, 1, sizeof(word), f); word = SDL_SwapBE16(word); int track0 = (word & 0x8000) != 0; mused.song.song_rate = (1 + ((word & 0x7000) >> 12)) * 50; int LEN = word & 0xfff; fread(&word, 1, sizeof(word), f); mused.song.loop_point = SDL_SwapBE16(word); fread(&byte, 1, sizeof(byte), f); int TRL = mused.sequenceview_steps = byte; mused.song.loop_point *= TRL; mused.song.song_length = LEN * TRL; fread(&byte, 1, sizeof(byte), f); int TRK = byte; fread(&byte, 1, sizeof(byte), f); int SMP = byte; fread(&byte, 1, sizeof(byte), f); int SS = byte; fseek(f, SS * 2, SEEK_CUR); // we don't need the subsong positions { Uint8 seq[2 * 0x1000 * 4]; fread(&seq, 1, LEN * 2 * 4, f); for (int i = 0 ; i < LEN ; ++i) { for (int c = 0 ; c < 4 ; ++c) { /*if (!track0 && pat == 0) continue;*/ add_sequence(c, i * TRL, seq[c * 2 + i * 4 * 2], *(Sint8*)&seq[c * 2 + i * 4 * 2 + 1]); } } } mused.song.num_patterns = TRK + 1; for (int pat = 0 ; pat < TRK + 1; ++pat) { resize_pattern(&mused.song.pattern[pat], TRL); for (int s = 0 ; s < TRL ; ++s) zero_step(&mused.song.pattern[pat].step[s]); if (track0 && pat == 0) continue; Uint8 steps[64 * 3 + 1]; fread(steps, 3, TRL, f); for (int s = 0 ; s < TRL ; ++s) { Uint32 step = (((Uint32)steps[s * 3] << 16) | ((Uint32)steps[s * 3 + 1] << 8) | ((Uint32)steps[s * 3 + 2])); Uint8 note = (step >> 18) & 0x3f; Uint8 instrument = (step >> 12) & 0x3f; Uint8 command = (step >> 8) & 0xf; Uint8 data = step & 0xff; mused.song.pattern[pat].step[s].note = note ? (note - 1) : MUS_NOTE_NONE; mused.song.pattern[pat].step[s].instrument = instrument ? instrument - 1 : MUS_NOTE_NO_INSTRUMENT; mused.song.pattern[pat].step[s].ctrl = 0; mused.song.pattern[pat].step[s].command = find_command_ahx(command, data, &mused.song.pattern[pat].step[s].ctrl); mused.song.pattern[pat].step[s].volume = MUS_NOTE_NO_VOLUME; } } for (int smp = 0 ; smp < SMP ; ++smp) { MusInstrument *i = &mused.song.instrument[smp]; mus_get_default_instrument(i); i->flags = MUS_INST_SET_PW|MUS_INST_SET_CUTOFF|MUS_INST_INVERT_VIBRATO_BIT|MUS_INST_RELATIVE_VOLUME; i->cydflags = CYD_CHN_ENABLE_FILTER|CYD_CHN_ENABLE_PULSE; fread(&byte, 1, 1, f); i->volume = byte * 2; i->slide_speed = 0xc0; fread(&byte, 1, 1, f); int s = my_min(5, byte & 0x7); if (s >= 4) { s -= 2; i->flags |= MUS_INST_QUARTER_FREQ; } int wavelen_semitones = s * 12; i->base_note = (MIDDLE_C + 48) - wavelen_semitones; Uint8 vol, len; fread(&len, 1, 1, f); fread(&vol, 1, 1, f); i->adsr.a = my_min(31, vol > 0x10 ? 0 : (vol ? (len / vol) / 2 : len / 4)); fread(&len, 1, 1, f); fread(&vol, 1, 1, f); i->adsr.d = my_min(31, sqrt((float)len / 255) * 31 * 2 + 1); // AHX envelopes are linear, we have exponential i->adsr.s = my_min(31, sqrt((float)vol / 64) * 31); fread(&byte, 1, 1, f); fread(&len, 1, 1, f); fread(&vol, 1, 1, f); i->adsr.r = 1; i->adsr.s = my_max(my_min(31, sqrt((float)vol / 64) * 31), i->adsr.s); if (vol == 0) { i->adsr.s = 0; i->adsr.d = my_min(i->adsr.d, sqrt((float)len / 255) * 31 * 2 + 1); } /* --- */ fread(&byte, 1, 1, f); fread(&byte, 1, 1, f); fread(&byte, 1, 1, f); Uint8 flt_upper, flt_lower; fread(&flt_lower, 1, 1, f); flt_lower &= 63; fread(&byte, 1, 1, f); fread(&byte, 1, 1, f); i->vib_delay = byte; i->vibrato_depth = (byte & 0xf) * 8; fread(&byte, 1, 1, f); i->vibrato_speed = byte * 3; Uint8 lower, upper; fread(&lower, 1, 1, f); fread(&upper, 1, 1, f); i->pwm_depth = my_min(255, (int)(upper - lower) * 2); i->pw = ((upper + lower) / 2) * 2047 / 63; fread(&byte, 1, 1, f); i->pwm_speed = (16 / my_max(1, byte)); fread(&flt_upper, 1, 1, f); flt_upper &= 63; if (flt_upper != flt_lower) // Probably AHX0 i->cutoff = 2047 * (int)((flt_upper - flt_lower) & 63) / 63; else i->cutoff = 2047; fread(&byte, 1, 1, f); i->prog_period = byte; int PLEN; fread(&byte, 1, 1, f); PLEN = byte; int pidx = 0; int pos[256]; int was_fixed = 0, has_4xx = 0; Uint32 steps[256]; fread(&steps, sizeof(Uint32), PLEN, f); for (int s = 0 ; s < PLEN ; ++s) { pos[s] = pidx; // map multiple klystrack program steps to the ahx program step if (pidx < MUS_PROG_LEN - 1) { Uint32 step = SDL_SwapBE32(steps[s]); Uint8 fx2 = (step & 0xe0000000) >> 29 ; Uint8 fx1 = (step & 0x1c000000) >> 26; Uint8 wave = (step & 0x3800000) >> 23; Uint8 fixed_note = (step >> 22) & 1; Uint8 note = (step >> 16) & 63; Uint8 data1 = (step >> 8) & 0xff; Uint8 data2 = (step) & 0xff; if (wave != 0) { // 1=triangle, // 2=sawtooth, 3=square, 4=noise switch (wave) { case 1: i->program[pidx] = MUS_FX_SET_WAVEFORM | CYD_CHN_ENABLE_TRIANGLE; break; case 2: i->program[pidx] = MUS_FX_SET_WAVEFORM | CYD_CHN_ENABLE_SAW; break; case 3: i->program[pidx] = MUS_FX_SET_WAVEFORM | CYD_CHN_ENABLE_PULSE; break; case 4: i->program[pidx] = MUS_FX_SET_WAVEFORM | CYD_CHN_ENABLE_NOISE; break; default: break; } } if (note || was_fixed) { if (wave && pidx < MUS_PROG_LEN - 1) { i->program[pidx] |= 0x8000; ++pidx; } int n = note - 1; if (fixed_note) n = my_min(0xf0, my_max(0, (int)n)) + 48 - wavelen_semitones; n = my_max(0, my_min(n, FREQ_TAB_SIZE - 1)); if (pidx < MUS_PROG_LEN - 1) i->program[pidx] = (fixed_note ? MUS_FX_ARPEGGIO_ABS : MUS_FX_ARPEGGIO) | ((n) & 0xff); } if (fx1 == 0x5 && fx2 != 0x0) { // jump should be processed after fx2 has been processed or it will jump to wrong row fx1 ^= fx2; fx2 ^= fx1; fx1 ^= fx2; data1 ^= data2; data2 ^= data1; data1 ^= data2; } if (fx1 || data1) { if ((wave || note) && pidx < MUS_PROG_LEN - 1) { i->program[pidx] |= 0x8000; ++pidx; } if (pidx < MUS_PROG_LEN - 1) ahx_program(fx1, data1, &pidx, i, pos, &has_4xx); } if (fx2 || data2) { if ((wave || note || (fx1 || data1)) && pidx < MUS_PROG_LEN - 1) { i->program[pidx] |= 0x8000; ++pidx; } if (pidx < MUS_PROG_LEN - 1) ahx_program(fx2, data2, &pidx, i, pos, &has_4xx); } was_fixed = fixed_note; ++pidx; } } if (!(has_4xx & 0x0f)) { i->pwm_depth = 0 ; // no modulation set so disable } if (!(has_4xx & 0xf0)) { i->cutoff = 2047 ; // no modulation set so disable } i->program[pidx] = MUS_FX_END; } size_t begin_names = ftell(f); fseek(f, 0, SEEK_END); size_t bytes = ftell(f) - begin_names; char *txt = malloc(bytes); fseek(f, begin_names, SEEK_SET); fread(txt, bytes, 1, f); char *ptr = txt; strncpy(mused.song.title, ptr, sizeof(mused.song.title)); ptr += strlen(ptr) + 1; for (int smp = 0 ; smp < SMP ; ++smp) { strncpy(mused.song.instrument[smp].name, ptr, sizeof(mused.song.instrument[smp].name)); ptr += strlen(ptr) + 1; } free(txt); // Amiga panning // not completely panned to left and right mused.song.default_panning[0] = -48; mused.song.default_panning[1] = 48; mused.song.default_panning[2] = 48; mused.song.default_panning[3] = -48; return 1; } klystrack-0.20171212/klystrack/src/import/xm.h0000644000000000000000000000230413214501362017517 0ustar rootroot#ifndef XM_H #define XM_H /* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (SDL_Surface *dest_surface, 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. */ #include int import_xm(FILE *f); #endif klystrack-0.20171212/klystrack/src/import/hubdialog.h0000644000000000000000000000010713214501362021030 0ustar rootroot#pragma once #include "hubbard.h" int hub_view(hubbard_t *hub); klystrack-0.20171212/klystrack/src/import/hubdialog.c0000644000000000000000000001517513214501362021036 0ustar rootroot#include "hubdialog.h" #include "mused.h" #include "view.h" #include "gui/msgbox.h" #include "gui/bevel.h" #include "gui/bevdefs.h" #include "gui/dialog.h" #include "gfx/gfx.h" #include "gui/view.h" #include "gui/mouse.h" #include "gui/toolutil.h" #include #define TOP_LEFT 0 #define TOP_RIGHT 0 #define MARGIN 8 #define SCREENMARGIN 64 #define DIALOG_WIDTH 150 #define DIALOG_HEIGHT 120 #define TITLE 14 #define FIELD 14 #define CLOSE_BUTTON 12 #define ELEMWIDTH data.elemwidth #define LIST_WIDTH data.list_width #define BUTTONS 16 static struct { int subsong; int selected_subsong; const char *title; int quit; const Font *largefont, *smallfont; GfxSurface *gfx; hubbard_t *hub; } data; extern const KeyShortcut shortcuts[]; static void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void parameters_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static const View filebox_view[] = { {{ SCREENMARGIN, SCREENMARGIN, DIALOG_WIDTH, DIALOG_HEIGHT-MARGIN }, window_view, &data, -1}, {{ MARGIN+SCREENMARGIN, SCREENMARGIN+MARGIN, DIALOG_WIDTH-MARGIN*2, TITLE - 2 }, title_view, &data, -1}, {{ SCREENMARGIN+MARGIN, SCREENMARGIN+MARGIN+TITLE+2, DIALOG_WIDTH-MARGIN, DIALOG_HEIGHT-BUTTONS-2-MARGIN }, parameters_view, &data, -1}, {{ SCREENMARGIN+MARGIN, DIALOG_HEIGHT-BUTTONS+2+SCREENMARGIN-MARGIN-8, DIALOG_WIDTH-MARGIN*2, BUTTONS-2 }, buttons_view, &data, -1}, {{0, 0, 0, 0}, NULL} }; static void ok_action(void *unused0, void *unused1, void *unused2) { data.selected_subsong = data.subsong; } static void parameters_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect button; copy_rect(&button, area); button.w = 128; button.h = 10; data.subsong += generic_field(event, &button, -1, -1, "SUBSONG", "%02d", MAKEPTR(data.subsong), 2); button.y += button.h; if (data.subsong < 0) data.subsong = 0; if (data.subsong >= data.hub->n_subsongs) data.subsong = data.hub->n_subsongs - 1; data.hub->n_tracks += generic_field(event, &button, -1, -1, "TRACKS", "%d", MAKEPTR(data.hub->n_tracks), 1); button.y += button.h; if (data.hub->n_tracks < 1) data.hub->n_tracks = 1; if (data.hub->n_tracks > 3) data.subsong = 3; data.hub->addr.patternptrlo += generic_field(event, &button, -1, -1, "PAT LO", "%04X", MAKEPTR(data.hub->addr.patternptrlo), 4); button.y += button.h; data.hub->addr.patternptrhi += generic_field(event, &button, -1, -1, "PAT HI", "%04X", MAKEPTR(data.hub->addr.patternptrhi), 4); button.y += button.h; data.hub->addr.songtab += generic_field(event, &button, -1, -1, "SONGS", "%04X", MAKEPTR(data.hub->addr.songtab), 4); button.y += button.h; data.hub->addr.instruments += generic_field(event, &button, -1, -1, "INSTRUMENTS", "%04X", MAKEPTR(data.hub->addr.instruments), 4); button.y += button.h; } static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect button; copy_rect(&button, area); /*button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, data.mode == 0 ? BEV_BUTTON_ACTIVE : BEV_BUTTON, BEV_BUTTON_ACTIVE, "Commands", init_lines, 0, 0, 0); button.x += button.w + 1; */ button.w = strlen("OK") * data.largefont->w + 24; button.x = area->w + area->x - button.w; button_text_event(dest_surface, event, &button, data.gfx, data.largefont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "OK", ok_action, 0, 0, 0); button.x += button.w + 1; } void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { bevel(dest_surface, area, data.gfx, BEV_MENU); } void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { const char* title = data.title; SDL_Rect titlearea, button; copy_rect(&titlearea, area); titlearea.w -= CLOSE_BUTTON - 4; copy_rect(&button, area); adjust_rect(&button, titlearea.h - CLOSE_BUTTON); button.w = CLOSE_BUTTON; button.x = area->w + area->x - CLOSE_BUTTON; font_write(data.largefont, dest_surface, &titlearea, title); if (button_event(dest_surface, event, &button, data.gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_CLOSE, NULL, MAKEPTR(1), 0, 0) & 1) data.quit = 1; } int hub_view(hubbard_t *hub) { set_repeat_timer(NULL); memset(&data, 0, sizeof(data)); data.title = "Import .SID"; data.largefont = &mused.largefont; data.smallfont = &mused.smallfont; data.selected_subsong = -1; data.gfx = mused.slider_bevel; data.hub = hub; while (!data.quit) { SDL_Event e = { 0 }; int got_event = 0; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_QUIT: set_repeat_timer(NULL); SDL_PushEvent(&e); return -1; break; case SDL_KEYDOWN: { switch (e.key.keysym.sym) { case SDLK_ESCAPE: set_repeat_timer(NULL); return -1; break; /*case SDLK_KP_ENTER: case SDLK_RETURN: if (data.selected_file != -1) data.picked_file = &data.files[data.selected_file]; else goto enter_pressed; break;*/ default: break; } } break; case SDL_USEREVENT: e.type = SDL_MOUSEBUTTONDOWN; break; case SDL_MOUSEMOTION: if (domain) { e.motion.xrel /= domain->scale; e.motion.yrel /= domain->scale; e.button.x /= domain->scale; e.button.y /= domain->scale; } break; case SDL_MOUSEBUTTONDOWN: if (domain) { e.button.x /= domain->scale; e.button.y /= domain->scale; } break; case SDL_MOUSEBUTTONUP: { if (e.button.button == SDL_BUTTON_LEFT) mouse_released(&e); } break; } if (e.type != SDL_MOUSEMOTION || (e.motion.state)) ++got_event; // ensure the last event is a mouse click so it gets passed to the draw/event code if (e.type == SDL_MOUSEBUTTONDOWN || (e.type == SDL_MOUSEMOTION && e.motion.state)) break; } if (got_event || gfx_domain_is_next_frame(domain)) { draw_view(domain, filebox_view, &e); gfx_domain_flip(domain); } else SDL_Delay(5); if (data.selected_subsong != -1) break; } return data.selected_subsong; } klystrack-0.20171212/klystrack/src/import/org.h0000644000000000000000000000230713214501362017665 0ustar rootroot#ifndef ORG_H #define ORG_H /* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (SDL_Surface *dest_surface, 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. */ #include int import_org(FILE *f); #endif klystrack-0.20171212/klystrack/src/import/xm.c0000644000000000000000000003465513214501362017530 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "xm.h" #include "mod.h" #include "edit.h" #include "mused.h" #include "event.h" #include "SDL_endian.h" #include "snd/freqs.h" #include #include extern Mused mused; Uint16 find_command_xm(Uint16 command) { if ((command & 0xff00) == 0x0100 || (command & 0xff00) == 0x0200) command = (command & 0xff00) | my_min(0xff, (command & 0xff)); // assuming linear xm freqs else if ((command >> 8) == 'G') command = MUS_FX_SET_GLOBAL_VOLUME | ((command & 0xff) * 2); else if ((command >> 8) == 'H') command = MUS_FX_FADE_GLOBAL_VOLUME | ((command & 0xff) * 2); else command = find_command_pt(command, 0); return command; } int import_xm(FILE *f) { struct { char sig[17]; char name[20]; Uint8 _1a; char tracker_name[20]; Uint16 version; Uint32 header_size; Uint16 song_length; Uint16 restart_position; Uint16 num_channels; Uint16 num_patterns; Uint16 num_instruments; Uint16 flags; Uint16 default_tempo; Uint16 default_bpm; Uint8 pattern_order[256]; } header; fread(&header.sig[0], 1, sizeof(header.sig), f); fread(&header.name[0], 1, sizeof(header.name), f); fread(&header._1a, 1, sizeof(header._1a), f); fread(&header.tracker_name[0], 1, sizeof(header.tracker_name), f); fread(&header.version, 1, sizeof(header.version), f); fread(&header.header_size, 1, sizeof(header.header_size), f); fread(&header.song_length, 1, sizeof(header.song_length), f); fread(&header.restart_position, 1, sizeof(header.restart_position), f); fread(&header.num_channels, 1, sizeof(header.num_channels), f); fread(&header.num_patterns, 1, sizeof(header.num_patterns), f); fread(&header.num_instruments, 1, sizeof(header.num_instruments), f); fread(&header.flags, 1, sizeof(header.flags), f); fread(&header.default_tempo, 1, sizeof(header.default_tempo), f); fread(&header.default_bpm, 1, sizeof(header.default_bpm), f); fread(&header.pattern_order[0], 1, sizeof(header.pattern_order), f); if (strncmp("Extended Module: ", header.sig, 17) != 0) { fatal("Not a FastTracker II module (sig: '%-17s')", header.sig); return 0; } FIX_ENDIAN(header.version); FIX_ENDIAN(header.header_size); FIX_ENDIAN(header.song_length); FIX_ENDIAN(header.restart_position); FIX_ENDIAN(header.num_channels); FIX_ENDIAN(header.num_instruments); FIX_ENDIAN(header.num_patterns); FIX_ENDIAN(header.flags); FIX_ENDIAN(header.default_tempo); FIX_ENDIAN(header.default_bpm); if (header.version != 0x0104) { fatal("XM version 0x%x not supported", header.version); return 0; } if ((int)header.num_channels * (int)header.num_patterns > NUM_PATTERNS) { fatal("Resulting song would have over %d patterns", NUM_PATTERNS); return 0; } if ((int)header.num_channels * (int)header.song_length > NUM_SEQUENCES) { fatal("Resulting song would have over %d sequence patterns", NUM_SEQUENCES); return 0; } int pattern_length[256]; for (int p = 0 ; p < header.num_patterns ; ++p) { struct { Uint32 header_length; Uint8 packing_type; Uint16 num_rows; Uint16 data_size; } pattern_hdr; fread(&pattern_hdr.header_length, 1, sizeof(pattern_hdr.header_length), f); fread(&pattern_hdr.packing_type, 1, sizeof(pattern_hdr.packing_type), f); fread(&pattern_hdr.num_rows, 1, sizeof(pattern_hdr.num_rows), f); fread(&pattern_hdr.data_size, 1, sizeof(pattern_hdr.data_size), f); FIX_ENDIAN(pattern_hdr.data_size); FIX_ENDIAN(pattern_hdr.num_rows); FIX_ENDIAN(pattern_hdr.header_length); pattern_length[p] = pattern_hdr.num_rows; Uint8 data[256*32*5]; debug("num_rows = %d", pattern_hdr.num_rows); fread(&data[0], 1, pattern_hdr.data_size, f); for (int c = 0 ; c < header.num_channels ; ++c) { int pat = p * header.num_channels + c; resize_pattern(&mused.song.pattern[pat], pattern_hdr.num_rows); } Uint8 *ptr = &data[0]; for (int r = 0 ; r < pattern_hdr.num_rows ; ++r) { for (int c = 0 ; c < header.num_channels ; ++c) { Uint8 note = *ptr++; Uint8 instrument = 0, volume = 0, fx = 0, param = 0; if (note & 0x80) { Uint8 flags = note; note = 0; if (flags & 1) note = *ptr++; if (flags & 2) instrument = *ptr++; if (flags & 4) volume = *ptr++; if (flags & 8) fx = *ptr++; if (flags & 16) param = *ptr++; } else { instrument = *ptr++; volume = *ptr++; fx = *ptr++; param = *ptr++; } int pat = p * header.num_channels + c; MusStep *step = &mused.song.pattern[pat].step[r]; step->ctrl = 0; if (note != 0 && note != 97) step->note = note - 1; else if (note == 97) step->note = MUS_NOTE_RELEASE; else step->note = MUS_NOTE_NONE; step->instrument = instrument != 0 ? instrument - 1 : MUS_NOTE_NO_INSTRUMENT; step->volume = MUS_NOTE_NO_VOLUME; if (volume >= 0x10 && volume <= 0x50) step->volume = (volume - 0x10) * 2; else if (volume >= 0x60 && volume <= 0x6f) step->volume = MUS_NOTE_VOLUME_FADE_DN | (volume & 0xf); else if (volume >= 0x70 && volume <= 0x7f) step->volume = MUS_NOTE_VOLUME_FADE_UP | (volume & 0xf); else if (volume >= 0xf0 && volume <= 0xff) step->ctrl = MUS_CTRL_SLIDE|MUS_CTRL_LEGATO; else if (volume >= 0xb0 && volume <= 0xbf) step->ctrl = MUS_CTRL_VIB; step->command = find_command_xm((fx << 8) | param); } } } int wt_e = 0; for (int i = 0 ; i < header.num_instruments ; ++i) { struct { Uint32 size; char name[22]; Uint8 type; Uint16 num_samples; } instrument_hdr; struct { Uint32 size; Uint8 sample[96]; Uint8 vol_env[48]; Uint8 pan_env[48]; Uint8 num_volume; Uint8 num_panning; Uint8 vol_sustain; Uint8 vol_loop_start, vol_loop_end; Uint8 pan_sustain; Uint8 pan_loop_start, pan_loop_end; Uint8 vol_type; Uint8 pan_type; Uint8 vib_type, vib_sweep, vib_depth, vib_rate; Uint16 vol_fadeout; Uint8 reserved[2]; } instrument_ext_hdr; size_t si = ftell(f); fread(&instrument_hdr.size, 1, sizeof(instrument_hdr.size), f); fread(&instrument_hdr.name[0], 1, sizeof(instrument_hdr.name), f); fread(&instrument_hdr.type, 1, sizeof(instrument_hdr.type), f); fread(&instrument_hdr.num_samples, 1, sizeof(instrument_hdr.num_samples), f); FIX_ENDIAN(instrument_hdr.size); FIX_ENDIAN(instrument_hdr.num_samples); if (instrument_hdr.num_samples > 0) { fread(&instrument_ext_hdr.size, 1, sizeof(instrument_ext_hdr.size), f); fread(&instrument_ext_hdr.sample[0], 1, sizeof(instrument_ext_hdr.sample), f); fread(&instrument_ext_hdr.vol_env[0], 1, sizeof(instrument_ext_hdr.vol_env), f); fread(&instrument_ext_hdr.pan_env[0], 1, sizeof(instrument_ext_hdr.pan_env), f); fread(&instrument_ext_hdr.num_volume, 1, sizeof(instrument_ext_hdr.num_volume), f); fread(&instrument_ext_hdr.num_panning, 1, sizeof(instrument_ext_hdr.num_panning), f); fread(&instrument_ext_hdr.vol_sustain, 1, sizeof(instrument_ext_hdr.vol_sustain), f); fread(&instrument_ext_hdr.vol_loop_start, 1, sizeof(instrument_ext_hdr.vol_loop_start), f); fread(&instrument_ext_hdr.vol_loop_end, 1, sizeof(instrument_ext_hdr.vol_loop_end), f); fread(&instrument_ext_hdr.pan_sustain, 1, sizeof(instrument_ext_hdr.pan_sustain), f); fread(&instrument_ext_hdr.pan_loop_start, 1, sizeof(instrument_ext_hdr.pan_loop_start), f); fread(&instrument_ext_hdr.pan_loop_end, 1, sizeof(instrument_ext_hdr.pan_loop_end), f); fread(&instrument_ext_hdr.vol_type, 1, sizeof(instrument_ext_hdr.vol_type), f); fread(&instrument_ext_hdr.pan_type, 1, sizeof(instrument_ext_hdr.pan_type), f); fread(&instrument_ext_hdr.vib_type, 1, sizeof(instrument_ext_hdr.vib_type), f); fread(&instrument_ext_hdr.vib_sweep, 1, sizeof(instrument_ext_hdr.vib_sweep), f); fread(&instrument_ext_hdr.vib_depth, 1, sizeof(instrument_ext_hdr.vib_depth), f); fread(&instrument_ext_hdr.vib_rate, 1, sizeof(instrument_ext_hdr.vib_rate), f); fread(&instrument_ext_hdr.vol_fadeout, 1, sizeof(instrument_ext_hdr.vol_fadeout), f); fread(&instrument_ext_hdr.reserved[0], 1, sizeof(instrument_ext_hdr.reserved), f); fseek(f, si + instrument_hdr.size, SEEK_SET); FIX_ENDIAN(instrument_ext_hdr.vol_fadeout); Uint32 first_length = 0, total_length = 0, type = 0; Sint32 fine = 0, loop_begin = 0, loop_len = 0; for (int s = 0 ; s < instrument_hdr.num_samples ; ++s) { struct { Uint32 sample_length; Uint32 sample_loop_start; Uint32 sample_loop_length; Uint8 volume; Sint8 finetune; Uint8 type; Uint8 panning; Uint8 relative_note; Uint8 reserved; char name[22]; } sample_hdr; fread(&sample_hdr.sample_length, 1, sizeof(sample_hdr.sample_length), f); fread(&sample_hdr.sample_loop_start, 1, sizeof(sample_hdr.sample_loop_start), f); fread(&sample_hdr.sample_loop_length, 1, sizeof(sample_hdr.sample_loop_length), f); fread(&sample_hdr.volume, 1, sizeof(sample_hdr.volume), f); fread(&sample_hdr.finetune, 1, sizeof(sample_hdr.finetune), f); fread(&sample_hdr.type, 1, sizeof(sample_hdr.type), f); fread(&sample_hdr.panning, 1, sizeof(sample_hdr.panning), f); fread(&sample_hdr.relative_note, 1, sizeof(sample_hdr.relative_note), f); fread(&sample_hdr.reserved, 1, sizeof(sample_hdr.reserved), f); fread(&sample_hdr.name[0], 1, sizeof(sample_hdr.name), f); FIX_ENDIAN(sample_hdr.sample_length); FIX_ENDIAN(sample_hdr.sample_loop_start); FIX_ENDIAN(sample_hdr.sample_loop_length); total_length += sample_hdr.sample_length; if (s > 0) continue; // read only first sample first_length = sample_hdr.sample_length; type = sample_hdr.type; mused.song.instrument[i].volume = sample_hdr.volume * 2; mused.song.instrument[i].base_note = MIDDLE_C + sample_hdr.relative_note; fine = sample_hdr.finetune; loop_begin = sample_hdr.sample_loop_start; loop_len = sample_hdr.sample_loop_length; } if (first_length > 0) { Sint8 *smp = malloc(first_length); fread(smp, 1, first_length, f); if (type & 16) { debug("16-bit sample"); int x = 0; for (int idx = 0 ; idx < first_length / 2 ; ++idx) { x += ((Uint16*)smp)[idx]; ((Uint16*)smp)[idx] = x; } cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[wt_e], smp, first_length / 2, CYD_WAVE_TYPE_SINT16, 1, 1, 1); } else { debug("8-bit sample"); int x = 0; for (int idx = 0 ; idx < first_length ; ++idx) { x += smp[idx]; smp[idx] = x; } cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[wt_e], smp, first_length, CYD_WAVE_TYPE_SINT8, 1, 1, 1); } free(smp); mused.mus.cyd->wavetable_entries[wt_e].loop_begin = loop_begin; mused.mus.cyd->wavetable_entries[wt_e].loop_end = loop_begin + loop_len; mused.mus.cyd->wavetable_entries[wt_e].loop_begin = my_min(mused.mus.cyd->wavetable_entries[wt_e].loop_begin, mused.mus.cyd->wavetable_entries[wt_e].samples - 1); mused.mus.cyd->wavetable_entries[wt_e].loop_end = my_min(mused.mus.cyd->wavetable_entries[wt_e].loop_end, mused.mus.cyd->wavetable_entries[wt_e].samples); mused.song.instrument[i].cydflags = CYD_CHN_ENABLE_WAVE | CYD_CHN_WAVE_OVERRIDE_ENV | CYD_CHN_ENABLE_KEY_SYNC; mused.song.instrument[i].flags = MUS_INST_SET_PW | MUS_INST_SET_CUTOFF; mused.song.instrument[i].vibrato_speed = instrument_ext_hdr.vib_rate; mused.song.instrument[i].vibrato_depth = instrument_ext_hdr.vib_depth; mused.song.instrument[i].vib_delay = instrument_ext_hdr.vib_sweep; // from mod.c mused.mus.cyd->wavetable_entries[wt_e].base_note = (MIDDLE_C << 8) - (Sint16)fine; mused.mus.cyd->wavetable_entries[wt_e].sample_rate = 7093789.2/856; switch (type & 3) { case 0: mused.mus.cyd->wavetable_entries[wt_e].flags &= ~CYD_WAVE_LOOP; break; case 1: mused.mus.cyd->wavetable_entries[wt_e].flags |= CYD_WAVE_LOOP; break; case 2: mused.mus.cyd->wavetable_entries[wt_e].flags |= CYD_WAVE_LOOP|CYD_WAVE_PINGPONG; break; } mused.song.instrument[i].wavetable_entry = wt_e++; strncpy(mused.song.instrument[i].name, instrument_hdr.name, 22); } fseek(f, total_length - first_length, SEEK_CUR); } else { fseek(f, si + instrument_hdr.size, SEEK_SET); } } int pos = 0; for (int s = 0 ; s < header.song_length ; ++s) { if (s == header.restart_position) mused.song.loop_point = pos; for (int c = 0 ; c < header.num_channels ; ++c) { add_sequence(c, pos, header.pattern_order[s] * header.num_channels + c, 0); } pos += pattern_length[header.pattern_order[s]]; } strncpy(mused.song.title, header.name, 20); mused.song.song_length = pos; mused.song.song_speed = mused.song.song_speed2 = header.default_tempo; mused.song.song_rate = header.default_bpm * 50 / 125; mused.song.num_channels = header.num_channels; mused.sequenceview_steps = 64; mused.song.num_patterns = header.num_patterns * header.num_channels; return 1; } klystrack-0.20171212/klystrack/src/import/org.c0000644000000000000000000002031013214501362017652 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "org.h" #include "edit.h" #include "mused.h" #include "event.h" #include "gui/toolutil.h" #include "SDL_endian.h" #include "snd/freqs.h" #include #include extern Mused mused; typedef struct { int n_samples; Uint32 sample_length; Sint8 *data; int n_drums; int drum_rate; struct { Uint32 length; Sint8 *data; } *drum; } orgsamp_t; int load_orgsamp(orgsamp_t *data) { FILE *f = open_dialog("rb", "Locate orgsamp.dat", "dat", domain, mused.slider_bevel, &mused.largefont, &mused.smallfont, "orgsamp.dat"); memset(data, 0, sizeof(*data)); if (f) { debug("Reading orgsamp.dat"); Uint8 temp8 = 0; Uint32 temp32 = 0; Uint16 temp16 = 0; fread(&temp8, 1, sizeof(temp8), f); data->n_samples = temp8; fread(&temp8, 1, 1, f); temp32 = temp8 << 16; fread(&temp8, 1, 1, f); temp32 |= temp8 << 8; fread(&temp8, 1, 1, f); temp32 |= temp8; data->sample_length = temp32; data->data = malloc(data->sample_length * data->n_samples); fread(data->data, 1, data->sample_length * data->n_samples, f); fread(&temp8, 1, sizeof(temp8), f); data->n_drums = temp8; data->drum = malloc(sizeof(data->drum[0]) * data->n_drums); fread(&temp16, 1, sizeof(temp16), f); data->drum_rate = SDL_SwapBE16(temp16); for (int i = 0 ; i < data->n_drums ; ++i) { fread(&temp8, 1, 1, f); temp32 = temp8 << 16; fread(&temp8, 1, 1, f); temp32 |= temp8 << 8; fread(&temp8, 1, 1, f); temp32 |= temp8; data->drum[i].length = temp32; data->drum[i].data = malloc(temp32); fread(data->drum[i].data, 1, data->drum[i].length, f); } fclose(f); return 1; } return 0; } void unload_orgsamp(orgsamp_t *data) { for (int i = 0 ; i < data->n_drums ; ++i) free(data->drum[i].data); free(data->drum); free(data->data); } int import_org(FILE *f) { struct { char sig[6]; // "Org-02" Uint16 tempo; Uint8 steps_per_bar; Uint8 beats_per_step; Uint32 loop_begin; Uint32 loop_end; } header; fread(&header.sig, 1, sizeof(header.sig), f); fread(&header.tempo, 1, sizeof(header.tempo), f); fread(&header.steps_per_bar, 1, sizeof(header.steps_per_bar), f); fread(&header.beats_per_step, 1, sizeof(header.beats_per_step), f); fread(&header.loop_begin, 1, sizeof(header.loop_begin), f); fread(&header.loop_end, 1, sizeof(header.loop_end), f); if (strncmp("Org-02", header.sig, 6) != 0 && strncmp("Org-03", header.sig, 6) != 0) { fatal("Not a Cave Story Organya song (sig: '%-6s')", header.sig); return 0; } FIX_ENDIAN(header.tempo); FIX_ENDIAN(header.loop_begin); FIX_ENDIAN(header.loop_end); mused.song.time_signature = (((Uint16)header.beats_per_step) << 8) | header.steps_per_bar; mused.time_signature = mused.song.time_signature; mused.song.song_length = header.loop_end + header.steps_per_bar; mused.song.loop_point = header.loop_begin; if (header.tempo > 0) mused.song.song_rate = my_min(255, (6 * 1000) / header.tempo); mused.sequenceview_steps = header.beats_per_step * header.steps_per_bar; mused.song.num_channels = 16; struct { Uint16 pitch; Uint8 instrument; Uint8 pi; Uint16 n_notes; } instrument[16]; for (int i = 0 ; i < 16 ; ++i) { fread(&instrument[i].pitch, 1, sizeof(instrument[i].pitch), f); fread(&instrument[i].instrument, 1, sizeof(instrument[i].instrument), f); fread(&instrument[i].pi, 1, sizeof(instrument[i].pi), f); fread(&instrument[i].n_notes, 1, sizeof(instrument[i].n_notes), f); FIX_ENDIAN(instrument[i].pitch); FIX_ENDIAN(instrument[i].n_notes); } orgsamp_t orgsamp; int orgsamp_loaded = load_orgsamp(&orgsamp); int real_channels = 0; for (int i = 0 ; i < 16 ; ++i) { if (instrument[i].n_notes) { mused.song.instrument[real_channels].cydflags = CYD_CHN_ENABLE_WAVE; mused.song.instrument[real_channels].adsr.a = 0; mused.song.instrument[real_channels].adsr.d = 0x1f; mused.song.instrument[real_channels].adsr.s = 0x1f; mused.song.instrument[real_channels].adsr.r = 1; mused.song.instrument[real_channels].flags = 0; mused.song.instrument[real_channels].wavetable_entry = real_channels; if (orgsamp_loaded) { CydWavetableEntry *e = &mused.mus.cyd->wavetable_entries[real_channels]; if (i < 8) { cyd_wave_entry_init(e, &orgsamp.data[instrument[i].instrument * orgsamp.sample_length], orgsamp.sample_length, CYD_WAVE_TYPE_SINT8, 1, 1, 1); e->flags |= CYD_WAVE_LOOP; e->loop_end = orgsamp.sample_length; e->sample_rate = (56320 * orgsamp.sample_length / 256); e->base_note = (MIDDLE_C - 3) * 256; sprintf(mused.song.instrument[real_channels].name, "Wave-%02d", instrument[i].instrument); } else { cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[real_channels], orgsamp.drum[instrument[i].instrument].data, orgsamp.drum[instrument[i].instrument].length, CYD_WAVE_TYPE_SINT8, 1, 1, 1); e->sample_rate = orgsamp.drum_rate * 20; e->base_note = (MIDDLE_C - 3) * 256; sprintf(mused.song.instrument[real_channels].name, "Drum-%02d", instrument[i].instrument); } } Uint32 *position = calloc(sizeof(Uint32), instrument[i].n_notes); Uint8 *note = calloc(sizeof(Uint8), instrument[i].n_notes), *length = calloc(sizeof(Uint8), instrument[i].n_notes), *volume = calloc(sizeof(Uint8), instrument[i].n_notes), *panning = calloc(sizeof(Uint8), instrument[i].n_notes); fread(position, sizeof(Uint32), instrument[i].n_notes, f); fread(note, sizeof(Uint8), instrument[i].n_notes, f); fread(length, sizeof(Uint8), instrument[i].n_notes, f); fread(volume, sizeof(Uint8), instrument[i].n_notes, f); fread(panning, sizeof(Uint8), instrument[i].n_notes, f); resize_pattern(&mused.song.pattern[i], header.loop_end); add_sequence(real_channels, 0, i, 0); Uint8 prev_vol = 0, prev_pan = CYD_PAN_CENTER; for (int n = 0 ; n < instrument[i].n_notes ; ++n) { if (position[n] >= header.loop_end) continue; MusStep *step = &mused.song.pattern[i].step[position[n]]; if (note[n] != 255) { step->note = note[n] + 12; step->instrument = real_channels; } if (volume[n] == 255) step->volume = prev_vol; else prev_vol = step->volume = (Uint16)volume[n] * 0x80 / 254; Uint8 pan = 0; if (panning[n] == 255) { pan = prev_pan; } else { pan = prev_pan = ((Uint16)panning[n]) * CYD_PAN_RIGHT / 0xc; } if (pan != CYD_PAN_CENTER) step->command = MUS_FX_SET_PANNING | pan; if (note[n] != 255 && length[n] && !instrument[i].pi && length[n] + position[n] < header.loop_end) { mused.song.pattern[i].step[length[n] + position[n]].note = MUS_NOTE_RELEASE; } } free(position); free(note); free(length); free(panning); ++real_channels; } } mused.song.num_channels = real_channels; if (orgsamp_loaded) unload_orgsamp(&orgsamp); return 1; } klystrack-0.20171212/klystrack/src/import/mod.h0000644000000000000000000000242513214501362017656 0ustar rootroot#ifndef MOD_H #define MOD_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (SDL_Surface *dest_surface, 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. */ #include #include "SDL.h" int import_mod(FILE *f); Uint16 find_command_pt(Uint16 command, int sample_length); #endif klystrack-0.20171212/klystrack/src/import/mod.c0000644000000000000000000002204213214501362017646 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "mod.h" #include "edit.h" #include "mused.h" #include "event.h" #include "SDL_endian.h" #include "snd/freqs.h" #include #include extern Mused mused; Uint16 find_command_pt(Uint16 command, int sample_length) { if ((command & 0xff00) == 0x0c00) command = MUS_FX_SET_VOLUME | ((command & 0xff) * 2); else if ((command & 0xff00) == 0x0a00) command = MUS_FX_FADE_VOLUME | (my_min(0xf, (command & 0x0f) * 2)) | (my_min(0xf, ((command & 0xf0) >> 4) * 2) << 4); else if ((command & 0xff00) == 0x0f00 && (command & 0xff) < 32) command = MUS_FX_SET_SPEED | my_min(0xf, (command & 0xff)); else if ((command & 0xff00) == 0x0f00 && (command & 0xff) >= 32) command = MUS_FX_SET_RATE | (((command & 0xff)) * 50 / 125); else if ((command & 0xff00) == 0x0100 || (command & 0xff00) == 0x0200 || (command & 0xff00) == 0x0300) command = (command & 0xff00) | my_min(0xff, (command & 0xff) * 8); else if ((command & 0xff00) == 0x0900 && sample_length) command = MUS_FX_WAVETABLE_OFFSET | ((Uint64)(command & 0xff) * 256 * 0x1000 / (Uint64)sample_length); else if ((command & 0xff00) == 0x0000 && (command & 0xff) != 0) command = MUS_FX_SET_EXT_ARP | (command & 0xff); else if ((command & 0xff00) != 0x0400 && (command & 0xff00) != 0x0000) command = 0; else if ((command & 0xfff0) == 0x0ec0) command = MUS_FX_EXT_NOTE_CUT | (command & 0xf); else if ((command & 0xfff0) == 0x0ed0) command = MUS_FX_EXT_NOTE_DELAY | (command & 0xf); else if ((command & 0xfff0) == 0x0e90) command = MUS_FX_EXT_RETRIGGER | (command & 0xf); else if ((command & 0xfff0) == 0x0e10) command = MUS_FX_EXT_PORTA_UP | (command & 0xf); else if ((command & 0xfff0) == 0x0e20) command = MUS_FX_EXT_PORTA_DN | (command & 0xf); else if ((command & 0xfff0) == 0x0ea0 || (command & 0xfff0) == 0x0eb0) command = ((command & 0xfff0) == 0x0ea0 ? 0x0eb0 : 0x0ea0) | (my_min(0xf, (command & 0x0f) * 2)); return command; } static Uint8 find_note(Uint16 period) { static const Uint16 periods[] = { 856,808,762,720,678,640,604,570,538,508,480,453, 428,404,381,360,339,320,302,285,269,254,240,226, 214,202,190,180,170,160,151,143,135,127,120,113, 0 }; if (period == 0) return MUS_NOTE_NONE; for (int i = 0 ; periods[i] ; ++i) if (periods[i] == period) return i + MIDDLE_C - 12; return MUS_NOTE_NONE; } int import_mod(FILE *f) { char ver[4]; fseek(f, 1080, SEEK_SET); fread(ver, 1, sizeof(ver), f); int channels = 0, instruments = 15; static const struct { int chn, inst; char *sig; } specs[] = { { 4, 31, "M.K." }, { 4, 31, "M!K!" }, { 4, 31, "FLT4" }, { 8, 31, "FLT8" }, { 4, 31, "4CHN" }, { 6, 31, "6CHN" }, { 8, 31, "8CHN" }, { 0 } }; for (int i = 0 ; specs[i].chn ; ++i) { if (strncmp(specs[i].sig, ver, 4) == 0) { channels = specs[i].chn; instruments = specs[i].inst; break; } } if (channels == 0) { warning("No file signature found: assuming Soundtracker format"); channels = 4; } fseek(f, 0, SEEK_SET); fread(mused.song.title, 20, sizeof(char), f); Uint16 sample_length[32], loop_begin[32], loop_len[32]; Sint8 fine[32]; int wt_e = 0; for (int i = 0 ; i < instruments ; ++i) { mused.song.instrument[i].flags = 0; char name[MUS_INSTRUMENT_NAME_LEN + 1] = { 0 }; fread(name, 1, 22, f); name[22] = '\0'; strcpy(mused.song.instrument[i].name, name); fread(&sample_length[i], 2, 1, f); fread(&fine[i], 1, 1, f); fine[i] = ((fine[i] & 0xf) << 4); sample_length[i] = SDL_SwapBE16(sample_length[i]) * 2; if (sample_length[i] > 1) { mused.song.instrument[i].cydflags = CYD_CHN_ENABLE_WAVE | CYD_CHN_WAVE_OVERRIDE_ENV | CYD_CHN_ENABLE_KEY_SYNC; mused.song.instrument[i].flags = MUS_INST_SET_PW | MUS_INST_SET_CUTOFF; mused.song.instrument[i].wavetable_entry = wt_e++; } fread(&mused.song.instrument[i].volume, 1, 1, f); mused.song.instrument[i].volume *= 2; fread(&loop_begin[i], 2, 1, f); fread(&loop_len[i], 2, 1, f); } Uint8 temp; fread(&temp, 1, sizeof(temp), f); mused.song.song_length = (Uint16)temp * 64; fread(&temp, 1, sizeof(temp), f); mused.song.loop_point = 0; //(Uint16)temp * 64; Uint8 sequence[128]; fread(sequence, 1, 128, f); if (instruments > 15) fseek(f, 4, SEEK_CUR); // skip id sig if not a soundtracker module int pat = 0; int patterns = 0; for (int i = 0 ; i * 64 < mused.song.song_length ; ++i) { patterns = my_max(patterns, sequence[i]); for (int c = 0 ; c < channels ; ++c) add_sequence(c, i * 64, sequence[i] * channels + c, 0); } int sl[32] = { 0 }, lp[32][16]; memset(lp, 0, sizeof(lp)); assert(32 >= channels); for (Uint8 i = 0 ; i <= patterns ; ++i) { for (int c = 0 ; c < channels ; ++c) { pat = i * channels + c; resize_pattern(&mused.song.pattern[pat], 64); memset(mused.song.pattern[pat].step, 0, sizeof(mused.song.pattern[pat].step[0]) * 64); } for (int s = 0 ; s < 64 ; ++s) { pat = i * channels; for (int c = 0 ; c < channels ; ++c) { Uint16 period; fread(&period, 1, sizeof(period), f); Uint8 inst, param; fread(&inst, 1, sizeof(inst), f); fread(¶m, 1, sizeof(param), f); mused.song.pattern[pat].step[s].note = find_note(SDL_SwapBE16(period) & 0xfff); mused.song.pattern[pat].step[s].instrument = ((inst >> 4) | ((SDL_SwapBE16(period) & 0xf000) >> 8)) - 1; mused.song.pattern[pat].step[s].volume = MUS_NOTE_NO_VOLUME; if (mused.song.pattern[pat].step[s].instrument != MUS_NOTE_NO_INSTRUMENT && mused.song.pattern[pat].step[s].instrument != 0) sl[c] = sample_length[mused.song.pattern[pat].step[s].instrument]; Uint8 command = inst & 0xf; if (command == 5) { command = 0xa; mused.song.pattern[pat].step[s].ctrl |= MUS_CTRL_SLIDE | MUS_CTRL_LEGATO; } if (command == 6) { command = 0xa; mused.song.pattern[pat].step[s].ctrl |= MUS_CTRL_VIB; } if (command != 0 && param != 0) lp[c][command] = param; mused.song.pattern[pat].step[s].command = find_command_pt(lp[c][command] | ((Uint16)command << 8), sl[c]); ++pat; } } } Sint8 *sample_data = malloc(65536 * sizeof(sample_data[0])); wt_e = 0; for (int i = 0 ; i < instruments ; ++i) { if (sample_length[i] > 1) { debug("Reading sample %d (%d bytes)", i, sample_length[i]); fread(sample_data, sample_length[i], 1, f); sample_data[0] = sample_data[1] = 0; cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[wt_e], sample_data, sample_length[i], CYD_WAVE_TYPE_SINT8, 1, 1, 1); mused.mus.cyd->wavetable_entries[wt_e].loop_begin = SDL_SwapBE16(loop_begin[i]) * 2; mused.mus.cyd->wavetable_entries[wt_e].loop_end = (SDL_SwapBE16(loop_begin[i]) + SDL_SwapBE16(loop_len[i])) * 2; mused.mus.cyd->wavetable_entries[wt_e].loop_begin = my_min(mused.mus.cyd->wavetable_entries[wt_e].loop_begin, mused.mus.cyd->wavetable_entries[wt_e].samples - 1); mused.mus.cyd->wavetable_entries[wt_e].loop_end = my_min(mused.mus.cyd->wavetable_entries[wt_e].loop_end, mused.mus.cyd->wavetable_entries[wt_e].samples); if (SDL_SwapBE16(loop_len[i]) > 1) { mused.mus.cyd->wavetable_entries[wt_e].flags |= CYD_WAVE_LOOP; } /* assuming PAL timing i.e. C-2 = 8287 Hz */ mused.mus.cyd->wavetable_entries[wt_e].base_note = (MIDDLE_C << 8) - ((Sint16)fine[i] << 1); mused.mus.cyd->wavetable_entries[wt_e].sample_rate = 7093789.2/856; ++wt_e; } } free(sample_data); mused.sequenceview_steps = 64; mused.song.num_patterns = patterns * channels; if (channels == 4) { // Amiga panning // not completely panned to left and right mused.song.default_panning[0] = -48; mused.song.default_panning[1] = 48; mused.song.default_panning[2] = 48; mused.song.default_panning[3] = -48; } return 1; } klystrack-0.20171212/klystrack/src/view/0000755000000000000000000000000013214501362016363 5ustar rootrootklystrack-0.20171212/klystrack/src/view/visu.h0000644000000000000000000000250613214501362017525 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "../view.h" void spectrum_analyzer_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void catometer_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); klystrack-0.20171212/klystrack/src/view/visu.c0000644000000000000000000001130313214501362017513 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "visu.h" #include "gui/bevel.h" #include "mybevdefs.h" #include "mused.h" #include "snd/freqs.h" #include "gfx/gfx.h" #include "theme.h" extern Uint32 colors[NUM_COLORS]; void spectrum_analyzer_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect content; copy_rect(&content, dest); SDL_Rect clip; gfx_domain_get_clip(domain, &clip); gfx_domain_set_clip(domain, &content); int spec[255] = { 0 }; for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { Uint8 note = (mused.stat_note[i] & 0xff00) >> 8; spec[note] = my_max(spec[note], mused.vis.cyd_env[i]); if (note > 0) spec[note - 1] = my_max(spec[note] / 3, spec[note - 1]); if (note < 255) spec[note + 1] = my_max(spec[note] / 3, spec[note + 1]); } for (int i = 0 ; i < 96 ; ++i) { if (spec[i] >= mused.vis.spec_peak[i]) mused.vis.spec_peak_decay[i] = 0; mused.vis.spec_peak_decay[i] = my_min(64, mused.vis.spec_peak_decay[i] + 1); mused.vis.spec_peak[i] = my_max(0, my_max(mused.vis.spec_peak[i], spec[i]) - my_min(1, my_max(0, /*mused.vis.spec_peak_decay[i] - 20*/ 2)) * 4); } const int w = mused.analyzer->surface->w / 2; SDL_Rect bar = {content.x, 0, w, 0}; SDL_Rect src = { 0, 0, w, content.h }; for (int i = (MIDDLE_C - content.w / w / 2 + 12) ; i < FREQ_TAB_SIZE && bar.x < content.x + content.w ; ++i, bar.x += bar.w) { if (i >= 0) { /*bar.h = mused.vis.spec_peak[i] * content.h / MAX_VOLUME; bar.y = content.y + content.h - bar.h; SDL_FillRect(mused.screen, &bar, 0x404040);*/ src.x = 0; src.y = 0; src.w = w; src.h = content.h; bar.h = content.h; bar.y = content.y; SDL_Rect temp; copy_rect(&temp, &bar); my_BlitSurface(mused.analyzer, &src, dest_surface, &temp); bar.h = my_min(MAX_VOLUME, mused.vis.spec_peak[i]) * content.h / MAX_VOLUME; bar.y = content.y + content.h - bar.h; src.h = my_min(MAX_VOLUME, mused.vis.spec_peak[i]) * content.h / MAX_VOLUME; src.y = mused.analyzer->surface->h - bar.h; src.h = bar.h; src.x = w; copy_rect(&temp, &bar); temp.y += 1; my_BlitSurface(mused.analyzer, &src, dest_surface, &temp); } } gfx_domain_set_clip(dest_surface, &clip); } void catometer_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect content; copy_rect(&content, dest); gfx_rect(dest_surface, &content, colors[COLOR_BACKGROUND]); SDL_Rect clip, cat; copy_rect(&cat, &content); cat.w = mused.catometer->surface->w; cat.x = cat.x + content.w / 2 - mused.catometer->surface->w / 2; gfx_domain_get_clip(domain, &clip); gfx_domain_set_clip(domain, &content); my_BlitSurface(mused.catometer, NULL, dest_surface, &cat); int v = 0; for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { v += mused.vis.cyd_env[i]; } float a = ((float)v * M_PI / (MAX_VOLUME * 4) + M_PI) * 0.25 + mused.vis.prev_a * 0.75; if (a < M_PI) a = M_PI; if (a > M_PI * 2) a = M_PI * 2; mused.vis.prev_a = a; int ax = cos(a) * 12; int ay = sin(a) * 12; int eye1 = 31; int eye2 = -30; for (int w = -3 ; w <= 3 ; ++w) { gfx_line(dest_surface, dest->x + dest->w / 2 + eye1 + w, dest->y + dest->h / 2 + 6, dest->x + dest->w / 2 + ax + eye1, dest->y + dest->h / 2 + ay + 6, colors[COLOR_CATOMETER_EYES]); gfx_line(dest_surface, dest->x + dest->w / 2 + eye2 + w, dest->y + dest->h / 2 + 6, dest->x + dest->w / 2 + ax + eye2, dest->y + dest->h / 2 + ay + 6, colors[COLOR_CATOMETER_EYES]); } gfx_domain_set_clip(dest_surface, &clip); } klystrack-0.20171212/klystrack/src/view/timer.h0000644000000000000000000000232013214501362017651 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "../view.h" void timer_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); klystrack-0.20171212/klystrack/src/view/wavetableview.c0000644000000000000000000005067413214501362021410 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "wavetableview.h" #include "../mused.h" #include "../view.h" #include "../event.h" #include "gui/mouse.h" #include "gui/dialog.h" #include "gui/bevel.h" #include "theme.h" #include "mybevdefs.h" #include "action.h" #include "wave_action.h" extern Mused mused; void wavetable_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect r, frame; copy_rect(&frame, dest); bevelex(domain, &frame, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&frame, 4); copy_rect(&r, &frame); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; { r.w = 64; r.h = 10; int d; r.w = 128; if ((d = generic_field(event, &r, EDITWAVETABLE, W_RATE, "RATE", "%6d Hz", MAKEPTR(w->sample_rate), 9)) != 0) { wave_add_param(d); } update_rect(&frame, &r); r.w = 72; r.h = 10; if ((d = generic_field(event, &r, EDITWAVETABLE, W_BASE, "BASE", "%s", notename((w->base_note + 0x80) >> 8), 3)) != 0) { wave_add_param(d); } update_rect(&frame, &r); r.w = 48; if ((d = generic_field(event, &r, EDITWAVETABLE, W_BASEFINE, "", "%+4d", MAKEPTR((Sint8)w->base_note), 4)) != 0) { wave_add_param(d); } r.w = 128; update_rect(&frame, &r); generic_flags(event, &r, EDITWAVETABLE, W_INTERPOLATE, "NO INTERPOLATION", &w->flags, CYD_WAVE_NO_INTERPOLATION); update_rect(&frame, &r); } my_separator(&frame, &r); { r.w = 80; generic_flags(event, &r, EDITWAVETABLE, W_LOOP, "LOOP", &w->flags, CYD_WAVE_LOOP); update_rect(&frame, &r); r.w = 112; int d; if ((d = generic_field(event, &r, EDITWAVETABLE, W_LOOPBEGIN, "BEGIN", "%7d", MAKEPTR(w->loop_begin), 7)) != 0) { wave_add_param(d); } update_rect(&frame, &r); r.w = 80; generic_flags(event, &r, EDITWAVETABLE, W_LOOPPINGPONG, "PINGPONG", &w->flags, CYD_WAVE_PINGPONG); update_rect(&frame, &r); r.w = 112; if ((d = generic_field(event, &r, EDITWAVETABLE, W_LOOPEND, "END", "%7d", MAKEPTR(w->loop_end), 7)) != 0) { wave_add_param(d); } update_rect(&frame, &r); } } void wavetablelist_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); const int chars = area.w / mused.console->font.w - 3; console_clear(mused.console); bevelex(dest_surface, &area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 3); console_set_clip(mused.console, &area); gfx_domain_set_clip(dest_surface, &area); int y = area.y; int start = mused.wavetable_list_position; for (int i = start ; i < CYD_WAVE_MAX_ENTRIES && y < area.h + area.y ; ++i, y += mused.console->font.h) { SDL_Rect row = { area.x - 1, y - 1, area.w + 2, mused.console->font.h + 1}; if (i == mused.selected_wavetable) { bevel(dest_surface, &row, mused.slider_bevel, BEV_SELECTED_PATTERN_ROW); console_set_color(mused.console, colors[COLOR_INSTRUMENT_SELECTED]); } else { console_set_color(mused.console, colors[COLOR_INSTRUMENT_NORMAL]); } const CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[i]; char temp[1000] = ""; if (w->samples > 0 || mused.song.wavetable_names[i][0]) snprintf(temp, chars, "%s (%u smp)", mused.song.wavetable_names[i][0] ? mused.song.wavetable_names[i] : "No name", w->samples); console_write_args(mused.console, "%02X %s\n", i, temp); check_event(event, &row, select_wavetable, MAKEPTR(i), 0, 0); slider_set_params(&mused.wavetable_list_slider_param, 0, CYD_WAVE_MAX_ENTRIES - 1, start, i, &mused.wavetable_list_position, 1, SLIDER_VERTICAL, mused.slider_bevel); } gfx_domain_set_clip(dest_surface, NULL); check_mouse_wheel_event(event, dest, &mused.wavetable_list_slider_param); } static void update_sample_preview(GfxDomain *dest, const SDL_Rect* area) { if (!mused.wavetable_preview || (mused.wavetable_preview->surface->w != area->w || mused.wavetable_preview->surface->h != area->h)) { if (mused.wavetable_preview) gfx_free_surface(mused.wavetable_preview); mused.wavetable_preview = gfx_create_surface(dest, area->w, area->h); } else if (mused.wavetable_preview_idx == mused.selected_wavetable) return; mused.wavetable_preview_idx = mused.selected_wavetable; SDL_FillRect(mused.wavetable_preview->surface, NULL, SDL_MapRGB(mused.wavetable_preview->surface->format, (colors[COLOR_WAVETABLE_BACKGROUND] >> 16) & 255, (colors[COLOR_WAVETABLE_BACKGROUND] >> 8) & 255, colors[COLOR_WAVETABLE_BACKGROUND] & 255)); const CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; mused.wavetable_bits = 0; if (w->samples > 0) { const int res = 4096; const int dadd = my_max(res, w->samples * res / area->w); const int gadd = my_max(res, (Uint32)area->w * res / w->samples); int c = 0, d = 0; for (int x = 0 ; x < area->w * res ; ) { int min = 32768; int max = -32768; for (; d < w->samples && c < dadd ; c += res, ++d) { min = my_min(min, w->data[d]); max = my_max(max, w->data[d]); mused.wavetable_bits |= w->data[d]; } c -= dadd; if (min < 0 && max < 0) max = 0; if (min > 0 && max > 0) min = 0; min = (32768 + min) * area->h / 65536; max = (32768 + max) * area->h / 65536 - min; int prev_x = x - 1; x += gadd; SDL_Rect r = { prev_x / res, min, my_max(1, x / res - prev_x / res), max + 1 }; SDL_FillRect(mused.wavetable_preview->surface, &r, SDL_MapRGB(mused.wavetable_preview->surface->format, (colors[COLOR_WAVETABLE_SAMPLE] >> 16) & 255, (colors[COLOR_WAVETABLE_SAMPLE] >> 8) & 255, colors[COLOR_WAVETABLE_SAMPLE] & 255)); } debug("Wavetable item bitmask = %x, lowest bit = %d", mused.wavetable_bits, __builtin_ffs(mused.wavetable_bits) - 1); set_info_message("Sample quality %d bits", 16 - (__builtin_ffs(mused.wavetable_bits) - 1)); } gfx_update_texture(dest, mused.wavetable_preview); } void wavetable_sample_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); bevelex(domain, &area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 3); update_sample_preview(dest_surface, &area); my_BlitSurface(mused.wavetable_preview, NULL, dest_surface, &area); int mx, my; if (mused.mode == EDITWAVETABLE && (SDL_GetMouseState(&mx, &my) & SDL_BUTTON(1))) { mx /= mused.pixel_scale; my /= mused.pixel_scale; if (mused.prev_wavetable_x == -1) { mused.prev_wavetable_x = mx; mused.prev_wavetable_y = my; } int dx; int d = abs(mx - mused.prev_wavetable_x); if (mx < mused.prev_wavetable_x) dx = 1; else dx = -1; if (mx >= area.x && my >= area.y && mx < area.x + area.w && my < area.y + area.h) { if (d > 0) { for (int x = mx, i = 0 ; i <= d ; x += dx, ++i) wavetable_draw((float)(x - area.x) / area.w, (float)((my + (mused.prev_wavetable_y - my) * i / d) - area.y) / area.h, 1.0f / area.w); } else wavetable_draw((float)(mx - area.x) / area.w, (float)(my - area.y) / area.h, 1.0f / area.w); } mused.prev_wavetable_x = mx; mused.prev_wavetable_y = my; } else { mused.prev_wavetable_x = -1; mused.prev_wavetable_y = -1; } } void invalidate_wavetable_view() { mused.wavetable_preview_idx = -1; mused.wavetable_bits = 0; } void wavetable_tools_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect r, frame; copy_rect(&frame, dest); bevelex(domain, &frame, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&frame, 4); copy_rect(&r, &frame); r.h = 12; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "DROP LOWEST BIT", wavetable_drop_lowest_bit, NULL, NULL, NULL); r.y += r.h; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "HALVE RATE", wavetable_halve_samplerate, NULL, NULL, NULL); r.y += r.h; { int temp_x = r.x; int temp = r.w; r.w /= 2; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "NORMALIZE", wavetable_normalize, MAKEPTR(32768), NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "DISTORT", wavetable_distort, MAKEPTR((int)(0.891 * 32768)), NULL, NULL); r.y += r.h; r.x = temp_x; r.w = temp; } { int temp_x = r.x; int temp = r.w; r.w /= 2; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "+1 dB", wavetable_amp, MAKEPTR((int)(1.122 * 32768)), NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "-1 dB", wavetable_amp, MAKEPTR((int)(0.891 * 32768)), NULL, NULL); r.y += r.h; r.x = temp_x; r.w = temp; } { int temp_x = r.x; int temp = r.w; r.w /= 2; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "CUT TAIL", wavetable_cut_tail, NULL, NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "CUT HEAD", wavetable_cut_head, NULL, NULL, NULL); r.y += r.h; r.x = temp_x; r.w = temp; } { int temp_x = r.x; int temp = r.w; r.w /= 2; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "KILL DC", wavetable_remove_dc, 0, NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "FIND ZERO", wavetable_find_zero, NULL, NULL, NULL); r.y += r.h; r.x = temp_x; r.w = temp; } { int temp_x = r.x; int temp = r.w; r.w /= 2; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "LOPASS", wavetable_filter, MAKEPTR(0), NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "HIPASS", wavetable_filter, MAKEPTR(1), NULL, NULL); r.y += r.h; r.x = temp_x; r.w = temp; } button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "5TH", wavetable_chord, MAKEPTR(5), NULL, NULL); r.y += r.h; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "OCTAVE", wavetable_chord, MAKEPTR(12), NULL, NULL); r.y += r.h; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "WAVEGEN", flip_bit_action, &mused.flags, MAKEPTR(SHOW_WAVEGEN), NULL); if (!(mused.flags & SHOW_WAVEGEN) && mused.wavetable_param >= W_NUMOSCS && mused.wavetable_param <= W_TOOLBOX) { mused.wavetable_param = W_NUMOSCS - 1; } } void oscillator_view(GfxDomain *domain, const SDL_Rect *dest, const SDL_Event *event, void *param) { WgOsc *osc = param; SDL_Rect frame; copy_rect(&frame, dest); int bev = BEV_THIN_FRAME; if (osc == &mused.wgset.chain[mused.selected_wg_osc]) bev = BEV_EDIT_CURSOR; bevelex(domain, &frame, mused.slider_bevel, bev, BEV_F_STRETCH_ALL); adjust_rect(&frame, 2); gfx_rect(domain, &frame, colors[COLOR_WAVETABLE_BACKGROUND]); wg_init_osc(osc); float py = wg_osc(osc, 0); for (int x = 1 ; x < frame.w ; ++x) { float y = wg_osc(osc, (float)x / frame.w); gfx_line(domain, frame.x + x - 1, py * frame.h / 2 + frame.y + frame.h / 2, frame.x + x, y * frame.h / 2 + frame.y + frame.h / 2, colors[COLOR_WAVETABLE_SAMPLE]); py = y; } } void wavegen_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect r, frame; copy_rect(&frame, dest); bevelex(domain, &frame, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&frame, 4); copy_rect(&r, &frame); r.h = 10; int d; static WgPreset presets[] = { {"OPL2 0", {{ {WG_OSC_SINE, WG_OP_ADD, 1, 0, 50, 0, 0} }, 1}}, {"OPL2 1", {{ {WG_OSC_SINE, WG_OP_MUL, 1, 0, 50, 0, 0}, {WG_OSC_SQUARE, WG_OP_MUL, 1, 0, 50, 0, WG_OSC_FLAG_ABS} }, 2}}, {"OPL2 2", {{ {WG_OSC_SINE, WG_OP_MUL, 1, 0, 50, 0, 0}, {WG_OSC_SQUARE, WG_OP_MUL, 1, 0, 50, 0, 0} }, 2}}, {"OPL2 3", {{ {WG_OSC_SINE, WG_OP_MUL, 1, 0, 50, 0, 0}, {WG_OSC_SQUARE, WG_OP_MUL, 2, 0, 50, 0, WG_OSC_FLAG_ABS}, {WG_OSC_SQUARE, WG_OP_MUL, 1, 0, 50, 0, 0} }, 3}}, {"OPL3 4", {{ {WG_OSC_SINE, WG_OP_MUL, 2, 0, 50, 0, 0}, {WG_OSC_SQUARE, WG_OP_MUL, 1, 0, 50, 0, WG_OSC_FLAG_ABS} }, 2}}, {"OPL3 5", {{ {WG_OSC_SINE, WG_OP_MUL, 2, 0, 50, 0, 0}, {WG_OSC_SQUARE, WG_OP_MUL, 2, 0, 50, 0, 0}, {WG_OSC_SQUARE, WG_OP_MUL, 1, 0, 50, 0, WG_OSC_FLAG_ABS} }, 3}}, {"OPL3 6", {{ {WG_OSC_SQUARE, WG_OP_MUL, 1, 0, 50, 0, 0}}, 1}}, }; { SDL_Rect button; copy_rect(&button, &r); button.w = 38; button_text_event(domain, event, &button, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "LOAD", wavegen_preset, &presets[mused.selected_wg_preset], &mused.wgset, NULL); } if ((d = generic_field(event, &r, EDITWAVETABLE, -1, "", "%s", (char*)presets[mused.selected_wg_preset].name, 10)) != 0) { mused.selected_wg_preset += d; if (mused.selected_wg_preset < 0) mused.selected_wg_preset = 0; else if (mused.selected_wg_preset >= sizeof(presets) / sizeof(presets[0])) mused.selected_wg_preset = sizeof(presets) / sizeof(presets[0]) - 1; } r.y += r.h + 2; if ((d = generic_field(event, &r, EDITWAVETABLE, W_NUMOSCS, "OSCS", "%d", MAKEPTR(mused.wgset.num_oscs), 3)) != 0) { wave_add_param(d); } r.y += r.h + 2; int active_oscs = mused.wgset.num_oscs; for (int i = 0 ; i < active_oscs ; ++i) { WgOsc *osc = &mused.wgset.chain[i]; copy_rect(&r, &frame); r.y += 24; r.w = frame.w / active_oscs - 2; r.x = frame.x + (r.w + 2) * i; r.h = 32; oscillator_view(dest_surface, &r, event, osc); if (check_event(event, &r, NULL, 0, 0, 0)) mused.selected_wg_osc = i; } for (int i = 0 ; i < active_oscs ; ++i) { WgOsc *osc = &mused.wgset.chain[i]; SDL_Rect r; copy_rect(&r, &frame); r.y += 34; r.w = 12; r.x = frame.x + (frame.w / active_oscs) * i + (frame.w / active_oscs) - 8; r.h = 12; const char *op[] = {"+", "x"}; if (i < active_oscs - 1 && button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, op[osc->op], NULL, NULL, NULL, NULL) & 1) osc->op = (osc->op + 1) % WG_NUM_OPS; } WgOsc *osc = &mused.wgset.chain[mused.selected_wg_osc]; r.y += r.h; r.x = frame.x; int row_begin = r.x; r.w = frame.w / 2 - 2; r.h = 10; if ((d = generic_field(event, &r, EDITWAVETABLE, W_OSCTYPE, "TYPE", "%d", MAKEPTR(osc->osc), 1)) != 0) { wave_add_param(d); } r.x += r.w + 4; if ((d = generic_field(event, &r, EDITWAVETABLE, W_OSCMUL, "MUL", "%d", MAKEPTR(osc->mult), 1)) != 0) { wave_add_param(d); } r.x = row_begin; r.y += r.h; if ((d = generic_field(event, &r, EDITWAVETABLE, W_OSCSHIFT, "SHIFT", "%d", MAKEPTR(osc->shift), 1)) != 0) { wave_add_param(d); } r.x += r.w + 4; if ((d = generic_field(event, &r, EDITWAVETABLE, W_OSCEXP, "EXP", ".%02u", MAKEPTR(osc->exp), 3)) != 0) { wave_add_param(d); } r.x = row_begin; r.y += r.h; generic_flags(event, &r, EDITWAVETABLE, W_OSCABS, "ABS", &osc->flags, WG_OSC_FLAG_ABS); r.x += r.w + 4; generic_flags(event, &r, EDITWAVETABLE, W_OSCNEG, "NEG", &osc->flags, WG_OSC_FLAG_NEG); r.x = row_begin; r.y += r.h; r.x = frame.x; r.w = frame.w - 2; r.h = 10; if ((d = generic_field(event, &r, EDITWAVETABLE, W_WAVELENGTH, "LENGTH", "%5d", MAKEPTR(mused.wgset.length), 5)) != 0) { wave_add_param(d); } r.y += r.h + 2; r.w = r.w / 2; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "RND+GEN", wavetable_randomize_and_create_one_cycle, &mused.wgset, NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "GENERATE", wavetable_create_one_cycle, &mused.wgset, NULL, NULL); r.y += r.h; r.x -= r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "RND", wavegen_randomize, &mused.wgset, NULL, NULL); r.x += r.w; button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "TOOLBOX", flip_bit_action, &mused.flags, MAKEPTR(SHOW_WAVEGEN), NULL); } void wavetable_edit_area(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { if (mused.flags & SHOW_WAVEGEN) wavegen_view(dest_surface, dest, event, param); else wavetable_tools_view(dest_surface, dest, event, param); } void wavegen_preview(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); bevelex(domain, &area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 3); float py = wg_get_sample(mused.wgset.chain, mused.wgset.num_oscs, 0); if (py > 1.0) py = 1.0; else if (py < -1.0) py = -1.0; for (int x = 1 ; x < area.w ; ++x) { float y = wg_get_sample(mused.wgset.chain, mused.wgset.num_oscs, (float)x / area.w); if (y > 1.0) y = 1.0; else if (y < -1.0) y = -1.0; gfx_line(domain, area.x + x - 1, py * area.h / 2 + area.y + area.h / 2, area.x + x, y * area.h / 2 + area.y + area.h / 2, colors[COLOR_WAVETABLE_SAMPLE]); py = y; } } void wavetable_sample_area(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { if (mused.flags & SHOW_WAVEGEN) wavegen_preview(dest_surface, dest, event, param); else wavetable_sample_view(dest_surface, dest, event, param); } void wavetable_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect farea, larea, tarea; copy_rect(&farea,dest); copy_rect(&larea,dest); copy_rect(&tarea,dest); farea.w = 2 * mused.console->font.w + 2 + 16; larea.w = 32; label("WAVE", &larea); tarea.w = dest->w - farea.w - larea.w - 1; farea.x = larea.w + dest->x; tarea.x = farea.x + farea.w; int d; if ((d = generic_field(event, &farea, EDITWAVETABLE, W_WAVE, "WAVE", "%02X", MAKEPTR(mused.selected_wavetable), 2)) != 0) { wave_add_param(d); } inst_field(event, &tarea, W_NAME, MUS_WAVETABLE_NAME_LEN + 1, mused.song.wavetable_names[mused.selected_wavetable]); if (is_selected_param(EDITWAVETABLE, W_NAME) || (mused.mode == EDITWAVETABLE && (mused.edit_buffer == mused.song.wavetable_names[mused.selected_wavetable] && mused.focus == EDITBUFFER))) { SDL_Rect r; copy_rect(&r, &tarea); adjust_rect(&r, -2); set_cursor(&r); } } klystrack-0.20171212/klystrack/src/view/sequence.c0000644000000000000000000002163013214501362020341 0ustar rootroot#include "sequence.h" #include "../mused.h" #include "gui/bevel.h" #include "../mybevdefs.h" #include "action.h" #include "gui/mouse.h" #define RGB(r,g,b) ((r << 16) | (g << 8) | (b)) Uint32 pattern_color[16] = { RGB(255,255,255), RGB(255,0,0), RGB(255,130,0), RGB(223,227,0), RGB(130,255,0), RGB(0,255, 0), RGB(0, 227, 130), RGB(0, 255,255), RGB(0,130,255), RGB(0,0,255), RGB(130,0,255), RGB(255,0,255), RGB(239,0,130),RGB(196,196,196), RGB(130,130,130), RGB(85,85,85) }; void sequence_view_inner(GfxDomain *dest_surface, const SDL_Rect *_dest, const SDL_Event *event) { SDL_Rect dest; copy_rect(&dest, _dest); bevelex(dest_surface, _dest, mused.slider_bevel, BEV_SEQUENCE_BORDER, BEV_F_STRETCH_ALL); const int height = 10; const int top = mused.sequence_position; const int w = my_max(dest.w / mused.song.num_channels - 1, (mused.flags & SHOW_PATTERN_POS_OFFSET) ? 40 : 24); int h = dest.h; const int bottom = top + h * mused.sequenceview_steps / height - 1; if (mused.song.num_channels * (w + 1) > dest.w) h -= SCROLLBAR; if (mused.current_sequencepos >= top && mused.current_sequencepos < bottom) { SDL_Rect sel = {dest.x, dest.y + (mused.current_sequencepos * height / mused.sequenceview_steps - top * height / mused.sequenceview_steps) + 1, dest.w, height}; clip_rect(&sel, &dest); gfx_domain_set_clip(domain, &sel); bevelex(dest_surface, &sel, mused.slider_bevel, BEV_SELECTED_SEQUENCE_ROW, BEV_F_STRETCH_ALL); } slider_set_params(&mused.sequence_slider_param, 0, mused.song.song_length - mused.sequenceview_steps, my_max(0, top), (bottom / mused.sequenceview_steps - 1) * mused.sequenceview_steps, &mused.sequence_position, mused.sequenceview_steps, SLIDER_VERTICAL, mused.slider_bevel); int vischans = my_min(mused.song.num_channels - 1, mused.sequence_horiz_position + (dest.w - (w - 1)) / (w + 1)); slider_set_params(&mused.sequence_horiz_slider_param, 0, mused.song.num_channels - 1, mused.sequence_horiz_position, vischans, &mused.sequence_horiz_position, 1, SLIDER_HORIZONTAL, mused.slider_bevel); SDL_Rect clip2, textclip; copy_rect(&clip2, &dest); copy_rect(&textclip, &dest); clip2.h += 8; clip2.y -= 4; textclip.y += 1; textclip.h -= 1; for (int channel = mused.sequence_horiz_position ; channel < mused.song.num_channels && channel <= vischans ; ++channel) { const MusSeqPattern *sp = &mused.song.sequence[channel][0]; const int x = (channel - mused.sequence_horiz_position) * (w + 1); for (int i = 0 ; i < mused.song.num_sequences[channel] ; ++i, ++sp) { if (sp->position >= bottom) break; int len = mused.song.pattern[sp->pattern].num_steps; if (i < mused.song.num_sequences[channel] - 1) len = my_min(len, (sp + 1)->position - sp->position); if (sp->position + len < top) continue; SDL_Rect pat = { x + dest.x + 1, (sp->position - top) * height / mused.sequenceview_steps + dest.y + 1, w, len * height / mused.sequenceview_steps }; SDL_Rect text; copy_rect(&text, &pat); clip_rect(&text, &textclip); gfx_domain_set_clip(domain, &dest); int bev = (mused.current_sequencetrack == channel && mused.current_sequencepos >= sp->position && mused.current_sequencepos < sp->position + len) ? BEV_PATTERN_CURRENT : BEV_PATTERN; clip_rect(&pat, &clip2); gfx_surface_set_color(mused.slider_bevel, pattern_color[mused.song.pattern[sp->pattern].color]); bevelex(dest_surface, &pat, mused.slider_bevel, bev, BEV_F_STRETCH_ALL); adjust_rect(&text, 2); text.h += 1; gfx_domain_set_clip(domain, &text); if (mused.flags & SHOW_PATTERN_POS_OFFSET) font_write_args(&mused.tinyfont_sequence_normal, dest_surface, &text, "%02X%+d +%02x", sp->pattern, sp->note_offset, sp->position % mused.sequenceview_steps); else font_write_args(&mused.tinyfont_sequence_normal, dest_surface, &text, "%02X%+d", sp->pattern, sp->note_offset); } int y = dest.y; for (int i = top ; i < bottom ; i += mused.sequenceview_steps, y+=height) { SDL_Rect pos = { dest.x + x, y, w, height }; clip_rect(&pos, &dest); check_event(event, &pos, select_sequence_position, MAKEPTR(channel), MAKEPTR(i), 0); } } gfx_surface_set_color(mused.slider_bevel, 0xffffff); gfx_domain_set_clip(domain, &dest); SDL_Rect loop = { dest.x, (mused.song.loop_point - top) * height / mused.sequenceview_steps + dest.y + 1, dest.w, (mused.song.song_length - mused.song.loop_point) * height / mused.sequenceview_steps }; bevel(dest_surface, &loop, mused.slider_bevel, BEV_SEQUENCE_LOOP); if (mused.focus == EDITSEQUENCE) { if (mused.current_sequencepos >= top && mused.current_sequencepos < bottom && mused.current_sequencetrack >= mused.sequence_horiz_position && mused.current_sequencetrack <= vischans) { if (mused.flags & EDIT_SEQUENCE_DIGITS) { SDL_Rect pat = { (mused.current_sequencetrack - mused.sequence_horiz_position) * (w + 1) + dest.x, (mused.current_sequencepos - top) * height / mused.sequenceview_steps + dest.y, mused.tinyfont.w, mused.tinyfont.h }; pat.x += mused.sequence_digit * pat.w; clip_rect(&pat, &dest); adjust_rect(&pat, -3); pat.x += 3; pat.y += 3; pat.w -= 1; pat.h -= 1; set_cursor(&pat); } else { SDL_Rect pat = { (mused.current_sequencetrack - mused.sequence_horiz_position) * (w + 1) + dest.x, (mused.current_sequencepos - top) * height / mused.sequenceview_steps + dest.y, w, height }; clip_rect(&pat, &dest); adjust_rect(&pat, -2); pat.x += 1; pat.y += 1; set_cursor(&pat); } } else { set_cursor(NULL); } if (mused.selection.start != mused.selection.end) { if (mused.selection.start <= bottom && mused.selection.end >= top) { SDL_Rect selection = { dest.x + (w + 1) * (mused.current_sequencetrack - mused.sequence_horiz_position), dest.y + height * (mused.selection.start - mused.sequence_position) / mused.sequenceview_steps, w, height * (mused.selection.end - mused.selection.start) / mused.sequenceview_steps}; adjust_rect(&selection, -3); bevel(dest_surface, &selection, mused.slider_bevel, BEV_SELECTION); } } } if (mused.flags & SONG_PLAYING) { SDL_Rect play = { dest.x, (mused.stat_song_position - top) * height / mused.sequenceview_steps + dest.y, dest.w, 2 }; clip_rect(&play, &dest); bevelex(dest_surface, &play, mused.slider_bevel, BEV_SEQUENCE_PLAY_POS, BEV_F_STRETCH_ALL); } gfx_domain_set_clip(domain, NULL); if (event->type == SDL_MOUSEBUTTONDOWN && mused.focus == EDITSEQUENCE) { switch (event->button.button) { case 4: mused.sequence_position -= mused.sequenceview_steps; break; case 5: mused.sequence_position += mused.sequenceview_steps; break; } mused.sequence_position = my_max(0, my_min(mused.song.song_length - mused.sequenceview_steps, mused.sequence_position)); } } static void sequence_view_stepcounter(GfxDomain *dest_surface, const SDL_Rect *_dest, const SDL_Event *event) { const int height = 10; const int top = mused.sequence_position; gfx_domain_set_clip(domain, _dest); bevelex(dest_surface, _dest, mused.slider_bevel, BEV_SEQUENCE_BORDER, BEV_F_STRETCH_ALL); SDL_Rect dest; copy_rect(&dest, _dest); adjust_rect(&dest, 1); dest.w += 1; SDL_Rect pos = { dest.x + 1, dest.y + 2, dest.w, height }; if (mused.current_sequencepos >= top) { SDL_Rect sel = { dest.x + 1, dest.y + 2 + (mused.current_sequencepos - top) * height / mused.sequenceview_steps , dest.w, height }; sel.x -= 1; sel.y -= 2; gfx_domain_set_clip(domain, &sel); bevel(dest_surface, &sel, mused.slider_bevel, BEV_SELECTED_SEQUENCE_ROW); } for (int p = top ; pos.y < dest.y + dest.h ; p += mused.sequenceview_steps, pos.y += height) { clip_rect(&pos, &dest); gfx_domain_set_clip(domain, &pos); if (SHOW_DECIMALS & mused.flags) font_write_args(&mused.tinyfont_sequence_counter, dest_surface, &pos, "%04d", p % 10000); else font_write_args(&mused.tinyfont_sequence_counter, dest_surface, &pos, "%04X", p & 0xffff); } gfx_domain_set_clip(domain, NULL); } void sequence_view2(GfxDomain *dest_surface, const SDL_Rect *_dest, const SDL_Event *event, void *param) { SDL_Rect seq, pos; copy_rect(&seq, _dest); copy_rect(&pos, _dest); seq.w -= mused.tinyfont.w * 4 + 4; seq.x += mused.tinyfont.w * 4 + 4; pos.w = mused.tinyfont.w * 4 + 4; sequence_view_stepcounter(dest_surface, &pos, event); sequence_view_inner(dest_surface, &seq, event); const int w = my_max(_dest->w / mused.song.num_channels - 1, 64); if (mused.song.num_channels * (w + 1) > _dest->w) { SDL_Rect scrollbar = { _dest->x, _dest->y + _dest->h - SCROLLBAR, _dest->w, SCROLLBAR }; slider(dest_surface, &scrollbar, event, &mused.sequence_horiz_slider_param); } } klystrack-0.20171212/klystrack/src/view/wavetableview.h0000644000000000000000000000374513214501362021412 0ustar rootroot#ifndef WAVETABLEVIEW_H #define WAVETABLEVIEW_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gfx/gfx.h" void wavetable_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void wavetablelist_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void wavetable_sample_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void wavetable_tools_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void wavetable_edit_area(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void wavetable_sample_area(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void wavetable_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void invalidate_wavetable_view(); #endif klystrack-0.20171212/klystrack/src/view/pattern.c0000644000000000000000000005176013214501362020215 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "../view.h" #include "../event.h" #include "../mused.h" #include "../action.h" #include "../diskop.h" #include "gui/mouse.h" #include "gui/dialog.h" #include "gui/bevel.h" #include "../theme.h" #include "../mybevdefs.h" #include "snd/freqs.h" #include #include "sequence.h" #define HEADER_HEIGHT 12 const struct { bool margin; int w; int id; } pattern_params[] = { {false, 3, PED_NOTE}, {true, 1, PED_INSTRUMENT1}, {false, 1, PED_INSTRUMENT2}, {true, 1, PED_VOLUME1}, {false, 1, PED_VOLUME2}, {true, 1, PED_LEGATO}, {false, 1, PED_SLIDE}, {false, 1, PED_VIB}, {true, 1, PED_COMMAND1}, {false, 1, PED_COMMAND2}, {false, 1, PED_COMMAND3}, {false, 1, PED_COMMAND4}, }; #define selrow(sel, nor) ((current_patternstep() == i) ? (sel) : (nor)) #define diszero(e, c) ((!(e)) ? mix_colors(c, colors[COLOR_PATTERN_EMPTY_DATA]) : c) void pattern_view_header(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, int channel) { bevelex(dest_surface, dest, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); SDL_Rect area; copy_rect(&area, dest); adjust_rect(&area, 3); font_write_args(&mused.smallfont, dest_surface, &area, "%02d", channel); SDL_Rect mute; { copy_rect(&mute, dest); mute.w = dest->h; mute.x = dest->x + dest->w - mute.w; void *action = enable_channel; if (SDL_GetModState() & KMOD_SHIFT) action = solo_channel; button_event(dest_surface, event, &mute, mused.slider_bevel, (mused.mus.channel[channel].flags & MUS_CHN_DISABLED) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, (mused.mus.channel[channel].flags & MUS_CHN_DISABLED) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, (mused.mus.channel[channel].flags & MUS_CHN_DISABLED) ? DECAL_AUDIO_DISABLED : DECAL_AUDIO_ENABLED, action, MAKEPTR(channel), 0, 0); } if (!(mused.flags & COMPACT_VIEW) && (!(mused.flags & EXPAND_ONLY_CURRENT_TRACK) || channel == mused.current_sequencetrack)) { SDL_Rect vol; copy_rect(&vol, &mute); const int pan_w = 42; vol.x -= vol.w + 3 + 17; vol.x -= pan_w * 2 + 3 + 12; vol.w = pan_w; vol.h -= 1; vol.y += 1; int d; int _current_pattern = current_pattern_for_channel(channel); if (_current_pattern != -1) { if ((d = generic_field(event, &vol, 96, channel, "", "", NULL, 1))) { snapshot_cascade(S_T_SONGINFO, 96, channel); mused.song.pattern[_current_pattern].color = my_max(0, my_min(15, (int)mused.song.pattern[_current_pattern].color + d)); } { SDL_Rect bar; copy_rect(&bar, &vol); bar.w = 8; bar.h = 8; bar.x += vol.w - 24 - 1; bar.y += 1; gfx_rect(dest_surface, &bar, pattern_color[mused.song.pattern[_current_pattern].color]); } } vol.x += vol.w + 2; char tmp[4]="\xfa\xf9"; if (mused.song.default_panning[channel]) snprintf(tmp, sizeof(tmp), "%c%X", mused.song.default_panning[channel] < 0 ? '\xf9' : '\xfa', mused.song.default_panning[channel] == 63 ? 8 : ((abs((int)mused.song.default_panning[channel]) >> 3) & 0xf)); if ((d = generic_field(event, &vol, 97, channel, "P", "%s", tmp, 2))) { snapshot_cascade(S_T_SONGINFO, 97, channel); mused.song.default_panning[channel] = my_max(-64, my_min(63, (int)mused.song.default_panning[channel] + d * 8)); if (abs(mused.song.default_panning[channel]) < 8) mused.song.default_panning[channel] = 0; } vol.x += vol.w + 2; if ((d = generic_field(event, &vol, 98, channel, "V", "%02X", MAKEPTR(mused.song.default_volume[channel]), 2))) { snapshot_cascade(S_T_SONGINFO, 98, channel); mused.song.default_volume[channel] = my_max(0, my_min(MAX_VOLUME, (int)mused.song.default_volume[channel] + d)); } } } void pattern_view_inner(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event) { gfx_domain_set_clip(dest_surface, dest); const int height = 8; const int top = mused.pattern_position - dest->h / height / 2; const int bottom = top + dest->h / height; SDL_Rect row; copy_rect(&row, dest); adjust_rect(&row, 1); gfx_rect(dest_surface, &row, colors[COLOR_BACKGROUND]); row.y = (bottom - top) / 2 * height + row.y + 2 + HEADER_HEIGHT; row.h = height + 1; bevelex(dest_surface, &row, mused.slider_bevel, BEV_SELECTED_PATTERN_ROW, BEV_F_STRETCH_ALL); slider_set_params(&mused.pattern_slider_param, 0, mused.song.song_length - 1, mused.pattern_position, mused.pattern_position, &mused.pattern_position, 1, SLIDER_VERTICAL, mused.slider_bevel); const int char_width = mused.largefont.w; int w = 2 * char_width + 4 + 4; int narrow_w = 2 * char_width + 4 + 4; const int SPACER = 4; for (int param = PED_NOTE ; param < PED_PARAMS ; ++param) { if (param == PED_NOTE || viscol(param)) w += pattern_params[param].w * char_width; if (param == PED_NOTE) narrow_w += pattern_params[param].w * char_width; if (pattern_params[param].margin && param < PED_PARAMS - 1 && viscol(param + 1)) { w += SPACER; if (param == PED_NOTE) narrow_w += SPACER; } } if (!(mused.flags & EXPAND_ONLY_CURRENT_TRACK)) narrow_w = w; slider_set_params(&mused.pattern_horiz_slider_param, 0, mused.song.num_channels - 1, mused.pattern_horiz_position, my_min(mused.song.num_channels, mused.pattern_horiz_position + 1 + (dest->w - w) / narrow_w) - 1, &mused.pattern_horiz_position, 1, SLIDER_HORIZONTAL, mused.slider_bevel); int x = 0; for (int channel = mused.pattern_horiz_position ; channel < mused.song.num_channels && x < dest->w ; x += ((channel == mused.current_sequencetrack) ? w : narrow_w), ++channel) { const MusSeqPattern *sp = &mused.song.sequence[channel][0]; SDL_Rect track; copy_rect(&track, dest); track.w = ((channel == mused.current_sequencetrack) ? w : narrow_w) + 2; track.x += x; gfx_domain_set_clip(dest_surface, NULL); SDL_Rect header; copy_rect(&header, &track); header.h = HEADER_HEIGHT; header.w -= 2; pattern_view_header(dest_surface, &header, event, channel); track.h -= HEADER_HEIGHT; track.y += HEADER_HEIGHT + 1; bevelex(dest_surface, &track, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL|BEV_F_DISABLE_CENTER); adjust_rect(&track, 3); for (int i = 0 ; i < mused.song.num_sequences[channel] ; ++i, ++sp) { if (sp->position >= bottom) break; int len = mused.song.pattern[sp->pattern].num_steps; if (sp->position + len <= top) continue; if (i < mused.song.num_sequences[channel] - 1) len = my_min(len, (sp + 1)->position - sp->position); SDL_Rect pat = { track.x, (sp->position - top) * height + track.y, ((channel == mused.current_sequencetrack) ? w : narrow_w), len * height }; SDL_Rect text; copy_rect(&text, &pat); clip_rect(&pat, &track); gfx_domain_set_clip(dest_surface, &pat); for (int step = 0 ; step < len ; ++step, text.y += height) { if (text.y < pat.y) continue; if (sp->position + step >= bottom) break; MusStep *s = &mused.song.pattern[sp->pattern].step[step]; SDL_Rect pos; copy_rect(&pos, &text); pos.h = height; static const struct { Uint32 bar, beat, normal; } coltab[] = { {COLOR_PATTERN_BAR, COLOR_PATTERN_BEAT, COLOR_PATTERN_NORMAL}, {COLOR_PATTERN_INSTRUMENT_BAR, COLOR_PATTERN_INSTRUMENT_BEAT, COLOR_PATTERN_INSTRUMENT}, {COLOR_PATTERN_INSTRUMENT_BAR, COLOR_PATTERN_INSTRUMENT_BEAT, COLOR_PATTERN_INSTRUMENT}, {COLOR_PATTERN_VOLUME_BAR, COLOR_PATTERN_VOLUME_BEAT, COLOR_PATTERN_VOLUME}, {COLOR_PATTERN_VOLUME_BAR, COLOR_PATTERN_VOLUME_BEAT, COLOR_PATTERN_VOLUME}, {COLOR_PATTERN_CTRL_BAR, COLOR_PATTERN_CTRL_BEAT, COLOR_PATTERN_CTRL}, {COLOR_PATTERN_CTRL_BAR, COLOR_PATTERN_CTRL_BEAT, COLOR_PATTERN_CTRL}, {COLOR_PATTERN_CTRL_BAR, COLOR_PATTERN_CTRL_BEAT, COLOR_PATTERN_CTRL}, {COLOR_PATTERN_COMMAND_BAR, COLOR_PATTERN_COMMAND_BEAT, COLOR_PATTERN_COMMAND}, {COLOR_PATTERN_COMMAND_BAR, COLOR_PATTERN_COMMAND_BEAT, COLOR_PATTERN_COMMAND}, {COLOR_PATTERN_COMMAND_BAR, COLOR_PATTERN_COMMAND_BEAT, COLOR_PATTERN_COMMAND}, {COLOR_PATTERN_COMMAND_BAR, COLOR_PATTERN_COMMAND_BEAT, COLOR_PATTERN_COMMAND} }; if (step == 0) { console_set_color(mused.console, colors[COLOR_PATTERN_SEQ_NUMBER]); font_write_args(&mused.console->font, dest_surface, &pos, "%02X", sp->pattern); } else { console_set_color(mused.console, timesig(step, colors[COLOR_PATTERN_BAR], colors[COLOR_PATTERN_BEAT], colors[COLOR_PATTERN_NORMAL])); SDL_Rect cpos; copy_rect(&cpos, &pos); cpos.y += (mused.console->font.h - mused.tinyfont.h) / 2; cpos.x += (mused.console->font.w * 2 - mused.tinyfont.w * 2) / 2; if (SHOW_DECIMALS & mused.flags) font_write_args(&mused.tinyfont, dest_surface, &cpos, "%02d\n", (step + 100) % 100); // so we don't get negative numbers else font_write_args(&mused.tinyfont, dest_surface, &cpos, "%02X\n", step & 0xff); } pos.x += 2 * char_width + SPACER; for (int param = PED_NOTE ; param < PED_PARAMS ; ++param) { if (param != PED_NOTE && !viscol(param)) continue; pos.w = pattern_params[param].w * char_width; if (pattern_params[param].margin) pos.x += SPACER; Uint32 color = 0; if (sp->position + step != mused.pattern_position) color = timesig(step, colors[coltab[param].bar], colors[coltab[param].beat], colors[coltab[param].normal]); else console_set_color(mused.console, colors[COLOR_PATTERN_SELECTED]); switch (param) { case PED_NOTE: { const char *note = (s->note < MUS_NOTE_NONE) ? ((s->note == MUS_NOTE_RELEASE) ? "\x08\x09\x0b" : notename(s->note)) : "---"; if (sp->position + step != mused.pattern_position) console_set_color(mused.console, diszero(mused.song.pattern[sp->pattern].step[step].note != MUS_NOTE_NONE, color)); font_write(&mused.console->font, dest_surface, &pos, note); } break; case PED_INSTRUMENT1: case PED_INSTRUMENT2: if (sp->position + step != mused.pattern_position) console_set_color(mused.console, diszero(s->instrument != MUS_NOTE_NO_INSTRUMENT, color)); if (s->instrument != MUS_NOTE_NO_INSTRUMENT) font_write_args(&mused.console->font, dest_surface, &pos, "%X", (s->instrument >> (4 - (param - PED_INSTRUMENT1) * 4)) & 0xf); else font_write(&mused.console->font, dest_surface, &pos, "-"); break; case PED_VOLUME1: case PED_VOLUME2: if (sp->position + step != mused.pattern_position) console_set_color(mused.console, diszero(s->volume != MUS_NOTE_NO_VOLUME, color)); if (s->volume != MUS_NOTE_NO_VOLUME) { if (param == PED_VOLUME1 && s->volume > MAX_VOLUME) { char c; switch (s->volume & 0xf0) { default: c = '-'; break; case MUS_NOTE_VOLUME_SET_PAN: c = 'P'; break; case MUS_NOTE_VOLUME_PAN_LEFT: c = 0xf9; break; case MUS_NOTE_VOLUME_PAN_RIGHT: c = 0xfa; break; case MUS_NOTE_VOLUME_FADE_UP: c = 0xfb; break; case MUS_NOTE_VOLUME_FADE_DN: c = 0xfc; break; } font_write_args(&mused.console->font, dest_surface, &pos, "%c", c); } else { font_write_args(&mused.console->font, dest_surface, &pos, "%X", (s->volume >> (4 - (param - PED_VOLUME1) * 4)) & 0xf); } } else font_write(&mused.console->font, dest_surface, &pos, "-"); break; case PED_LEGATO: case PED_SLIDE: case PED_VIB: if (sp->position + step != mused.pattern_position) console_set_color(mused.console, diszero((s->ctrl & (1 << (param - PED_LEGATO))), color)); font_write_args(&mused.console->font, dest_surface, &pos, "%c", (s->ctrl & (1 << (param - PED_LEGATO))) ? "LSV"[param - PED_LEGATO] : '-'); break; case PED_COMMAND1: case PED_COMMAND2: case PED_COMMAND3: case PED_COMMAND4: if (sp->position + step != mused.pattern_position) console_set_color(mused.console, diszero(s->command != 0, color)); if ((mused.flags & HIDE_ZEROS) && s->command == 0) font_write_args(&mused.console->font, dest_surface, &pos, "-"); else font_write_args(&mused.console->font, dest_surface, &pos, "%X", (s->command >> (12 - (param - PED_COMMAND1) * 4)) & 0xf); break; } SDL_Rect tmp; copy_rect(&tmp, &pos); clip_rect(&tmp, &track); if (sp && event->type == SDL_MOUSEBUTTONDOWN) { check_event(event, &tmp, select_pattern_param, MAKEPTR(param), MAKEPTR(sp->position + step), MAKEPTR(channel)); set_repeat_timer(NULL); // ugh } pos.x += pos.w; if (channel != mused.current_sequencetrack && (mused.flags & EXPAND_ONLY_CURRENT_TRACK)) break; } } if ((mused.flags & SONG_PLAYING) && !(mused.flags & FOLLOW_PLAY_POSITION)) { gfx_domain_set_clip(dest_surface, &track); SDL_Rect pos = { track.x, (mused.stat_song_position - top) * height + track.y - 1, ((channel == mused.current_sequencetrack) ? w : narrow_w), 2 }; bevel(dest_surface, &pos, mused.slider_bevel, BEV_SEQUENCE_PLAY_POS); } } if ((mused.flags & SONG_PLAYING) && !(mused.flags & DISABLE_VU_METERS)) { gfx_domain_set_clip(dest_surface, &track); const int ah = dest->h + dest->y - row.y; const int w = mused.vu_meter->surface->w; const int h = my_min(mused.vu_meter->surface->h, mused.vis.cyd_env[channel] * ah / MAX_VOLUME); SDL_Rect r = { track.x + track.w / 2 - w / 2 , row.y - h, w, h }; SDL_Rect sr = { 0, mused.vu_meter->surface->h - h, mused.vu_meter->surface->w, h }; gfx_blit(mused.vu_meter, &sr, dest_surface, &r); } } SDL_Rect pat; copy_rect(&pat, dest); adjust_rect(&pat, 2); gfx_domain_set_clip(dest_surface, &pat); if (mused.focus == EDITPATTERN) { int x = 2 + 2 * char_width + SPACER; for (int param = 0 ; param < mused.current_patternx ; ++param) { if (viscol(param)) { x += (param > 0 && pattern_params[param].margin ? SPACER : 0) + pattern_params[param].w * char_width; } } if (pattern_params[mused.current_patternx].margin) x += SPACER; if (mused.current_sequencetrack >= mused.pattern_horiz_position && mused.current_sequencetrack <= my_min(mused.song.num_channels, mused.pattern_horiz_position + 1 + (dest->w - w) / narrow_w) - 1) { SDL_Rect cursor = { 1 + dest->x + narrow_w * (mused.current_sequencetrack - mused.pattern_horiz_position) + x, row.y, pattern_params[mused.current_patternx].w * char_width, row.h}; adjust_rect(&cursor, -2); set_cursor(&cursor); } if (mused.selection.start != mused.selection.end) { if (mused.selection.start <= bottom && mused.selection.end >= top) { SDL_Rect selection = { dest->x + narrow_w * (mused.current_sequencetrack - mused.pattern_horiz_position) + 2 * char_width + SPACER, row.y + height * (mused.selection.start - mused.pattern_position), w - (2 * char_width + SPACER), height * (mused.selection.end - mused.selection.start)}; adjust_rect(&selection, -3); selection.h += 2; bevel(dest_surface, &selection, mused.slider_bevel, BEV_SELECTION); } } } gfx_domain_set_clip(dest_surface, NULL); if (mused.focus == EDITSEQUENCE) { // hack to display cursor both in sequence editor and here int x = 0; int w = char_width * 2; if (mused.flags & EDIT_SEQUENCE_DIGITS) { x = mused.sequence_digit * char_width; w = char_width; } SDL_Rect cursor = { 3 + dest->x + narrow_w * (mused.current_sequencetrack - mused.pattern_horiz_position) + x, row.y, w, row.h}; adjust_rect(&cursor, -2); bevelex(dest_surface, &cursor, mused.slider_bevel, (mused.flags & EDIT_MODE) ? BEV_EDIT_CURSOR : BEV_CURSOR, BEV_F_STRETCH_ALL); } // ach if (event->type == SDL_MOUSEWHEEL && mused.focus == EDITPATTERN) { if (event->wheel.y > 0) { mused.pattern_position -= 1; } else { mused.pattern_position += 1; } mused.pattern_position = my_max(0, my_min(mused.song.song_length - 1, mused.pattern_position)); } } static void pattern_view_stepcounter(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event) { SDL_Rect content; copy_rect(&content, dest); SDL_Rect header, frame, compact; copy_rect(&header, dest); header.h = HEADER_HEIGHT; header.w -= 2; copy_rect(&compact, &header); adjust_rect(&compact, 2); compact.w /= 2; bevelex(dest_surface, &header, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); button_event(dest_surface, event, &compact, mused.slider_bevel, !(mused.flags & COMPACT_VIEW) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, !(mused.flags & COMPACT_VIEW) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, (mused.flags & COMPACT_VIEW) ? DECAL_COMPACT_SELETED : DECAL_COMPACT, flip_bit_action, &mused.flags, MAKEPTR(COMPACT_VIEW), 0); compact.x += compact.w; button_event(dest_surface, event, &compact, mused.slider_bevel, !(mused.flags & EXPAND_ONLY_CURRENT_TRACK) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, !(mused.flags & EXPAND_ONLY_CURRENT_TRACK) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, (mused.flags & EXPAND_ONLY_CURRENT_TRACK) ? DECAL_FOCUS_SELETED : DECAL_FOCUS, flip_bit_action, &mused.flags, MAKEPTR(EXPAND_ONLY_CURRENT_TRACK), 0); content.y += HEADER_HEIGHT; content.h -= HEADER_HEIGHT; copy_rect(&frame, &content); adjust_rect(&content, 2); console_set_clip(mused.console, &content); console_clear(mused.console); adjust_rect(&content, 2); console_set_clip(mused.console, &content); console_set_background(mused.console, 0); int start = mused.pattern_position - dest->h / mused.console->font.h / 2; int y = 0; for (int row = start ; y < content.h ; ++row, y += mused.console->font.h) { if (mused.pattern_position == row) { SDL_Rect row = { content.x - 2, content.y + y - 1, content.w + 4, mused.console->font.h + 1}; bevelex(dest_surface,&row, mused.slider_bevel, BEV_SELECTED_PATTERN_ROW, BEV_F_STRETCH_ALL); } if (row < 0 || row >= mused.song.song_length) { console_set_color(mused.console, colors[COLOR_PATTERN_DISABLED]); } else { console_set_color(mused.console, ((row == mused.pattern_position) ? colors[COLOR_PATTERN_SELECTED] : timesig(row, colors[COLOR_PATTERN_BAR], colors[COLOR_PATTERN_BEAT], colors[COLOR_PATTERN_NORMAL]))); } if (SHOW_DECIMALS & mused.flags) console_write_args(mused.console, "%03d\n", (row + 1000) % 1000); // so we don't get negative numbers else console_write_args(mused.console, "%03X\n", row & 0xfff); } bevelex(dest_surface, &frame, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL|BEV_F_DISABLE_CENTER); gfx_domain_set_clip(dest_surface, NULL); } void pattern_view2(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect pat, pos; copy_rect(&pat, dest); copy_rect(&pos, dest); pat.w -= 30; pat.x += 30; pos.w = 32; pattern_view_stepcounter(dest_surface, &pos, event); pattern_view_inner(dest_surface, &pat, event); gfx_domain_set_clip(dest_surface, NULL); SDL_Rect scrollbar = { dest->x, dest->y + dest->h - SCROLLBAR, dest->w, SCROLLBAR }; slider(dest_surface, &scrollbar, event, &mused.pattern_horiz_slider_param); } klystrack-0.20171212/klystrack/src/view/pattern.h0000644000000000000000000000255113214501362020214 0ustar rootroot#ifndef PATTERN_H #define PATTERN_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" void pattern_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void pattern_view2(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); #endif klystrack-0.20171212/klystrack/src/view/sequence.h0000644000000000000000000000024613214501362020346 0ustar rootroot#include "../view.h" extern Uint32 pattern_color[16]; void sequence_view2(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); klystrack-0.20171212/klystrack/src/view/timer.c0000644000000000000000000000116613214501362017653 0ustar rootroot#include "timer.h" #include "gui/bevel.h" #include "mused.h" #include "mybevdefs.h" void timer_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { //bevel(mused.screen, dest, mused.slider_bevel->surface, BEV_THIN_FRAME); SDL_Rect field; copy_rect(&field, dest); adjust_rect(&field, 2); if (mused.flags & SONG_PLAYING) { Uint64 t = (mused.play_start_at + mused.time_played) / 1000; font_write_args(&mused.smallfont, dest_surface, &field, "%02d:%02d", (int)(t / 60), (int)(t % 60)); } else font_write(&mused.smallfont, dest_surface, &field, "00:00"); } klystrack-0.20171212/klystrack/src/midi.h0000644000000000000000000000254213214501362016507 0ustar rootroot#ifndef MIDI_H #define MIDI_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (SDL_Surface *dest_surface, 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. */ #ifdef MIDI #include "SDL.h" #include "gui/menu.h" extern Menu midi_menu[]; void midi_init(); void midi_deinit(); void midi_set_channel(void *chn, void *unused1, void *unused2); #endif #endifklystrack-0.20171212/klystrack/src/menudefs.c0000644000000000000000000003000713214501362017363 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "gui/menu.h" #include "action.h" #include "diskop.h" #include "edit.h" #include "mused.h" #include "import/import.h" #include "midi.h" #include "stats.h" #include "zap.h" #include "optimize.h" extern Mused mused; const Menu mainmenu[]; static const Menu showmenu[]; static const Menu filemenu[]; extern Menu thememenu[]; extern Menu keymapmenu[]; Menu editormenu[] = { { 0, showmenu, "Instrument", NULL, change_mode_action, (void*)EDITINSTRUMENT, 0, 0 }, { 0, showmenu, "Pattern", NULL, change_mode_action, (void*)EDITPATTERN, 0, 0 }, { 0, showmenu, "Sequence", NULL, change_mode_action, (void*)EDITSEQUENCE, 0, 0 }, { 0, showmenu, "Classic", NULL, change_mode_action, (void*)EDITCLASSIC, 0, 0 }, { 0, showmenu, "Effects", NULL, change_mode_action, (void*)EDITFX, 0, 0 }, { 0, showmenu, "Wavetable", NULL, change_mode_action, (void*)EDITWAVETABLE, 0, 0 }, { 0, NULL, NULL } }; Menu analyzermenu[] = { { 0, showmenu, "Spectrum", NULL, change_visualizer_action, (void*)VIS_SPECTRUM, 0, 0 }, { 0, showmenu, "CATOMETER!", NULL, change_visualizer_action, (void*)VIS_CATOMETER, 0, 0 }, { 0, NULL, NULL } }; static const Menu columnsmenu[] = { { 0, showmenu, "Instrument", NULL, MENU_CHECK, &mused.visible_columns, (void*)VC_INSTRUMENT, 0 }, { 0, showmenu, "Volume", NULL, MENU_CHECK, &mused.visible_columns, (void*)VC_VOLUME, 0 }, { 0, showmenu, "Control bits", NULL, MENU_CHECK, &mused.visible_columns, (void*)VC_CTRL, 0 }, { 0, showmenu, "Command", NULL, MENU_CHECK, &mused.visible_columns, (void*)VC_COMMAND, 0 }, { 0, NULL, NULL } }; static const Menu showmenu[] = { { 0, mainmenu, "Editor", editormenu, NULL }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Compact", NULL, MENU_CHECK, &mused.flags, (void*)COMPACT_VIEW, 0 }, { 0, mainmenu, "Track focus", NULL, MENU_CHECK, &mused.flags, (void*)EXPAND_ONLY_CURRENT_TRACK, 0 }, { 0, mainmenu, "Visible columns", columnsmenu, NULL }, { 0, mainmenu, "Show position offset", NULL, MENU_CHECK, &mused.flags, (void*)SHOW_PATTERN_POS_OFFSET, 0 }, { 0, mainmenu, "Show analyzer", NULL, MENU_CHECK, &mused.flags, (void*)SHOW_ANALYZER, 0 }, { 0, mainmenu, "Analyzer", analyzermenu, NULL }, { 0, mainmenu, "Show logo", NULL, MENU_CHECK, &mused.flags, (void*)SHOW_LOGO, 0 }, { 0, NULL, NULL } }; const Menu prefsmenu[]; Menu pixelmenu[] = { { 0, prefsmenu, "1x1", NULL, change_pixel_scale, (void*)1, 0, 0 }, { 0, prefsmenu, "2x2", NULL, change_pixel_scale, (void*)2, 0, 0 }, { 0, prefsmenu, "3x3", NULL, change_pixel_scale, (void*)3, 0, 0 }, { 0, prefsmenu, "4x4", NULL, change_pixel_scale, (void*)4, 0, 0 }, { 0, NULL,NULL }, }; Menu oversamplemenu[] = { { 0, prefsmenu, "No oversampling", NULL, change_oversample, (void*)0, 0, 0 }, { 0, prefsmenu, "2x", NULL, change_oversample, (void*)1, 0, 0 }, { 0, prefsmenu, "4x", NULL, change_oversample, (void*)2, 0, 0 }, { 0, prefsmenu, "8x", NULL, change_oversample, (void*)3, 0, 0 }, { 0, NULL,NULL }, }; Menu patternlengthmenu[] = { { 0, prefsmenu, "Same as STEP", NULL, MENU_CHECK, &mused.flags, (void*)LOCK_SEQUENCE_STEP_AND_PATTERN_LENGTH, 0 }, { 0, prefsmenu, "16 steps", NULL, change_default_pattern_length, (void*)16, 0, 0 }, { 0, prefsmenu, "32 steps", NULL, change_default_pattern_length, (void*)32, 0, 0 }, { 0, prefsmenu, "48 steps", NULL, change_default_pattern_length, (void*)48, 0, 0 }, { 0, prefsmenu, "64 steps", NULL, change_default_pattern_length, (void*)64, 0, 0 }, { 0, NULL,NULL }, }; const Menu prefsmenu[] = { { 0, mainmenu, "Theme", thememenu, NULL }, { 0, mainmenu, "Keymap", keymapmenu, NULL }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Pixel size", pixelmenu }, { 0, mainmenu, "Fullscreen", NULL, MENU_CHECK_NOSET, &mused.flags, (void*)FULLSCREEN, toggle_fullscreen }, { 0, mainmenu, "Disable rendering to texture", NULL, MENU_CHECK_NOSET, &mused.flags, (void*)DISABLE_RENDER_TO_TEXTURE, toggle_render_to_texture }, { 0, mainmenu, "Oversampling", oversamplemenu }, { 0, mainmenu, "", NULL, NULL }, #ifdef MIDI { 0, mainmenu, "MIDI", midi_menu }, { 0, mainmenu, "", NULL, NULL }, #endif { 0, mainmenu, "Keyjazz", NULL, MENU_CHECK, &mused.flags, (void*)MULTICHANNEL_PREVIEW, 0 }, { 0, mainmenu, "Hold key to sustain", NULL, MENU_CHECK, &mused.flags, (void*)MULTIKEY_JAMMING, 0 }, { 0, mainmenu, "Follow song position", NULL, MENU_CHECK, &mused.flags, (void*)FOLLOW_PLAY_POSITION, 0 }, { 0, mainmenu, "Animate cursor", NULL, MENU_CHECK, &mused.flags, (void*)ANIMATE_CURSOR, 0 }, { 0, mainmenu, "Hide zeros", NULL, MENU_CHECK, &mused.flags, (void*)HIDE_ZEROS, 0 }, { 0, mainmenu, "Protracker style delete", NULL, MENU_CHECK, &mused.flags, (void*)DELETE_EMPTIES, 0 }, { 0, mainmenu, "Toggle edit on stop", NULL, MENU_CHECK, &mused.flags, (void*)TOGGLE_EDIT_ON_STOP, 0 }, { 0, mainmenu, "Stop editing when playing", NULL, MENU_CHECK, &mused.flags, (void*)STOP_EDIT_ON_PLAY, 0 }, { 0, mainmenu, "Decimal numbers", NULL, MENU_CHECK, &mused.flags, (void*)SHOW_DECIMALS, 0 }, { 0, mainmenu, "Default pattern length", patternlengthmenu }, { 0, mainmenu, "Reverb length in ticks", NULL, MENU_CHECK, &mused.flags, (void*)SHOW_DELAY_IN_TICKS, 0 }, { 0, mainmenu, "AHX-style sequence edit", NULL, MENU_CHECK, &mused.flags, (void*)EDIT_SEQUENCE_DIGITS, 0 }, { 0, mainmenu, "Disable nostalgy", NULL, MENU_CHECK, &mused.flags, (void*)DISABLE_NOSTALGY, 0 }, { 0, mainmenu, "Disable VU meters", NULL, MENU_CHECK, &mused.flags, (void*)DISABLE_VU_METERS, 0 }, { 0, mainmenu, "Disable file backups", NULL, MENU_CHECK, &mused.flags, (void*)DISABLE_BACKUPS, 0 }, { 0, mainmenu, "Load default song on startup", NULL, MENU_CHECK, &mused.flags, (void*)START_WITH_TEMPLATE, 0 }, { 0, mainmenu, "Use system mouse cursor", NULL, MENU_CHECK_NOSET, &mused.flags, (void*)USE_SYSTEM_CURSOR, toggle_mouse_cursor }, { 0, NULL, NULL } }; static const Menu importmenu[] = { { 0, filemenu, "Import .MOD", NULL, import_module, MAKEPTR(IMPORT_MOD) }, { 0, filemenu, "Import .AHX", NULL, import_module, MAKEPTR(IMPORT_AHX) }, { 0, filemenu, "Import .XM", NULL, import_module, MAKEPTR(IMPORT_XM) }, { 0, filemenu, "Import .ORG", NULL, import_module, MAKEPTR(IMPORT_ORG) }, { 0, filemenu, "Import .SID (Rob Hubbard)", NULL, import_module, MAKEPTR(IMPORT_HUBBARD) }, { 0, NULL, NULL } }; static const Menu instmenu[] = { { 0, filemenu, "Kill instrument", NULL, kill_instrument }, { 0, filemenu, "Open instrument", NULL, open_data, MAKEPTR(OD_T_INSTRUMENT), MAKEPTR(OD_A_OPEN) }, { 0, filemenu, "Save instrument", NULL, open_data, MAKEPTR(OD_T_INSTRUMENT), MAKEPTR(OD_A_SAVE) }, { 0, NULL, NULL } }; static const Menu wavetablemenu[] = { { 0, filemenu, "Kill wave", NULL, kill_wavetable_entry, 0, 0 }, { 0, filemenu, "Open .WAV", NULL, open_data, MAKEPTR(OD_T_WAVETABLE), MAKEPTR(OD_A_OPEN) }, { 0, filemenu, "Save .WAV", NULL, open_data, MAKEPTR(OD_T_WAVETABLE), MAKEPTR(OD_A_SAVE) }, { 0, filemenu, "Open 8-bit signed", NULL, open_data, MAKEPTR(OD_T_WAVETABLE_RAW_S), MAKEPTR(OD_A_OPEN) }, { 0, filemenu, "Open 8-bit unsigned", NULL, open_data, MAKEPTR(OD_T_WAVETABLE_RAW_U), MAKEPTR(OD_A_OPEN) }, { 0, NULL, NULL } }; static const Menu filemenu[] = { { 0, mainmenu, "New song", NULL, new_song_action }, { 0, mainmenu, "Open song", NULL, open_data, MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_OPEN) }, { 0, mainmenu, "Save song", NULL, open_data, MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_SAVE) }, { 0, mainmenu, "Export .WAV", NULL, export_wav_action }, { 0, mainmenu, "Export tracks as .WAV", NULL, export_channels_action }, { 0, mainmenu, "Import", importmenu }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Instrument", instmenu }, { 0, mainmenu, "Wavetable", wavetablemenu }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Exit", NULL, quit_action }, { 0, NULL, NULL } }; static const Menu playmenu[] = { { 0, mainmenu, "Play", NULL, play, (void*)0, 0, 0 }, { 0, mainmenu, "Stop", NULL, stop, 0, 0, 0 }, { 0, mainmenu, "Play from cursor", NULL, play, (void*)1, 0, 0 }, { 0, mainmenu, "Loop current position", NULL, play_position, 0, 0, 0 }, { 0, mainmenu, "", NULL }, { 0, mainmenu, "Unmute all channels", NULL, unmute_all_action, 0, 0, 0 }, { 0, NULL, NULL } }; static const Menu infomenu[] = { { 0, mainmenu, "About", NULL, show_about_box, (void*)0, 0, 0 }, { 0, mainmenu, "Song statistics", NULL, song_stats, (void*)0, 0, 0 }, { 0, NULL, NULL } }; static const Menu editmenu[]; static const Menu editpatternmenu[] = { { 0, editmenu, "Clone", NULL, clone_pattern, 0, 0, 0 }, { 0, editmenu, "Find empty", NULL, get_unused_pattern, 0, 0, 0 }, { 0, editmenu, "Split at cursor", NULL, split_pattern, 0, 0, 0 }, { 0, editmenu, "", NULL }, { 0, editmenu, "Expand 2X", NULL, expand_pattern, MAKEPTR(2), 0, 0 }, { 0, editmenu, "Shrink 2X", NULL, shrink_pattern, MAKEPTR(2), 0, 0 }, { 0, editmenu, "Expand 3X", NULL, expand_pattern, MAKEPTR(3), 0, 0 }, { 0, editmenu, "Shrink 3X", NULL, shrink_pattern, MAKEPTR(3), 0, 0 }, { 0, NULL, NULL } }; static const Menu zapmenu[] = { { 0, editmenu, "Zap instruments", NULL, zap_instruments, 0, 0, 0 }, { 0, editmenu, "Zap sequence", NULL, zap_sequence, 0, 0, 0 }, { 0, editmenu, "Zap wavetable", NULL, zap_wavetable, 0, 0, 0 }, { 0, editmenu, "Zap FX", NULL, zap_wavetable, 0, 0, 0 }, { 0, NULL, NULL } }; static const Menu optimizemenu[] = { { 0, editmenu, "Kill duplicate patterns", NULL, optimize_patterns_action, 0, 0, 0 }, { 0, editmenu, "Kill unused instruments", NULL, optimize_instruments_action, 0, 0, 0 }, { 0, editmenu, "Kill unused wavetables", NULL, optimize_wavetables_action, 0, 0, 0 }, { 0, NULL, NULL } }; static const Menu editmenu[] = { { 0, mainmenu, "Undo", NULL, do_undo, 0, 0, 0 }, { 0, mainmenu, "Redo", NULL, do_undo, MAKEPTR(1), 0, 0 }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Zap", zapmenu, NULL }, { 0, mainmenu, "Optimize", optimizemenu, NULL }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Copy", NULL, generic_action, copy, 0, 0 }, { 0, mainmenu, "Paste", NULL, generic_action, paste, 0, 0 }, { 0, mainmenu, "Join paste", NULL, generic_action, join_paste, 0, 0 }, { 0, mainmenu, "Cut", NULL, generic_action, cut, 0, 0 }, { 0, mainmenu, "Delete", NULL, generic_action, delete, 0, 0 }, { 0, mainmenu, "Select all", NULL, select_all, 0, 0, 0 }, { 0, mainmenu, "Deselect", NULL, clear_selection, 0, 0, 0 }, { 0, mainmenu, "", NULL, NULL }, { 0, mainmenu, "Pattern", editpatternmenu, NULL }, { 0, mainmenu, "", NULL }, { 0, mainmenu, "Interpolate", NULL, interpolate, 0, 0, 0 }, { 0, mainmenu, "", NULL }, { 0, mainmenu, "Edit mode", NULL, MENU_CHECK, &mused.flags, (void*)EDIT_MODE, 0 }, { 0, NULL, NULL } }; const Menu mainmenu[] = { { 0, NULL, "FILE", filemenu }, { 0, NULL, "PLAY", playmenu }, { 0, NULL, "EDIT", editmenu }, { 0, NULL, "SHOW", showmenu }, { 0, NULL, "PREFS", prefsmenu }, { 0, NULL, "INFO", infomenu }, { 0, NULL, NULL } }; klystrack-0.20171212/klystrack/src/console.h0000644000000000000000000000345713214501362017235 0ustar rootroot#ifndef CONSOLE_H #define CONSOLE_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gfx/font.h" typedef struct { Uint32 current_color; Uint16 cursor; Font font; SDL_Rect clip; int background; } Console; void console_set_background(Console * c, int enabled); void console_reset_cursor(Console * c); void console_set_clip(Console * c, const SDL_Rect *rect); void console_clear(Console *console); Console * console_create(Bundle *b); void console_set_color(Console* console, Uint32 color); const SDL_Rect * console_write(Console* console, const char *string); const SDL_Rect * console_write_args(Console* console, const char *string, ...) __attribute__ ((format (printf, 2, 3))); void console_destroy(Console *c); #endif klystrack-0.20171212/klystrack/src/undo.h0000644000000000000000000000747713214501362016546 0ustar rootroot#ifndef UNDO_H #define UNDO_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "snd/music.h" #include typedef enum { UNDO_PATTERN, UNDO_SEQUENCE, UNDO_INSTRUMENT, UNDO_FX, UNDO_SONGINFO, UNDO_MODE, UNDO_WAVE_PARAM, UNDO_WAVE_DATA, UNDO_WAVE_NAME } UndoType; typedef union { struct { int channel; MusSeqPattern *seq; int n_seq; } sequence; struct { int idx; MusInstrument instrument; } instrument; struct { int idx; MusStep *step; int n_steps; } pattern; struct { CydFxSerialized fx; int idx; Uint8 multiplex_period; } fx; struct { int old_mode, focus; } mode; struct { Uint16 song_length, loop_point, sequence_step; Uint8 song_speed, song_speed2, song_rate; Uint16 time_signature; Uint32 flags; Uint8 num_channels; char title[MUS_SONG_TITLE_LEN + 1]; Uint8 master_volume, default_volume[MUS_MAX_CHANNELS], default_panning[MUS_MAX_CHANNELS]; } songinfo; struct { int idx; Uint32 flags; Uint32 sample_rate; Uint32 samples, loop_begin, loop_end; Uint16 base_note; } wave_param; struct { int idx; void *data; size_t length; Uint32 flags; Uint32 sample_rate; Uint32 samples, loop_begin, loop_end; Uint16 base_note; } wave_data; struct { int idx; char *name; } wave_name; } UndoEvent; typedef struct UndoFrame_t { UndoType type; struct UndoFrame_t *prev; UndoEvent event; bool modified; } UndoFrame; typedef UndoFrame *UndoStack; void undo_init(UndoStack *stack); void undo_deinit(UndoStack *stack); void undo_destroy_frame(UndoFrame *frame); void undo_add_frame(UndoStack *stack, UndoFrame *frame); /* Use when undo state stored but then the action is cancelled */ void undo_pop(UndoStack *stack); /* Pops the topmost frame from stack, use undo_destroy_frame() after processed */ UndoFrame *undo(UndoStack *stack); void undo_store_mode(UndoStack *stack, int old_mode, int focus, bool modified); void undo_store_instrument(UndoStack *stack, int idx, const MusInstrument *instrument, bool modified); void undo_store_sequence(UndoStack *stack, int channel, const MusSeqPattern *sequence, int n_seq, bool modified); void undo_store_songinfo(UndoStack *stack, const MusSong *song, bool modified); void undo_store_fx(UndoStack *stack, int idx, const CydFxSerialized *fx, Uint8 multiplex_period, bool modified); void undo_store_pattern(UndoStack *stack, int idx, const MusPattern *pattern, bool modified); void undo_store_wave_data(UndoStack *stack, int idx, const CydWavetableEntry *entry, bool modified); void undo_store_wave_name(UndoStack *stack, int idx, const char *name, bool modified); void undo_store_wave_param(UndoStack *stack, int idx, const CydWavetableEntry *entry, bool modified); #ifdef DEBUG void undo_show_stack(UndoStack *stack); #endif #endif klystrack-0.20171212/klystrack/src/shortcutdefs.c0000644000000000000000000002044513214501362020277 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "shortcutdefs.h" #include "SDL.h" #include "action.h" #include "diskop.h" #include "edit.h" #include "mused.h" #include "view.h" extern Mused mused; extern const View *tab[]; const KeyShortcut shortcuts[] = { { 0, SDLK_TAB, cycle_focus, tab, &mused.focus, &mused.mode, "Cycle focus" }, { 0, SDLK_ESCAPE, quit_action, 0, 0, 0, "Quit" }, { KMOD_ALT, SDLK_F4, quit_action, 0, 0, 0, "Quit" }, { 0, SDLK_F1, open_help, 0, 0, 0, "Help" }, { 0, SDLK_F2, change_mode_action, (void*)EDITPATTERN, 0, 0, "Pattern editor"}, { 0, SDLK_F3, change_mode_action, (void*)EDITINSTRUMENT, 0, 0, "Instrument editor"}, { KMOD_SHIFT, SDLK_F3, change_mode_action, (void*)EDITFX, 0, 0, "FX editor"}, { 0, SDLK_F4, change_mode_action, (void*)EDITSEQUENCE, 0, 0, "Sequence editor"}, { KMOD_SHIFT, SDLK_F4, change_mode_action, (void*)EDITCLASSIC, 0, 0, "Classic editor"}, { KMOD_SHIFT, SDLK_F2, change_mode_action, (void*)EDITWAVETABLE, 0, 0, "Wavetable editor"}, { 0, SDLK_F5, play, 0, 0, 0, "Play" }, { 0, SDLK_F6, play, (void*)1, 0, 0, "Play from cursor" }, { KMOD_SHIFT, SDLK_F6, play_position, 0, 0, 0, "Loop current pattern" }, { 0, SDLK_F8, stop, 0, 0, 0, "Stop" }, { 0, SDLK_F9, change_octave, (void*)-1, 0, 0, "Select lower octave" }, { KMOD_SHIFT, SDLK_F9, change_song_rate, (void*)-1, 0, 0, "Decrease play rate" }, { KMOD_SHIFT|KMOD_CTRL, SDLK_F9, change_time_signature, 0, 0, 0, "Change time signature" }, { 0, SDLK_F10, change_octave, (void*)+1, 0, 0, "Select higher octave" }, { KMOD_SHIFT, SDLK_F10, change_song_rate, (void*)+1, 0, 0, "Increase play rate" }, { KMOD_SHIFT|KMOD_CTRL, SDLK_F10, change_time_signature, (void*)1, 0, 0, "Change time signature" }, { 0, SDLK_KP_PLUS, select_instrument, (void*)+1, (void*)1, 0, "Next instrument"}, { KMOD_CTRL, SDLK_KP_PLUS, change_song_speed, 0, (void*)+1, 0, "Increase play speed" }, { KMOD_ALT, SDLK_KP_PLUS, change_song_speed, (void*)1, (void*)+1, 0, "Increase play speed/shuffle" }, { 0, SDLK_KP_MINUS, select_instrument, (void*)-1, (void*)1, 0, "Previous instrument" }, { KMOD_CTRL, SDLK_KP_MINUS, change_song_speed, 0, (void*)-1, 0, "Decrease play speed" }, { KMOD_ALT, SDLK_KP_MINUS, change_song_speed, (void*)1, (void*)-1, 0, "Decrease play speed/shuffle" }, { KMOD_CTRL, SDLK_n, new_song_action, 0, 0, 0, "New song" }, { KMOD_CTRL, SDLK_s, open_data, MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_SAVE), 0, "Save file" }, { KMOD_CTRL, SDLK_o, open_data, MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_OPEN), 0, "Load file" }, { KMOD_CTRL, SDLK_c, generic_action, copy, 0, 0, "Copy to clipboard" }, { KMOD_CTRL, SDLK_v, generic_action, paste, 0, 0, "Paste from clipboard" }, { KMOD_CTRL, SDLK_x, generic_action, cut, 0, 0, "Cut to clipboard" }, { KMOD_CTRL, SDLK_DELETE, generic_action, delete, 0, 0, "Delete selection" }, { KMOD_SHIFT, SDLK_INSERT, generic_action, paste, 0, 0, "Paste from clipboard" }, { KMOD_CTRL, SDLK_j, generic_action, join_paste, 0, 0, "Join from clipboard" }, { KMOD_CTRL, SDLK_INSERT, generic_action, copy, 0, 0, "Copy to clipboard" }, { KMOD_CTRL, SDLK_a, select_all, 0, 0, 0, "Select all" }, { KMOD_CTRL, SDLK_d, clear_selection, 0, 0, 0, "Deselect" }, { KMOD_CTRL, SDLK_r, toggle_pixel_scale, 0, 0, 0, "Toggle pixel scale" }, { KMOD_CTRL, SDLK_b, begin_selection_action, 0, 0, 0, "Set selection beginning" }, { KMOD_CTRL, SDLK_e, end_selection_action, 0, 0, 0, "Set selection end" }, { KMOD_CTRL|KMOD_SHIFT, SDLK_e, expand_pattern, MAKEPTR(2), 0, 0, "Expand pattern" }, { KMOD_ALT, SDLK_RETURN, toggle_fullscreen, 0, 0, 0, "Toggle fullscreen" }, { KMOD_CTRL|KMOD_SHIFT, SDLK_k, clone_each_pattern, 0, 0, 0, "Clone sequence row" }, { KMOD_CTRL, SDLK_k, clone_pattern, 0, 0, 0, "Clone pattern" }, { KMOD_CTRL, SDLK_u, get_unused_pattern, 0, 0, 0, "Find first unused pattern" }, { KMOD_CTRL|KMOD_SHIFT, SDLK_u, get_unused_pattern_all_tracks, 0, 0, 0, "Find unused patterns for all tracks" }, { KMOD_CTRL, SDLK_i, interpolate, 0, 0, 0, "Interpolate" }, { KMOD_SHIFT, SDLK_KP_PLUS, transpose_note_data, (void*)+1, 0, 0, "Transpose selection up" }, { KMOD_SHIFT, SDLK_KP_MINUS, transpose_note_data, (void*)-1, 0, 0, "Transpose selection down" }, { KMOD_ALT, SDLK_s, split_pattern, 0, 0, 0, "Split pattern at cursor position" }, { KMOD_CTRL, SDLK_m, unmute_all_action, 0, 0, 0, "Unmute all channels" }, { KMOD_CTRL|KMOD_SHIFT, SDLK_m, solo_channel, 0, 0, 0, "Solo current channel" }, { KMOD_CTRL, SDLK_z, do_undo, 0, 0, 0, "Undo" }, { KMOD_CTRL, SDLK_y, do_undo, MAKEPTR(1), 0, 0, "Redo" }, { KMOD_CTRL, SDLK_0, set_note_jump, MAKEPTR(0), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_1, set_note_jump, MAKEPTR(1), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_2, set_note_jump, MAKEPTR(2), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_3, set_note_jump, MAKEPTR(3), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_4, set_note_jump, MAKEPTR(4), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_5, set_note_jump, MAKEPTR(5), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_6, set_note_jump, MAKEPTR(6), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_7, set_note_jump, MAKEPTR(7), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_8, set_note_jump, MAKEPTR(8), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_9, set_note_jump, MAKEPTR(9), 0, 0, "Set note jump" }, { KMOD_CTRL, SDLK_KP_0, select_instrument_page, MAKEPTR(0), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_1, select_instrument_page, MAKEPTR(1), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_2, select_instrument_page, MAKEPTR(2), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_3, select_instrument_page, MAKEPTR(3), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_4, select_instrument_page, MAKEPTR(4), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_5, select_instrument_page, MAKEPTR(5), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_6, select_instrument_page, MAKEPTR(6), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_7, select_instrument_page, MAKEPTR(7), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_8, select_instrument_page, MAKEPTR(8), 0, MAKEPTR(1), "Select instrument page" }, { KMOD_CTRL, SDLK_KP_9, select_instrument_page, MAKEPTR(9), 0, MAKEPTR(1), "Select instrument page" }, { 0, SDLK_KP_0, select_instrument, MAKEPTR(0), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_1, select_instrument, MAKEPTR(1), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_2, select_instrument, MAKEPTR(2), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_3, select_instrument, MAKEPTR(3), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_4, select_instrument, MAKEPTR(4), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_5, select_instrument, MAKEPTR(5), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_6, select_instrument, MAKEPTR(6), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_7, select_instrument, MAKEPTR(7), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_8, select_instrument, MAKEPTR(8), 0, MAKEPTR(1), "Select instrument" }, { 0, SDLK_KP_9, select_instrument, MAKEPTR(9), 0, MAKEPTR(1), "Select instrument" }, { KMOD_CTRL, SDLK_p, toggle_follow_play_position, 0, 0, 0, "Toggle follow song position" }, /* Null terminated */ { 0, 0, NULL, 0, 0, 0 } }; klystrack-0.20171212/klystrack/src/event.h0000644000000000000000000000775113214501362016715 0ustar rootroot#ifndef EVENT_H #define EVENT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gui/slider.h" void edit_instrument_event(SDL_Event *e); void sequence_event(SDL_Event *e); void pattern_event(SDL_Event *e); void edit_program_event(SDL_Event *e); void edit_text(SDL_Event *e); int generic_edit_text(SDL_Event *e, char *edit_buffer, size_t edit_buffer_size, int *editpos); void fx_event(SDL_Event *e); void fx_add_param(int d); void wave_event(SDL_Event *e); void wave_add_param(int d); void songinfo_event(SDL_Event *e); void songinfo_add_param(int d); void instrument_add_param(int a); void del_sequence(int first,int last,int track); void add_sequence(int channel, int position, int pattern, int offset); void set_room_size(int fx, int size, int vol, int dec); void update_position_sliders(); void update_horiz_sliders(); void note_event(SDL_Event *e); enum { PED_NOTE, PED_INSTRUMENT1, PED_INSTRUMENT2, PED_VOLUME1, PED_VOLUME2, PED_LEGATO, PED_SLIDE, PED_VIB, PED_COMMAND1, PED_COMMAND2, PED_COMMAND3, PED_COMMAND4, PED_PARAMS }; #define PED_CTRL PED_LEGATO enum { P_INSTRUMENT, P_NAME, P_BASENOTE, P_FINETUNE, P_LOCKNOTE, P_DRUM, P_KEYSYNC, P_INVVIB, P_SETPW, P_SETCUTOFF, P_SLIDESPEED, P_PULSE, P_PW, P_SAW, P_TRIANGLE, P_NOISE, P_METAL, P_LFSR, P_LFSRTYPE, P_1_4TH, P_WAVE, P_WAVE_ENTRY, P_WAVE_OVERRIDE_ENV, P_WAVE_LOCK_NOTE, P_VOLUME, P_RELVOL, P_ATTACK, P_DECAY, P_SUSTAIN, P_RELEASE, P_BUZZ, P_BUZZ_SEMI, P_BUZZ_FINE, P_BUZZ_SHAPE, P_SYNC, P_SYNCSRC, P_RINGMOD, P_RINGMODSRC, P_FILTER, P_FLTTYPE, P_CUTOFF, P_RESONANCE, P_FX, P_FXBUS, P_VIBSPEED, P_VIBDEPTH, P_VIBSHAPE, P_VIBDELAY, P_PWMSPEED, P_PWMDEPTH, P_PWMSHAPE, P_PROGPERIOD, P_NORESTART, P_MULTIOSC, P_FM_ENABLE, P_FM_MODULATION, P_FM_FEEDBACK, P_FM_HARMONIC_CARRIER, P_FM_HARMONIC_MODULATOR, P_FM_ATTACK, P_FM_DECAY, P_FM_SUSTAIN, P_FM_RELEASE, P_FM_ENV_START, P_FM_WAVE, P_FM_WAVE_ENTRY, /*----------*/ P_PARAMS }; enum { W_WAVE, W_NAME, W_RATE, W_BASE, W_BASEFINE, W_INTERPOLATE, W_LOOP, W_LOOPBEGIN, W_LOOPPINGPONG, W_LOOPEND, W_NUMOSCS, W_OSCTYPE, W_OSCMUL, W_OSCSHIFT, W_OSCEXP, W_OSCABS, W_OSCNEG, W_WAVELENGTH, W_RNDGEN, W_GENERATE, W_RND, W_TOOLBOX, /* ----- */ W_N_PARAMS }; enum { R_MULTIPLEX, R_MULTIPLEX_PERIOD, R_PITCH_INACCURACY, R_FX_BUS, R_FX_BUS_NAME, R_CRUSH, R_CRUSHBITS, R_CRUSHDOWNSAMPLE, R_CRUSHDITHER, R_CRUSHGAIN, R_CHORUS, R_MINDELAY, R_MAXDELAY, R_SEPARATION, R_RATE, R_ENABLE, R_ROOMSIZE, R_ROOMVOL, R_ROOMDECAY, R_SNAPTICKS, R_TAPENABLE, R_TAP, R_DELAY, R_GAIN, R_PANNING, /* ---- */ R_N_PARAMS }; enum { SI_LENGTH, SI_LOOP, SI_STEP, SI_SPEED1, SI_SPEED2, SI_RATE, SI_TIME, SI_OCTAVE, SI_CHANNELS, SI_MASTERVOL, /*--------*/ SI_N_PARAMS }; #endif klystrack-0.20171212/klystrack/src/export.h0000644000000000000000000000235613214501362017111 0ustar rootroot#ifndef EXPORT_H #define EXPORT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "snd/music.h" void export_wav(MusSong *song, CydWavetableEntry * entry, FILE *f, int channel); #endif klystrack-0.20171212/klystrack/src/wave.h0000644000000000000000000000265513214501362016534 0ustar rootroot#ifndef WAVE_H #define WAVE_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include enum { WAVE_FORMAT_PCM = 1, WAVE_FORMAT_FLOAT = 3 }; typedef struct { int format; Uint16 channels; Uint32 sample_rate; Uint32 length; Uint16 bits_per_sample; void *data; } Wave; Wave * wave_load(FILE *f); void wave_destroy(Wave *wave); #endifklystrack-0.20171212/klystrack/src/mused.h0000644000000000000000000001573513214501362016712 0ustar rootroot#ifndef MUSED_H #define MUSED_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "snd/music.h" #include "gfx/font.h" #include "console.h" #include "gui/slider.h" #include "edit.h" enum { EDITPATTERN, EDITSEQUENCE, EDITCLASSIC, EDITINSTRUMENT, EDITFX, EDITWAVETABLE, /* Focuses */ EDITPROG, EDITSONGINFO, /* Virtual modes, i.e. what are not modes itself but should be considered happening "inside" prev_mode */ EDITBUFFER, MENU }; #define N_VIEWS EDITPROG #define VIRTUAL_MODE EDITBUFFER #include "clipboard.h" #include "copypaste.h" #include "gui/menu.h" #include "undo.h" #include #include "wavegen.h" #include "diskop.h" #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 enum { COMPACT_VIEW = 1, SONG_PLAYING = 2, FULLSCREEN = 4, MULTICHANNEL_PREVIEW = 8, SHOW_PATTERN_POS_OFFSET = 16, FOLLOW_PLAY_POSITION = 32, ANIMATE_CURSOR = 64, HIDE_ZEROS = 128, DELETE_EMPTIES = 256, EDIT_MODE = 512, SHOW_ANALYZER = 2048, #ifdef MIDI MIDI_SYNC = 4096, #endif SHOW_LOGO = 8192, SHOW_DECIMALS = 16384, LOOP_POSITION = 32768, LOCK_SEQUENCE_STEP_AND_PATTERN_LENGTH = 65536, SHOW_DELAY_IN_TICKS = 65536 << 1, EDIT_SEQUENCE_DIGITS = 65536 << 2, EXPAND_ONLY_CURRENT_TRACK = 65536 << 3, DISABLE_NOSTALGY = 65536 << 4, TOGGLE_EDIT_ON_STOP = 65536 << 5, STOP_EDIT_ON_PLAY = 65536 << 6, MULTIKEY_JAMMING = 65536 << 7, DISABLE_VU_METERS = 65536 << 8, WINDOW_MAXIMIZED = 65536 << 9, SHOW_WAVEGEN = 65536 << 10, DISABLE_RENDER_TO_TEXTURE = 65536 << 11, DISABLE_BACKUPS = 65536 << 12, START_WITH_TEMPLATE = 65536 << 13, USE_SYSTEM_CURSOR = 65536 << 14, }; enum { VC_INSTRUMENT = 1, VC_VOLUME = 2, VC_CTRL = 4, VC_COMMAND = 8 }; enum { VIS_SPECTRUM = 0, VIS_CATOMETER = 1, VIS_NUM_TOTAL }; typedef struct { Uint32 flags, visible_columns; int done; Console *console; MusSong song; CydEngine cyd; MusEngine mus; int octave, instrument_page, current_instrument, default_pattern_length, selected_param, editpos, mode, focus, current_patternx, current_patternpos, current_sequencepos, sequenceview_steps, single_pattern_edit, prev_mode, current_sequenceparam, instrument_list_position, pattern_position, sequence_position, pattern_horiz_position, sequence_horiz_position, program_position, current_program_step, edit_reverb_param, selected_wavetable, wavetable_param, songinfo_param, loop_store_length, loop_store_loop, note_jump, wavetable_list_position, wavetable_preview_idx, sequence_digit; int current_sequencetrack; Uint16 time_signature; Clipboard cp; char * edit_buffer; int edit_buffer_size; SliderParam sequence_slider_param, pattern_slider_param, program_slider_param, instrument_list_slider_param, pattern_horiz_slider_param, sequence_horiz_slider_param, wavetable_list_slider_param; char previous_song_filename[1000], previous_export_filename[1000], previous_filebox_path[OD_T_N_TYPES][1000]; /*---*/ char * edit_backup_buffer; Selection selection; /* -- stat -- */ int stat_song_position; int stat_pattern_position[MUS_MAX_CHANNELS]; MusPattern *stat_pattern[MUS_MAX_CHANNELS]; MusChannel *channel; int stat_pattern_number[MUS_MAX_CHANNELS], stat_note[MUS_MAX_CHANNELS]; Uint64 time_played, play_start_at; /* ---- */ char info_message[256]; SDL_TimerID info_message_timer; GfxSurface *slider_bevel, *vu_meter, *analyzer, *logo, *catometer; Font smallfont, largefont, tinyfont, tinyfont_sequence_counter, tinyfont_sequence_normal; SDL_Cursor *mouse_cursor; GfxSurface *mouse_cursor_surface; GfxSurface *icon_surface; /* for menu */ Font menufont, menufont_selected, headerfont, headerfont_selected, shortcutfont, shortcutfont_selected, buttonfont; char themename[100], keymapname[100]; int pixel_scale; int mix_rate, mix_buffer; int window_w, window_h; int fx_bus, fx_room_size, fx_room_vol, fx_room_dec, fx_tap, fx_axis, fx_room_ticks, fx_room_prev_x, fx_room_prev_y; /*---vis---*/ int current_visualizer; struct { int cyd_env[MUS_MAX_CHANNELS]; int spec_peak[96], spec_peak_decay[96]; float prev_a; } vis; /*---*/ SDL_Rect cursor_target, cursor; /*----------*/ UndoStack undo; UndoStack redo; SHType last_snapshot; int last_snapshot_a, last_snapshot_b; bool modified; /*------------*/ GfxSurface *wavetable_preview; Uint16 wavetable_bits; int prev_wavetable_x, prev_wavetable_y; #ifdef MIDI Uint32 midi_device; Uint8 midi_channel; bool midi_start; Uint16 midi_rate; Uint32 midi_last_clock; Uint8 tick_ctr; #endif WgSettings wgset; int selected_wg_osc, selected_wg_preset; int oversample; } Mused; extern Mused mused; extern GfxDomain *domain; extern Uint32 pattern_color[16]; #define NUM_PATTERNS 4096 #define NUM_INSTRUMENTS 128 #define NUM_SEQUENCES 2048 void default_settings(); void change_mode(int newmode); void clear_pattern(MusPattern *pat); void clear_pattern_range(MusPattern *pat, int first, int last); void init(MusInstrument *instrument, MusPattern *pattern, MusSeqPattern sequence[MUS_MAX_CHANNELS][NUM_SEQUENCES], MusChannel *channel); void deinit(); void new_song(); void kt_default_instrument(MusInstrument *instrument); void set_edit_buffer(char *buffer, size_t size); void change_pixel_scale(void *a, void*b, void*c); void mirror_flags(); void resize_pattern(MusPattern * pattern, Uint16 new_size); void init_scrollbars(); void my_open_menu(); int viscol(int col); void post_config_load(); void enable_callback(bool state); int get_pattern(int abspos, int track); int get_patternstep(int abspos, int track); int current_pattern(); int current_pattern_for_channel(int channel); int current_patternstep(); MusStep * get_current_step(); MusPattern * get_current_pattern(); void change_visualizer(int vis); void set_info_message(const char *string, ...) __attribute__ ((format (printf, 1, 2))); void set_channels(int channels); Uint32 get_playtime_at(int position); #endif klystrack-0.20171212/klystrack/src/memwriter.c0000644000000000000000000000414013214501362017567 0ustar rootroot#include "memwriter.h" #include "macros.h" #include #include static Sint64 mw_size(SDL_RWops *ops) { MemWriter *mem = ops->hidden.unknown.data1; return mem->size; } static Sint64 mw_seek(SDL_RWops *ops, Sint64 position, int mode) { MemWriter *mem = ops->hidden.unknown.data1; switch (mode) { case RW_SEEK_SET: mem->position = position; break; case RW_SEEK_CUR: mem->position += position; break; case RW_SEEK_END: mem->position = mem->size - position; break; } return mem->position; } static size_t mw_read(SDL_RWops *ops, void *data, size_t size, size_t num) { return 0; } static size_t mw_write(SDL_RWops *ops, const void *data, size_t size, size_t num) { MemWriter *mem = ops->hidden.unknown.data1; if (mem->position + size * num > mem->allocated) { int chunk = mem->position + size * num - mem->allocated; if (chunk < 1024) chunk = 1024; mem->allocated = mem->allocated + chunk; mem->data = realloc(mem->data, mem->allocated); debug("MemWriter: Allocating %d bytes (%d bytes allocated total)", chunk, (int)mem->allocated); } memcpy(mem->data + mem->position, data, size * num); mem->position += size * num; if (mem->size < mem->position) { mem->size = mem->position; } return size * num; } static int mw_close(SDL_RWops *ops) { MemWriter *mem = ops->hidden.unknown.data1; int r = 0; if (mem->flush) { debug("MemWriter: Flushing %d bytes to disk", (int)mem->size); r = fwrite(mem->data, mem->size, 1, mem->flush) == mem->size ? 0 : -1; } free(mem->data); free(mem); SDL_FreeRW(ops); return r; } SDL_RWops * create_memwriter(FILE *flush) { MemWriter *mem = malloc(sizeof(*mem)); mem->position = 0; mem->data = NULL; mem->size = 0; mem->allocated = 0; mem->flush = flush; SDL_RWops *ops = SDL_AllocRW(); ops->seek = mw_seek; ops->write = mw_write; ops->read = mw_read; ops->close = mw_close; ops->size = mw_size; ops->type =0x1234; ops->hidden.unknown.data1 = mem; return ops; } klystrack-0.20171212/klystrack/src/wavewriter.h0000644000000000000000000000077213214501362017767 0ustar rootroot#ifndef WAVEWRITER_H #define WAVEWRITER_H #include #include "SDL.h" typedef struct { FILE *file; int channels; size_t chunksize_pos, riffsize_pos; } WaveWriter; /* Create WaveWriter with sample rate of rate/16-bits and start writing to file */ WaveWriter * ww_create(FILE * file, int sample_rate, int channels); /* Write channels * samples Sint16's */ void ww_write(WaveWriter *ww, Sint16 * buffer, int samples); /* Close file and free WaveWriter */ void ww_finish(WaveWriter *ww); #endif klystrack-0.20171212/klystrack/src/command.c0000644000000000000000000001776613214501362017214 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "command.h" #include "snd/music.h" #include "snd/freqs.h" #include "macros.h" #include #include "mused.h" #include "view.h" static const InstructionDesc instruction_desc[] = { {MUS_FX_END, 0xffff, "Program end", "PrgEnd", 0, 0}, {MUS_FX_NOP, 0xffff, "No operation", "Nop", 0, 0}, {MUS_FX_JUMP, 0xff00, "Goto", NULL, -1, -1}, {MUS_FX_LABEL, 0xff00, "Loop begin", "Begin", 0, 0}, {MUS_FX_LOOP, 0xff00, "Loop end", "Loop", -1, -1}, {MUS_FX_ARPEGGIO, 0x7f00, "Set arpeggio note", "Arp", -1, -1}, {MUS_FX_ARPEGGIO_ABS, 0x7f00, "Set absolute arpeggio note", "AbsArp", 0, FREQ_TAB_SIZE - 1}, {MUS_FX_SET_EXT_ARP, 0x7f00, "Set external arpeggio notes", "ExtArp", -1, -1}, {MUS_FX_PORTA_UP, 0x7f00, "Portamento up", "PortUp", -1, -1}, {MUS_FX_PORTA_DN, 0x7f00, "Portamento down", "PortDn", -1, -1}, {MUS_FX_PORTA_UP_LOG, 0x7f00, "Portamento up (curve)", "PortUpC", -1, -1}, {MUS_FX_PORTA_DN_LOG, 0x7f00, "Portamento down (curve)", "PortDnC", -1, -1}, {MUS_FX_EXT_NOTE_DELAY, 0x7ff0, "Note delay", "Delay", -1, -1}, {MUS_FX_VIBRATO, 0x7f00, "Vibrato", NULL, -1, -1}, {MUS_FX_SLIDE, 0x7f00, "Slide", NULL, -1, -1}, {MUS_FX_PORTA_UP_SEMI, 0x7f00, "Portamento up (semitones)", "PortUpST", -1, -1}, {MUS_FX_PORTA_DN_SEMI, 0x7f00, "Portamento down (semitones)", "PortDnST", -1, -1}, {MUS_FX_CUTOFF_UP, 0x7f00, "Filter cutoff up", "CutoffUp", -1, -1}, {MUS_FX_CUTOFF_DN, 0x7f00, "Filter cutoff down", "CutoffDn", -1, -1}, {MUS_FX_CUTOFF_SET, 0x7f00, "Set filter cutoff", "Cutoff", 0, 0xff}, {MUS_FX_CUTOFF_SET_COMBINED, 0x7f00, "Set combined cutoff", "CutoffAHX", 0, 0xff}, {MUS_FX_RESONANCE_SET, 0x7f00, "Set filter resonance", "Resonance", 0, 3}, {MUS_FX_FILTER_TYPE, 0x7f00, "Set filter type", "FltType", 0, 2}, {MUS_FX_PW_DN, 0x7f00, "PW down", "PWDn", -1, -1}, {MUS_FX_PW_UP, 0x7f00, "PW up", "PWUp", -1, -1}, {MUS_FX_PW_SET, 0x7f00, "Set PW", "PW", -1, -1}, {MUS_FX_SET_VOLUME, 0x7f00, "Set volume", "Volume", 0, 0xff}, {MUS_FX_FADE_GLOBAL_VOLUME, 0x7f00, "Global volume fade", "GlobFade", -1, -1}, {MUS_FX_SET_GLOBAL_VOLUME, 0x7f00, "Set global volume", "GlobVol", 0, MAX_VOLUME}, {MUS_FX_SET_CHANNEL_VOLUME, 0x7f00, "Set channel volume", "ChnVol", 0, MAX_VOLUME}, {MUS_FX_SET_WAVEFORM, 0x7f00, "Set waveform", "Waveform", 0, 0xff}, {MUS_FX_SET_WAVETABLE_ITEM, 0x7f00, "Set wavetable item", "Wavetable", 0, CYD_WAVE_MAX_ENTRIES - 1}, {MUS_FX_SET_FXBUS, 0x7f00, "Set FX bus", "SetFxBus", 0, CYD_MAX_FX_CHANNELS - 1}, {MUS_FX_SET_RINGSRC, 0x7f00, "Set ring modulation source (FF=off)", "SetRingSrc", 0, 0xff}, {MUS_FX_SET_SYNCSRC, 0x7f00, "Set sync source (FF=off)", "SetSyncSrc", 0, 0xff}, {MUS_FX_SET_DOWNSAMPLE, 0x7f00, "Set downsample", "SetDnSmp", 0, 0xff}, {MUS_FX_SET_SPEED, 0x7f00, "Set speed", "Speed", -1, -1}, {MUS_FX_SET_RATE, 0x7f00, "Set rate", "Rate", -1, -1}, {MUS_FX_LOOP_PATTERN, 0x7f00, "Loop pattern", "PatLoop", -1, -1}, {MUS_FX_SKIP_PATTERN, 0x7f00, "Skip pattern", "PatSkip", -1, -1}, {MUS_FX_TRIGGER_RELEASE, 0x7f00, "Trigger release", "Release", 0, 0xff}, {MUS_FX_RESTART_PROGRAM, 0x7f00, "Restart program", "Restart", 0, 0}, {MUS_FX_FADE_VOLUME, 0x7f00, "Fade volume", "VolFade", -1, -1}, {MUS_FX_EXT_FADE_VOLUME_UP, 0x7ff0, "Fine fade volume in", "VolUpFine", 0, 0xf}, {MUS_FX_EXT_FADE_VOLUME_DN, 0x7ff0, "Fine fade volume out", "VolDnFine", 0, 0xf}, {MUS_FX_EXT_PORTA_UP, 0x7ff0, "Fine portamento up", "PortUpFine", 0, 0xf}, {MUS_FX_EXT_PORTA_DN, 0x7ff0, "Fine portamento down", "PortDnFine", 0, 0xf}, {MUS_FX_EXT_NOTE_CUT, 0x7ff0, "Note cut", "NoteCut", 0, 0xf}, {MUS_FX_EXT_RETRIGGER, 0x7ff0, "Retrigger", "Retrig", 0, 0xf}, {MUS_FX_WAVETABLE_OFFSET, 0x7000, "Wavetable offset", "WaveOffs", 0, 0xfff}, {MUS_FX_SET_PANNING, 0x7f00, "Set panning", "SetPan", -1, -1}, {MUS_FX_PAN_LEFT, 0x7f00, "Pan left", "PanLeft", -1, -1}, {MUS_FX_PAN_RIGHT, 0x7f00, "Pan right", "PanRight", -1, -1}, {MUS_FX_BUZZ_UP, 0x7f00, "Tune buzz up", "BuzzUp", -1, -1}, {MUS_FX_BUZZ_DN, 0x7f00, "Tune buzz down", "BuzzDn", -1, -1}, {MUS_FX_BUZZ_SHAPE, 0x7f00, "Set buzz shape", "BuzzShape", 0, 3}, {MUS_FX_BUZZ_SET, 0x7f00, "Set buzz finetune", "BuzzFine", -1, -1}, {MUS_FX_CUTOFF_FINE_SET, 0x7000, "Set filter cutoff (fine)", "CutFine", 0, CYD_CUTOFF_MAX - 1}, {MUS_FX_BUZZ_SET_SEMI, 0x7f00, "Set buzz semitone", "BuzzSemi", -1, -1}, {MUS_FX_FM_SET_MODULATION, 0x7f00, "Set FM modulation", "FMMod", 0, 0x7f}, {MUS_FX_FM_SET_FEEDBACK, 0x7ff0, "Set FM feedback", "FMFB", 0, 7}, {MUS_FX_FM_SET_HARMONIC, 0x7f00, "Set FM multiplier", "Mult", 0, 255}, {MUS_FX_FM_SET_WAVEFORM, 0x7f00, "Set FM waveform", "FMWave", 0, 255}, {0, 0, NULL} }; const InstructionDesc * get_instruction_desc(Uint16 command) { for (int i = 0 ; instruction_desc[i].name != NULL ; ++i) { if (instruction_desc[i].opcode == (command & instruction_desc[i].mask)) { return &instruction_desc[i]; } } return false; } bool is_valid_command(Uint16 command) { return get_instruction_desc(command) != NULL; } void get_command_desc(char *text, size_t buffer_size, Uint16 inst) { const InstructionDesc *i = get_instruction_desc(inst); if (i == NULL) { strcpy(text, "Unknown\n"); return; } const char *name = i->name; const Uint16 fi = i->opcode; if ((fi & 0x7f00) == MUS_FX_SET_WAVEFORM) { if (inst & 0xff) snprintf(text, buffer_size, "%s (%s%s%s%s%s%s)\n", name, (inst & MUS_FX_WAVE_NOISE) ? "N" : "", (inst & MUS_FX_WAVE_SAW) ? "S" : "", (inst & MUS_FX_WAVE_TRIANGLE) ? "T" : "", (inst & MUS_FX_WAVE_PULSE) ? "P" : "", (inst & MUS_FX_WAVE_LFSR) ? "L" : "", (inst & MUS_FX_WAVE_WAVE) ? "W" : ""); else snprintf(text, buffer_size, "%s (None)\n", name); } else if ((fi & 0x7f00) == MUS_FX_FILTER_TYPE) { static const char *fn[FLT_TYPES] = {"LP", "HP", "BP"}; snprintf(text, buffer_size, "%s (%s)\n", name, fn[(inst & 0xf) % FLT_TYPES]); } else if ((fi & 0x7f00) == MUS_FX_BUZZ_SHAPE) { snprintf(text, buffer_size, "%s (%c)\n", name, ((inst & 0xf) % 4) + 0xf0); } else if ((fi & 0x7f00) == MUS_FX_SET_FXBUS) { snprintf(text, buffer_size, "%s (%s)\n", name, mused.song.fx[(inst & 0xf) % CYD_MAX_FX_CHANNELS].name); } else if ((fi & 0x7f00) == MUS_FX_SET_WAVETABLE_ITEM) { snprintf(text, buffer_size, "%s (%s)\n", name, mused.song.wavetable_names[(inst & 0xff)]); } else if ((fi & 0x7f00) == MUS_FX_SET_VOLUME) { snprintf(text, buffer_size, "%s (%+.1f dB)\n", name, percent_to_dB((float)(inst & 0xff) / MAX_VOLUME)); } else snprintf(text, buffer_size, "%s\n", name); } Uint16 validate_command(Uint16 command) { const InstructionDesc *i = get_instruction_desc(command); if (i) { if (i->maxv != -1 && i->minv != -1) { Uint16 v = ((~i->mask) & command) & ~0x8000; Uint16 c = command & 0x8000; v = my_min(i->maxv, my_max(i->minv, v)); command = (command & i->mask) | v | c; } } return command; } const InstructionDesc* list_all_commands() { return instruction_desc; }klystrack-0.20171212/klystrack/src/copypaste.h0000644000000000000000000000253713214501362017600 0ustar rootroot#ifndef COPYPASTE_H #define COPYPASTE_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ typedef struct { int start, end, keydown; } Selection; void copy(); void paste(); void join_paste(); void cut(); void delete(); void begin_selection(int position); void select_range(int position); #endif klystrack-0.20171212/klystrack/src/edit.c0000644000000000000000000002616413214501362016513 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "edit.h" #include "event.h" #include "mused.h" #include "gui/msgbox.h" #include "view/wavetableview.h" #include extern Mused mused; extern GfxDomain *domain; static int find_unused_pattern() { for (int empty = 0 ; empty < NUM_PATTERNS ; ++empty) { int not_empty = 0; for (int s = 0 ; s < mused.song.pattern[empty].num_steps && !not_empty ; ++s) if ((empty == current_pattern() && mused.focus == EDITPATTERN) || (mused.song.pattern[empty].step[s].note != MUS_NOTE_NONE || mused.song.pattern[empty].step[s].ctrl != 0 || mused.song.pattern[empty].step[s].instrument != MUS_NOTE_NO_INSTRUMENT || mused.song.pattern[empty].step[s].command != 0)) not_empty = 1; for (int c = 0 ; c < mused.song.num_channels && !not_empty ; ++c) { for (int i = 0 ; i < mused.song.num_sequences[c] && !not_empty ; ++i) { if (mused.song.sequence[c][i].pattern == empty) not_empty = 1; } } if (!not_empty) return empty; } msgbox(domain, mused.slider_bevel, &mused.largefont, "Max patterns exceeded!", MB_OK); return -1; } static void set_pattern(int pattern) { //if ((mused.focus == EDITPATTERN && !mused.single_pattern_edit) || mused.focus != EDITPATTERN) { debug("setting pattern to %d at %d", pattern, mused.current_sequencepos); snapshot(S_T_SEQUENCE); for (int i = 0 ; i < mused.song.num_sequences[mused.current_sequencetrack] ; ++i) { if (mused.song.sequence[mused.current_sequencetrack][i].position == mused.current_sequencepos && mused.song.sequence[mused.current_sequencetrack][i].pattern == current_pattern()) mused.song.sequence[mused.current_sequencetrack][i].pattern = pattern; } } } void clone_pattern(void *unused1, void *unused2, void *unused3) { debug("Cloning pattern"); int empty = find_unused_pattern(); int cp = current_pattern(); if (empty == -1 || cp == empty || cp < 0) { return; } mused.song.pattern[empty].color = mused.song.pattern[cp].color; resize_pattern(&mused.song.pattern[empty], mused.song.pattern[cp].num_steps); memcpy(mused.song.pattern[empty].step, mused.song.pattern[cp].step, mused.song.pattern[cp].num_steps * sizeof(mused.song.pattern[cp].step[0])); set_pattern(empty); set_info_message("Cloned pattern %02X to %02X", cp, empty); } void clone_each_pattern(void *unused1, void *unused2, void *unused3) { debug("Cloning each pattern"); int temp = mused.current_sequencetrack; for (int i = 0 ; i < mused.song.num_channels ; ++i) { mused.current_sequencetrack = i; clone_pattern(NULL, NULL, NULL); } mused.current_sequencetrack = temp; set_info_message("Cloned sequence row"); } void get_unused_pattern(void *unused1, void *unused2, void *unused3) { int empty = find_unused_pattern(); if (empty == -1 || (current_pattern() == empty && mused.focus == EDITPATTERN)) { return; } if (mused.focus == EDITSEQUENCE) { snapshot(S_T_SEQUENCE); bool found = false; for (int i = 0 ; i < mused.song.num_sequences[mused.current_sequencetrack] ; ++i) { if (mused.song.sequence[mused.current_sequencetrack][i].position == mused.current_sequencepos && mused.song.sequence[mused.current_sequencetrack][i].pattern == current_pattern()) found = true; } if (!found) add_sequence(mused.current_sequencetrack, mused.current_sequencepos, empty, 0); } set_pattern(empty); } void get_unused_pattern_all_tracks(void *unused1, void *unused2, void *unused3) { int temp = mused.current_sequencetrack; for (int i = 0 ; i < mused.song.num_channels ; ++i) { mused.current_sequencetrack = i; get_unused_pattern(0, 0, 0); } mused.current_sequencetrack = temp; } void zero_step(MusStep *step) { step->note = MUS_NOTE_NONE; step->instrument = MUS_NOTE_NO_INSTRUMENT; step->volume = MUS_NOTE_NO_VOLUME; step->ctrl = 0; step->command = 0; } void expand_pattern(void *factor, void *unused2, void *unused3) { if (mused.focus != EDITPATTERN) return; MusPattern *pattern = get_current_pattern(); if (!pattern) return; MusStep *temp = malloc(pattern->num_steps * sizeof(pattern->step[0])); memcpy(temp, pattern->step, pattern->num_steps * sizeof(pattern->step[0])); snapshot(S_T_PATTERN); resize_pattern(pattern, pattern->num_steps * CASTPTR(int,factor)); for (int i = 0 ; i < pattern->num_steps ; ++i) { zero_step(&pattern->step[i]); } for (int i = 0, ti = 0 ; i < pattern->num_steps ; ++i) { if ((i % CASTPTR(int,factor)) == 0) { memcpy(&pattern->step[i], &temp[ti], sizeof(pattern->step[i])); ++ti; } } free(temp); } void shrink_pattern(void *factor, void *unused2, void *unused3) { if (mused.focus != EDITPATTERN) return; MusPattern *pattern = get_current_pattern(); if (!pattern) return; if (pattern->num_steps <= CASTPTR(int,factor)) return; snapshot(S_T_PATTERN); resize_pattern(pattern, pattern->num_steps / CASTPTR(int,factor)); for (int i = 0, ti = 0 ; i < pattern->num_steps ; ++i, ti += CASTPTR(int,factor)) { memcpy(&pattern->step[i], &pattern->step[ti], sizeof(pattern->step[i])); } } void interpolate(void *unused1, void *unused2, void *unused3) { if (mused.focus != EDITPATTERN || mused.selection.start >= mused.selection.end - 1) return; MusPattern *pat = get_current_pattern(); if (!pat) return; int start_step = get_patternstep(mused.selection.start, mused.current_sequencetrack); Uint16 command = pat->step[start_step].command; Uint16 mask = 0xff00; if ((command & 0xf000) == MUS_FX_CUTOFF_FINE_SET || (command & 0xf000) == MUS_FX_WAVETABLE_OFFSET) mask = 0xf000; command &= mask; int begin = pat->step[start_step].command & ~mask; int end = pat->step[start_step + mused.selection.end - 1 - mused.selection.start].command & ~mask; int l = mused.selection.end - mused.selection.start - 1; snapshot(S_T_PATTERN); for (int i = start_step, p = 0 ; p < mused.selection.end - mused.selection.start ; ++i, ++p) { if ((pat->step[i].command & mask) == command) { Uint16 val = begin + (end - begin) * p / l; pat->step[i].command = command | val; } } } void snapshot(SHType type) { snapshot_cascade(type, -1, -1); } void snapshot_cascade(SHType type, int a, int b) { if (!(a != -1 && mused.last_snapshot == type && mused.last_snapshot_a == a && mused.last_snapshot_b == b)) { switch (type) { case S_T_PATTERN: undo_store_pattern(&mused.undo, current_pattern(), &mused.song.pattern[current_pattern()], mused.modified); break; case S_T_SEQUENCE: undo_store_sequence(&mused.undo, mused.current_sequencetrack, mused.song.sequence[mused.current_sequencetrack], mused.song.num_sequences[mused.current_sequencetrack], mused.modified); break; case S_T_MODE: undo_store_mode(&mused.undo, mused.mode, mused.focus, mused.modified); break; case S_T_FX: undo_store_fx(&mused.undo, mused.fx_bus, &mused.song.fx[mused.fx_bus], mused.song.multiplex_period, mused.modified); break; case S_T_SONGINFO: undo_store_songinfo(&mused.undo, &mused.song, mused.modified); break; case S_T_INSTRUMENT: undo_store_instrument(&mused.undo, mused.current_instrument, &mused.song.instrument[mused.current_instrument], mused.modified); break; case S_T_WAVE_PARAM: undo_store_wave_param(&mused.undo, mused.selected_wavetable, &mused.mus.cyd->wavetable_entries[mused.selected_wavetable], mused.modified); break; case S_T_WAVE_DATA: undo_store_wave_data(&mused.undo, mused.selected_wavetable, &mused.mus.cyd->wavetable_entries[mused.selected_wavetable], mused.modified); break; case S_T_WAVE_NAME: undo_store_wave_name(&mused.undo, mused.selected_wavetable, mused.song.wavetable_names[mused.selected_wavetable], mused.modified); break; default: warning("SHType %d not implemented", type); break; } } mused.last_snapshot = type; mused.last_snapshot_a = a; mused.last_snapshot_b = b; if (type != S_T_MODE) mused.modified = true; } void transpose_note_data(void *semitones, void *unused1, void *unused2) { if (mused.focus != EDITPATTERN || mused.selection.start >= mused.selection.end - 1) return; MusPattern *pat = get_current_pattern(); if (!pat) return; snapshot(S_T_PATTERN); debug("Transposing pattern %d (%d-%d)", current_pattern(), mused.selection.start, mused.selection.end); for (int i = get_patternstep(mused.selection.start, mused.current_sequencetrack), p = 0 ; p < mused.selection.end - mused.selection.start ; ++i, ++p) { if (pat->step[i].note != MUS_NOTE_NONE) { int semi = CASTPTR(int,semitones); int note = (int)pat->step[i].note + semi; if (note >= 0 && note < 12 * 8) pat->step[i].note = note; } } } void split_pattern(void *unused1, void *unused2, void *unused3) { if (mused.focus != EDITPATTERN && mused.focus != EDITSEQUENCE) return; MusPattern *pat = get_current_pattern(); if (!pat) return; int step = current_patternstep(); if (step <= 0) return; int empty = find_unused_pattern(); if (empty == -1 || (current_pattern() == empty && mused.focus == EDITPATTERN)) { return; } int cursor_pos; if (mused.focus == EDITSEQUENCE) cursor_pos = mused.current_sequencepos; else cursor_pos = mused.current_patternpos; int cp = current_pattern(); MusPattern *new_pattern = &mused.song.pattern[empty]; // Add new pattern in sequence snapshot(S_T_SEQUENCE); add_sequence(mused.current_sequencetrack, cursor_pos, empty, 0); // Copy latter half to the new pattern snapshot(S_T_PATTERN); resize_pattern(new_pattern, pat->num_steps - step); memcpy(new_pattern->step, &pat->step[step], sizeof(pat->step[0]) * ((int)pat->num_steps - step)); // Resize old pattern snapshot(S_T_PATTERN); resize_pattern(pat, step); set_info_message("Split %02X into %02X and %02X", cp, cp, empty); } klystrack-0.20171212/klystrack/src/clipboard.c0000644000000000000000000000434313214501362017520 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "clipboard.h" #include void cp_clear(Clipboard *cp) { if (cp->data != NULL) free(cp->data); cp->data = NULL; cp->size = 0; cp->type = 0; } void cp_copy(Clipboard *cp, int type, void *data, const size_t size, int position) { if (cp->data != NULL) free(cp->data); cp->data = malloc(size); memcpy(cp->data, data, size); cp->size = size; cp->type = type; cp->position = position; } void cp_paste(Clipboard *cp, int target_type, void *dest, const size_t buffer_size) { if (target_type != cp->type || buffer_size == 0) return; memcpy(dest, cp->data, (buffer_size == ALL_ITEMS || buffer_size > cp->size) ? cp->size : buffer_size); } void cp_paste_items(Clipboard *cp, int target_type, void *dest, const size_t dest_items, const size_t item_size) { cp_paste(cp, target_type, dest, dest_items * item_size); } size_t cp_get_item_count(Clipboard *cp, const size_t item_size) { return cp->size / item_size; } void cp_copy_items(Clipboard *cp, int type, void *data, const size_t dest_items, const size_t item_size, int position) { cp_copy(cp, type, data, dest_items * item_size, position); } klystrack-0.20171212/klystrack/src/zap.c0000644000000000000000000000562213214501362016354 0ustar rootroot#include "zap.h" #include "mused.h" #include "gui/toolutil.h" #include #include "event.h" #include "view/wavetableview.h" void zap_instruments(void* no_confirm, void* b, void* c) { if (!CASTPTR(int, no_confirm) && !confirm(domain, mused.slider_bevel, &mused.largefont, "Zap instruments (no undo)?")) return; debug("Zap instruments"); for (int i = 0 ; i < NUM_INSTRUMENTS ; ++i) { MusInstrument *inst = &mused.song.instrument[i]; kt_default_instrument(inst); } } void zap_sequence(void* no_confirm, void* b, void* c) { if (!CASTPTR(int, no_confirm) && !confirm(domain, mused.slider_bevel, &mused.largefont, "Zap sequence (no undo)?")) return; debug("Zap sequence"); for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { memset(mused.song.sequence[i], 0, NUM_SEQUENCES * sizeof(MusSeqPattern)); mused.song.num_sequences[i] = 0; mused.song.default_volume[i] = MAX_VOLUME; mused.song.default_panning[i] = 0; } for (int i = 0 ; i < NUM_PATTERNS ; ++i) { clear_pattern_range(&mused.song.pattern[i], 0, mused.song.pattern[i].num_steps); resize_pattern(&mused.song.pattern[i], mused.default_pattern_length); } mused.sequence_position = 0; mused.pattern_position = 0; mused.current_sequencepos = 0; mused.current_sequencetrack = 0; mused.song.song_length = 0; mused.song.loop_point = 0; update_position_sliders(); } void zap_fx(void* no_confirm, void* b, void* c) { if (!CASTPTR(int, no_confirm) && !confirm(domain, mused.slider_bevel, &mused.largefont, "Zap FX (no undo)?")) return; debug("Zap FX"); mused.song.flags = 0; for (int fx = 0 ; fx < CYD_MAX_FX_CHANNELS ; ++fx) { mused.song.fx[fx].flags = 0; mused.song.fx[fx].crushex.downsample = 0; mused.song.fx[fx].crush.bit_drop = 4; mused.song.fx[fx].crushex.gain = 128; mused.song.fx[fx].chr.min_delay = 0; mused.song.fx[fx].chr.rate = 40; mused.song.fx[fx].chr.max_delay = 20; strcpy(mused.song.fx[fx].name, ""); for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { mused.song.fx[fx].rvb.tap[i].delay = i * 100 + 50; mused.song.fx[fx].rvb.tap[i].gain = (i + 1) * -30; mused.song.fx[fx].rvb.tap[i].panning = CYD_PAN_CENTER; mused.song.fx[fx].rvb.tap[i].flags = 1; } } mirror_flags(); } void zap_wavetable(void* no_confirm, void* b, void* c) { if (!CASTPTR(int, no_confirm) && !confirm(domain, mused.slider_bevel, &mused.largefont, "Zap wavetable (no undo)?")) return; debug("Zap wavetable"); if (mused.song.wavetable_names) { for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) free(mused.song.wavetable_names[i]); free(mused.song.wavetable_names); } mused.song.wavetable_names = malloc(CYD_WAVE_MAX_ENTRIES * sizeof(char*)); for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { mused.song.wavetable_names[i] = malloc(MUS_WAVETABLE_NAME_LEN + 1); strcpy(mused.song.wavetable_names[i], ""); } if (mused.mus.cyd) cyd_reset_wavetable(mused.mus.cyd); invalidate_wavetable_view(); } klystrack-0.20171212/klystrack/src/zap.h0000644000000000000000000000037713214501362016363 0ustar rootroot#ifndef ZAP_H #define ZAP_H void zap_instruments(void* no_confirm, void* b, void* c); void zap_sequence(void* no_confirm, void* b, void* c); void zap_fx(void* no_confirm, void* b, void* c); void zap_wavetable(void* no_confirm, void* b, void* c); #endif klystrack-0.20171212/klystrack/src/diskop.c0000644000000000000000000006161213214501362017054 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "diskop.h" #include "action.h" #include "gui/toolutil.h" #include "mused.h" #include "macros.h" #include "gui/msgbox.h" #include #include "wave.h" #include "snd/freqs.h" #include "snd/pack.h" #include "view/wavetableview.h" #include #include "memwriter.h" #include #include #include "wavewriter.h" extern Mused mused; extern GfxDomain *domain; int create_backup(char *filename) { char new_filename[1000]; time_t now_time; time(&now_time); struct tm *now_tm = localtime(&now_time); if (!now_tm) return 0; snprintf(new_filename, sizeof(new_filename), "%s.%04d%02d%02d-%02d%02d%02d.backup", filename, now_tm->tm_year + 1900, now_tm->tm_mon + 1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec); return rename(filename, new_filename) == 0; } static void write_wavetable_entry(SDL_RWops *f, const CydWavetableEntry *write_wave, bool write_wave_data) { Uint32 flags = write_wave->flags & ~(CYD_WAVE_COMPRESSED_DELTA|CYD_WAVE_COMPRESSED_GRAY); // need to unmask bits because they're set by bitpack Uint32 sample_rate = write_wave->sample_rate; Uint32 samples = write_wave->samples, loop_begin = write_wave->loop_begin, loop_end = write_wave->loop_end; Uint16 base_note = write_wave->base_note; if (!write_wave_data) { // if the wave is not used and the data is not written, set these to zero too loop_begin = 0; loop_end = 0; samples = 0; } Uint8 *packed = NULL; Uint32 packed_size = 0; if (write_wave->samples > 0 && write_wave_data) { int pack_flags; packed = bitpack_best(write_wave->data, write_wave->samples, &packed_size, &pack_flags); flags |= (Uint32)pack_flags << 3; } FIX_ENDIAN(flags); FIX_ENDIAN(sample_rate); FIX_ENDIAN(samples); FIX_ENDIAN(loop_begin); FIX_ENDIAN(loop_end); FIX_ENDIAN(base_note); SDL_RWwrite(f, &flags, sizeof(flags), 1); SDL_RWwrite(f, &sample_rate, sizeof(sample_rate), 1); SDL_RWwrite(f, &samples, sizeof(samples), 1); SDL_RWwrite(f, &loop_begin, sizeof(loop_begin), 1); SDL_RWwrite(f, &loop_end, sizeof(loop_end), 1); SDL_RWwrite(f, &base_note, sizeof(base_note), 1); if (packed) { FIX_ENDIAN(packed_size); SDL_RWwrite(f, &packed_size, sizeof(packed_size), 1); SDL_RWwrite(f, packed, sizeof(packed[0]), (packed_size + 7) / 8); free(packed); } } /* Write max 255 character string */ static void write_string8(SDL_RWops *f, const char * string) { Uint8 len = strlen(string); SDL_RWwrite(f, &len, sizeof(len), 1); if (len) SDL_RWwrite(f, string, sizeof(string[0]), len); } static void save_instrument_inner(SDL_RWops *f, MusInstrument *inst, const CydWavetableEntry *write_wave, const CydWavetableEntry *write_wave_fm) { Uint32 temp32 = inst->flags; FIX_ENDIAN(temp32); SDL_RWwrite(f, &temp32, sizeof(temp32), 1); temp32 = inst->cydflags; FIX_ENDIAN(temp32); SDL_RWwrite(f, &temp32, sizeof(temp32), 1); SDL_RWwrite(f, &inst->adsr, sizeof(inst->adsr), 1); SDL_RWwrite(f, &inst->sync_source, sizeof(inst->sync_source), 1); SDL_RWwrite(f, &inst->ring_mod, sizeof(inst->ring_mod), 1); Uint16 temp16 = inst->pw; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, sizeof(temp16), 1); SDL_RWwrite(f, &inst->volume, sizeof(inst->volume), 1); Uint8 progsteps = 0; for (int i = 0 ; i < MUS_PROG_LEN ; ++i) if (inst->program[i] != MUS_FX_NOP) progsteps = i+1; SDL_RWwrite(f, &progsteps, sizeof(progsteps), 1); for (int i = 0 ; i < progsteps ; ++i) { temp16 = inst->program[i]; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, sizeof(temp16), 1); } SDL_RWwrite(f, &inst->prog_period, sizeof(inst->prog_period), 1); SDL_RWwrite(f, &inst->vibrato_speed, sizeof(inst->vibrato_speed), 1); SDL_RWwrite(f, &inst->vibrato_depth, sizeof(inst->vibrato_depth), 1); SDL_RWwrite(f, &inst->pwm_speed, sizeof(inst->pwm_speed), 1); SDL_RWwrite(f, &inst->pwm_depth, sizeof(inst->pwm_depth), 1); SDL_RWwrite(f, &inst->slide_speed, sizeof(inst->slide_speed), 1); SDL_RWwrite(f, &inst->base_note, sizeof(inst->base_note), 1); SDL_RWwrite(f, &inst->finetune, sizeof(inst->finetune), 1); write_string8(f, inst->name); temp16 = inst->cutoff; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, sizeof(temp16), 1); SDL_RWwrite(f, &inst->resonance, sizeof(inst->resonance), 1); SDL_RWwrite(f, &inst->flttype, sizeof(inst->flttype), 1); SDL_RWwrite(f, &inst->ym_env_shape, sizeof(inst->ym_env_shape), 1); temp16 = inst->buzz_offset; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, sizeof(temp16), 1); SDL_RWwrite(f, &inst->fx_bus, sizeof(inst->fx_bus), 1); SDL_RWwrite(f, &inst->vib_shape, sizeof(inst->vib_shape), 1); SDL_RWwrite(f, &inst->vib_delay, sizeof(inst->vib_delay), 1); SDL_RWwrite(f, &inst->pwm_shape, sizeof(inst->pwm_shape), 1); SDL_RWwrite(f, &inst->lfsr_type, sizeof(inst->lfsr_type), 1); if (write_wave) { Uint8 temp = 0xff; SDL_RWwrite(f, &temp, sizeof(temp), 1); } else { SDL_RWwrite(f, &inst->wavetable_entry, sizeof(inst->wavetable_entry), 1); } SDL_RWwrite(f, &inst->fm_flags, sizeof(inst->fm_flags), 1); SDL_RWwrite(f, &inst->fm_modulation, sizeof(inst->fm_modulation), 1); SDL_RWwrite(f, &inst->fm_feedback, sizeof(inst->fm_feedback), 1); SDL_RWwrite(f, &inst->fm_harmonic, sizeof(inst->fm_harmonic), 1); SDL_RWwrite(f, &inst->fm_adsr, sizeof(inst->fm_adsr), 1); SDL_RWwrite(f, &inst->fm_attack_start, sizeof(inst->fm_attack_start), 1); if (write_wave_fm) { Uint8 temp = (inst->wavetable_entry == inst->fm_wave) ? 0xfe : 0xff; SDL_RWwrite(f, &temp, sizeof(temp), 1); } else { SDL_RWwrite(f, &inst->fm_wave, sizeof(inst->fm_wave), 1); } if (write_wave) { write_wavetable_entry(f, write_wave, true); } if (write_wave_fm) { if (inst->wavetable_entry != inst->fm_wave) write_wavetable_entry(f, write_wave_fm, true); } } static void save_fx_inner(SDL_RWops *f, CydFxSerialized *fx) { CydFxSerialized temp; memcpy(&temp, fx, sizeof(temp)); FIX_ENDIAN(temp.flags); for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { FIX_ENDIAN(temp.rvb.tap[i].gain); FIX_ENDIAN(temp.rvb.tap[i].delay); } write_string8(f, temp.name); SDL_RWwrite(f, &temp.flags, sizeof(temp.flags), 1); SDL_RWwrite(f, &temp.crush.bit_drop, sizeof(temp.crush.bit_drop), 1); SDL_RWwrite(f, &temp.chr.rate, sizeof(temp.chr.rate), 1); SDL_RWwrite(f, &temp.chr.min_delay, sizeof(temp.chr.min_delay), 1); SDL_RWwrite(f, &temp.chr.max_delay, sizeof(temp.chr.max_delay), 1); SDL_RWwrite(f, &temp.chr.sep, sizeof(temp.chr.sep), 1); for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { SDL_RWwrite(f, &temp.rvb.tap[i].delay, sizeof(temp.rvb.tap[i].delay), 1); SDL_RWwrite(f, &temp.rvb.tap[i].gain, sizeof(temp.rvb.tap[i].gain), 1); SDL_RWwrite(f, &temp.rvb.tap[i].panning, sizeof(temp.rvb.tap[i].panning), 1); SDL_RWwrite(f, &temp.rvb.tap[i].flags, sizeof(temp.rvb.tap[i].flags), 1); } SDL_RWwrite(f, &temp.crushex.downsample, sizeof(temp.crushex.downsample), 1); SDL_RWwrite(f, &temp.crushex.gain, sizeof(temp.crushex.gain), 1); } static void write_packed_pattern(SDL_RWops *f, const MusPattern *pattern, bool skip) { /* Format: 00 1 * byte number of incoming steps 01... n_steps * nibble incoming data ... n_steps * variable data described by bits in nibble If ctrl bit 7 is set, there's also a volume column incoming */ Uint16 steps = pattern->num_steps; if (skip) steps = 0; FIX_ENDIAN(steps); SDL_RWwrite(f, &steps, 1, sizeof(steps)); SDL_RWwrite(f, &pattern->color, 1, sizeof(pattern->color)); Uint8 buffer = 0; for (int i = 0 ; i < steps ; ++i) { if (pattern->step[i].note != MUS_NOTE_NONE) buffer |= MUS_PAK_BIT_NOTE; if (pattern->step[i].instrument != MUS_NOTE_NO_INSTRUMENT) buffer |= MUS_PAK_BIT_INST; if (pattern->step[i].ctrl != 0 || pattern->step[i].volume != MUS_NOTE_NO_VOLUME) buffer |= MUS_PAK_BIT_CTRL; if (pattern->step[i].command != 0) buffer |= MUS_PAK_BIT_CMD; if (i & 1 || i + 1 >= steps) SDL_RWwrite(f, &buffer, 1, sizeof(buffer)); buffer <<= 4; } for (int i = 0 ; i < steps ; ++i) { if (pattern->step[i].note != MUS_NOTE_NONE) SDL_RWwrite(f, &pattern->step[i].note, 1, sizeof(pattern->step[i].note)); if (pattern->step[i].instrument != MUS_NOTE_NO_INSTRUMENT) SDL_RWwrite(f, &pattern->step[i].instrument, 1, sizeof(pattern->step[i].instrument)); if (pattern->step[i].ctrl != 0 || pattern->step[i].volume != MUS_NOTE_NO_VOLUME) { Uint8 ctrl = pattern->step[i].ctrl; if (pattern->step[i].volume != MUS_NOTE_NO_VOLUME) ctrl |= MUS_PAK_BIT_VOLUME; SDL_RWwrite(f, &ctrl, 1, sizeof(pattern->step[i].ctrl)); } if (pattern->step[i].command != 0) { Uint16 c = pattern->step[i].command; FIX_ENDIAN(c); SDL_RWwrite(f, &c, 1, sizeof(pattern->step[i].command)); } if (pattern->step[i].volume != MUS_NOTE_NO_VOLUME) SDL_RWwrite(f, &pattern->step[i].volume, 1, sizeof(pattern->step[i].volume)); } } int open_song(FILE *f) { new_song(); if (!mus_load_song_file(f, &mused.song, mused.mus.cyd->wavetable_entries)) return 0; mused.song.num_patterns = NUM_PATTERNS; mused.song.num_instruments = NUM_INSTRUMENTS; // Use kewlkool heuristics to determine sequence spacing mused.sequenceview_steps = mused.song.sequence_step; if (mused.sequenceview_steps == 0) { mused.sequenceview_steps = 1000; for (int c = 0 ; c < MUS_MAX_CHANNELS ; ++c) for (int s = 1 ; s < mused.song.num_sequences[c] && mused.song.sequence[c][s-1].position < mused.song.song_length ; ++s) if (mused.sequenceview_steps > mused.song.sequence[c][s].position - mused.song.sequence[c][s-1].position) { mused.sequenceview_steps = mused.song.sequence[c][s].position - mused.song.sequence[c][s-1].position; } for (int c = 0 ; c < MUS_MAX_CHANNELS ; ++c) if (mused.song.num_sequences[c] > 0 && mused.song.sequence[c][mused.song.num_sequences[c]-1].position < mused.song.song_length) { if (mused.sequenceview_steps > mused.song.song_length - mused.song.sequence[c][mused.song.num_sequences[c]-1].position) { mused.sequenceview_steps = mused.song.song_length - mused.song.sequence[c][mused.song.num_sequences[c]-1].position; } } if (mused.sequenceview_steps < 1) mused.sequenceview_steps = 1; if (mused.sequenceview_steps == 1000) mused.sequenceview_steps = 16; } mus_set_fx(&mused.mus, &mused.song); enable_callback(true); mirror_flags(); if (!mused.song.time_signature) mused.song.time_signature = 0x404; mused.time_signature = mused.song.time_signature; mused.flags &= ~EDIT_MODE; unmute_all_action(NULL, NULL, NULL); for (int i = 0 ; i < mused.song.num_patterns ; ++i) if(mused.song.pattern[i].num_steps == 0) resize_pattern(&mused.song.pattern[i], mused.default_pattern_length); mused.song.wavetable_names = realloc(mused.song.wavetable_names, sizeof(mused.song.wavetable_names[0]) * CYD_WAVE_MAX_ENTRIES); for (int i = mused.song.num_wavetables ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { mused.song.wavetable_names[i] = malloc(MUS_WAVETABLE_NAME_LEN + 1); memset(mused.song.wavetable_names[i], 0, MUS_WAVETABLE_NAME_LEN + 1); } set_channels(mused.song.num_channels); return 1; } int save_instrument(SDL_RWops *f) { const Uint8 version = MUS_VERSION; SDL_RWwrite(f, MUS_INST_SIG, strlen(MUS_INST_SIG), sizeof(MUS_INST_SIG[0])); SDL_RWwrite(f, &version, 1, sizeof(version)); save_instrument_inner(f, &mused.song.instrument[mused.current_instrument], &mused.mus.cyd->wavetable_entries[mused.song.instrument[mused.current_instrument].wavetable_entry], &mused.mus.cyd->wavetable_entries[mused.song.instrument[mused.current_instrument].fm_wave]); return 1; } int save_fx(SDL_RWops *f) { const Uint8 version = MUS_VERSION; SDL_RWwrite(f, MUS_FX_SIG, strlen(MUS_FX_SIG), sizeof(MUS_FX_SIG[0])); SDL_RWwrite(f, &version, 1, sizeof(version)); save_fx_inner(f, &mused.song.fx[mused.fx_bus]); return 1; } int save_song_inner(SDL_RWops *f, SongStats *stats) { bool kill_unused_things = false; Uint8 n_inst = mused.song.num_instruments; if (!confirm(domain, mused.slider_bevel, &mused.largefont, "Save unused song elements?")) { int maxpat = -1; for (int c = 0 ; c < mused.song.num_channels ; ++c) { for (int i = 0 ; i < mused.song.num_sequences[c] ; ++i) if (maxpat < mused.song.sequence[c][i].pattern) maxpat = mused.song.sequence[c][i].pattern; } n_inst = 0; for (int i = 0 ; i <= maxpat ; ++i) for (int s = 0 ; s < mused.song.pattern[i].num_steps ; ++s) if (mused.song.pattern[i].step[s].instrument != MUS_NOTE_NO_INSTRUMENT) n_inst = my_max(n_inst, mused.song.pattern[i].step[s].instrument + 1); mused.song.num_patterns = maxpat + 1; kill_unused_things = true; } SDL_RWwrite(f, MUS_SONG_SIG, strlen(MUS_SONG_SIG), sizeof(MUS_SONG_SIG[0])); const Uint8 version = MUS_VERSION; mused.song.time_signature = mused.time_signature; mused.song.sequence_step = mused.sequenceview_steps; SDL_RWwrite(f, &version, 1, sizeof(version)); SDL_RWwrite(f, &mused.song.num_channels, 1, sizeof(mused.song.num_channels)); Uint16 temp16 = mused.song.time_signature; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(mused.song.time_signature)); temp16 = mused.song.sequence_step; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(mused.song.sequence_step)); SDL_RWwrite(f, &n_inst, 1, sizeof(mused.song.num_instruments)); temp16 = mused.song.num_patterns; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(mused.song.num_patterns)); for (int i = 0 ; i < mused.song.num_channels ; ++i) { temp16 = mused.song.num_sequences[i]; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(mused.song.num_sequences[i])); } temp16 = mused.song.song_length; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(mused.song.song_length)); temp16 = mused.song.loop_point; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(mused.song.loop_point)); SDL_RWwrite(f, &mused.song.master_volume, 1, 1); SDL_RWwrite(f, &mused.song.song_speed, 1, sizeof(mused.song.song_speed)); SDL_RWwrite(f, &mused.song.song_speed2, 1, sizeof(mused.song.song_speed2)); SDL_RWwrite(f, &mused.song.song_rate, 1, sizeof(mused.song.song_rate)); Uint32 temp32 = mused.song.flags; FIX_ENDIAN(temp32); SDL_RWwrite(f, &temp32, 1, sizeof(mused.song.flags)); SDL_RWwrite(f, &mused.song.multiplex_period, 1, sizeof(mused.song.multiplex_period)); SDL_RWwrite(f, &mused.song.pitch_inaccuracy, 1, sizeof(mused.song.pitch_inaccuracy)); write_string8(f, mused.song.title); if (stats) stats->size[STATS_HEADER] = SDL_RWtell(f); Uint8 n_fx = kill_unused_things ? 0 : CYD_MAX_FX_CHANNELS; if (kill_unused_things) { for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i) { if (mused.song.fx[i].flags & (CYDFX_ENABLE_REVERB | CYDFX_ENABLE_CRUSH | CYDFX_ENABLE_CHORUS)) n_fx = my_max(n_fx, i + 1); } } SDL_RWwrite(f, &n_fx, 1, sizeof(n_fx)); debug("Saving %d fx", n_fx); for (int fx = 0 ; fx < n_fx ; ++fx) { save_fx_inner(f, &mused.song.fx[fx]); } if (stats) stats->size[STATS_FX] = SDL_RWtell(f); SDL_RWwrite(f, &mused.song.default_volume[0], sizeof(mused.song.default_volume[0]), mused.song.num_channels); SDL_RWwrite(f, &mused.song.default_panning[0], sizeof(mused.song.default_panning[0]), mused.song.num_channels); if (stats) stats->size[STATS_DEFVOLPAN] = SDL_RWtell(f); debug("Saving %d instruments", n_inst); for (int i = 0 ; i < n_inst ; ++i) { save_instrument_inner(f, &mused.song.instrument[i], NULL, NULL); } if (stats) stats->size[STATS_INSTRUMENTS] = SDL_RWtell(f); bool *used_pattern = calloc(sizeof(bool), mused.song.num_patterns); for (int i = 0 ; i < mused.song.num_channels; ++i) { for (int s= 0 ; s < mused.song.num_sequences[i] ; ++s) { temp16 = mused.song.sequence[i][s].position; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(temp16)); used_pattern[mused.song.sequence[i][s].pattern] = true; temp16 = mused.song.sequence[i][s].pattern; FIX_ENDIAN(temp16); SDL_RWwrite(f, &temp16, 1, sizeof(temp16)); SDL_RWwrite(f, &mused.song.sequence[i][s].note_offset, 1, sizeof(mused.song.sequence[i][s].note_offset)); } } if (stats) stats->size[STATS_SEQUENCE] = SDL_RWtell(f); for (int i = 0 ; i < mused.song.num_patterns; ++i) { write_packed_pattern(f, &mused.song.pattern[i], !used_pattern[i]); } if (stats) stats->size[STATS_PATTERNS] = SDL_RWtell(f); free(used_pattern); int max_wt = kill_unused_things ? 0 : CYD_WAVE_MAX_ENTRIES; for (int i = 0 ; i < CYD_WAVE_MAX_ENTRIES ; ++i) { if (mused.mus.cyd->wavetable_entries[i].samples) max_wt = my_max(max_wt, i + 1); } FIX_ENDIAN(max_wt); SDL_RWwrite(f, &max_wt, 1, sizeof(Uint8)); debug("Saving %d wavetable items", max_wt); for (int i = 0 ; i < max_wt ; ++i) { write_wavetable_entry(f, &mused.mus.cyd->wavetable_entries[i], true); } if (stats) stats->size[STATS_WAVETABLE] = SDL_RWtell(f); for (int i = 0 ; i < max_wt ; ++i) { write_string8(f, mused.song.wavetable_names[i]); } if (stats) stats->size[STATS_WAVETABLE_NAMES] = SDL_RWtell(f); mused.song.num_patterns = NUM_PATTERNS; mused.song.num_instruments = NUM_INSTRUMENTS; if (stats) { for (int i = N_STATS - 1 ; i > 0 ; --i) { stats->size[i] -= stats->size[i - 1]; } stats->total_size = 0; for (int i = 0 ; i < N_STATS ; ++i) { stats->total_size += stats->size[i]; } } return 1; } int open_wavetable(FILE *f) { Wave *w = wave_load(f); if (w) { cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[mused.selected_wavetable], w->data, w->length, w->bits_per_sample == 16 ? CYD_WAVE_TYPE_SINT16 : CYD_WAVE_TYPE_SINT8, w->channels, 1, 1); mused.mus.cyd->wavetable_entries[mused.selected_wavetable].flags = 0; mused.mus.cyd->wavetable_entries[mused.selected_wavetable].sample_rate = w->sample_rate; mused.mus.cyd->wavetable_entries[mused.selected_wavetable].base_note = MIDDLE_C << 8; wave_destroy(w); invalidate_wavetable_view(); return 1; } return 0; } static int open_wavetable_raw_inner(FILE *f, int t) { size_t pos = ftell(f); fseek(f, 0, SEEK_END); size_t s = ftell(f) - pos; fseek(f, pos, SEEK_SET); if (s > 0) { Sint8 *w = calloc(s, sizeof(Sint8)); if (w) { fread(w, 1, s, f); cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[mused.selected_wavetable], w, s, t, 1, 1, 1); mused.mus.cyd->wavetable_entries[mused.selected_wavetable].flags = 0; mused.mus.cyd->wavetable_entries[mused.selected_wavetable].sample_rate = 8000; mused.mus.cyd->wavetable_entries[mused.selected_wavetable].base_note = MIDDLE_C << 8; free(w); invalidate_wavetable_view(); return 1; } } return 0; } int open_wavetable_raw(FILE *f) { return open_wavetable_raw_inner(f, CYD_WAVE_TYPE_SINT8); } int open_wavetable_raw_u(FILE *f) { return open_wavetable_raw_inner(f, CYD_WAVE_TYPE_UINT8); } int open_instrument(FILE *f) { if (!mus_load_instrument_file2(f, &mused.song.instrument[mused.current_instrument], mused.mus.cyd->wavetable_entries)) return 0; mused.modified = true; invalidate_wavetable_view(); return 1; } int open_fx(FILE *f) { if (!mus_load_fx_file(f, &mused.song.fx[mused.fx_bus])) return 0; mused.modified = true; mus_set_fx(&mused.mus, &mused.song); return 1; } int save_song(SDL_RWops *ops) { int r = save_song_inner(ops, NULL); mused.modified = false; return r; } int save_wavetable(FILE *ops) { WaveWriter *ww = ww_create(ops, mused.mus.cyd->wavetable_entries[mused.selected_wavetable].sample_rate, 1); ww_write(ww, mused.mus.cyd->wavetable_entries[mused.selected_wavetable].data, mused.mus.cyd->wavetable_entries[mused.selected_wavetable].samples); ww_finish(ww); return 1; } void open_data(void *type, void *action, void *_ret) { int t = CASTPTR(int, type); int a = CASTPTR(int, action); int *ret = _ret; if (a == OD_A_OPEN && t == OD_T_SONG) { int r = -1; if (mused.modified) r = confirm_ync(domain, mused.slider_bevel, &mused.largefont, "Save song?"); int ret_val; if (r == 0) { if (ret) *ret = 0; return; } if (r == 1) { stop(0,0,0); // so loop positions set by pattern loop mode will be restored open_data(MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_SAVE), &ret_val); if (!ret_val) { if (ret) *ret = 0; return; } } } const struct { const char *name, *ext; int (*open)(FILE *); int (*save)(SDL_RWops *); } open_stuff[] = { { "song", "kt", open_song, save_song }, { "instrument", "ki", open_instrument, save_instrument }, { "wave", "wav", open_wavetable, NULL }, { "raw signed", "", open_wavetable_raw, NULL }, { "raw unsigned", "", open_wavetable_raw_u, NULL }, { "FX bus", "kx", open_fx, save_fx } }; const char *mode[] = { "rb", "wb" }; const char *modename[] = { "Open", "Save" }; char str[1000]; snprintf(str, sizeof(str), "%s %s", modename[a], open_stuff[t].name); stop(0,0,0); char _def[1024] = ""; char *def = NULL; if (a == OD_A_SAVE) { switch (t) { case OD_T_INSTRUMENT: { snprintf(_def, sizeof(_def), "%s.ki", mused.song.instrument[mused.current_instrument].name); } break; case OD_T_FX: { snprintf(_def, sizeof(_def), "%s.kx", mused.song.fx[mused.fx_bus].name); } break; case OD_T_SONG: { if (strlen(mused.previous_song_filename) == 0) { snprintf(_def, sizeof(_def), "%s.kt", mused.song.title); } else { strncpy(_def, mused.previous_song_filename, sizeof(_def)); } } break; } def = _def; } char filename[5000], previous_cwd[5000]; FILE *f = NULL; SDL_RWops *rw = NULL; // Save current cwd getcwd(previous_cwd, sizeof(previous_cwd)); if (mused.previous_filebox_path[t][0]) chdir(mused.previous_filebox_path[t]); if (open_dialog_fn(mode[a], str, open_stuff[t].ext, domain, mused.slider_bevel, &mused.largefont, &mused.smallfont, def, filename, sizeof(filename))) { getcwd(mused.previous_filebox_path[t], sizeof(mused.previous_filebox_path[t])); if (!(mused.flags & DISABLE_BACKUPS) && a == OD_A_SAVE && !create_backup(filename)) warning("Could not create backup for %s", filename); if (a == OD_A_SAVE && t == OD_T_SONG) strncpy(mused.previous_song_filename, filename, sizeof(mused.previous_song_filename) - 1); f = fopen(filename, mode[a]); if (!f) msgbox(domain, mused.slider_bevel, &mused.largefont, "Could not open file", MB_OK); } if (f) { int return_val = 1; void * tmp; if (a == 0) tmp = open_stuff[t].open; else tmp = open_stuff[t].save; if (tmp || ((t == OD_T_WAVETABLE) && (a == 1))) { cyd_lock(&mused.cyd, 1); int r; if (a == 0) r = open_stuff[t].open(f); else { if (t != OD_T_WAVETABLE) { rw = create_memwriter(f); r = open_stuff[t].save(rw); } else { r = save_wavetable(f); } } cyd_lock(&mused.cyd, 0); if (!r) { snprintf(str, sizeof(str), "Could not open %s!", open_stuff[t].name); msgbox(domain, mused.slider_bevel, &mused.largefont, str, MB_OK); return_val = 0; } else if (a == OD_A_OPEN && t != OD_T_SONG) mused.modified = true; } if (rw) SDL_RWclose(rw); fclose(f); if (ret) *ret = return_val; } else if (ret) *ret = 0; // Restore previous cwd chdir(previous_cwd); change_mode(mused.mode); } klystrack-0.20171212/klystrack/src/mymsg.h0000644000000000000000000000237613214501362016726 0ustar rootroot#ifndef MYMSG_H #define MYMSG_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (SDL_Surface *dest_surface, 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. */ enum { MSG_EVENTHIT = SDL_USEREVENT + 1, MSG_NOTEON, MSG_NOTEOFF, MSG_PROGRAMCHANGE }; #endif klystrack-0.20171212/klystrack/src/action.c0000644000000000000000000006232613214501362017043 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "action.h" #include "optimize.h" #include "mused.h" #include "gui/toolutil.h" #include "view.h" #include "event.h" #include "gui/msgbox.h" #include "version.h" #include "klystron_version.h" #include "gfx/gfx.h" #include "theme.h" #include "key.h" #include "gui/menu.h" #include "export.h" #include #include "gui/mouse.h" #include "view/wavetableview.h" #include "help.h" #include extern Mused mused; extern GfxDomain *domain; extern const Menu mainmenu[]; extern Menu pixelmenu[]; extern Menu patternlengthmenu[]; extern Menu oversamplemenu[]; bool inside_undo = false; void select_sequence_position(void *channel, void *position, void* unused) { if ((mused.flags & SONG_PLAYING) && (mused.flags & FOLLOW_PLAY_POSITION)) return; if (CASTPTR(int,channel) != -1) mused.current_sequencetrack = CASTPTR(int,channel); if (CASTPTR(int,position) < mused.song.song_length) mused.current_sequencepos = CASTPTR(int,position); mused.pattern_position = mused.current_patternpos = mused.current_sequencepos; mused.focus = EDITSEQUENCE; update_horiz_sliders(); } void select_pattern_param(void *id, void *position, void *track) { mused.current_patternx = CASTPTR(int,id); mused.current_sequencetrack = CASTPTR(int,track); mused.pattern_position = mused.current_sequencepos = CASTPTR(int,position); mused.focus = EDITPATTERN; update_horiz_sliders(); } void select_instrument_page(void *page, void *unused1, void *unused2) { mused.instrument_page = CASTPTR(int,page) * 10; set_info_message("Selected instrument bank %d-%d", mused.instrument_page, mused.instrument_page + 9); } void select_instrument(void *idx, void *relative, void *pagey) { if (pagey) { mused.current_instrument = mused.instrument_page + CASTPTR(int,idx); } else { if (relative) mused.current_instrument += CASTPTR(int,idx); else mused.current_instrument = CASTPTR(int,idx); } if (mused.current_instrument >= NUM_INSTRUMENTS) mused.current_instrument = NUM_INSTRUMENTS-1; else if (mused.current_instrument < 0) mused.current_instrument = 0; } void select_wavetable(void *idx, void *unused1, void *unused2) { mused.selected_wavetable = CASTPTR(int,idx); if (mused.selected_wavetable >= CYD_WAVE_MAX_ENTRIES) mused.selected_wavetable = CYD_WAVE_MAX_ENTRIES-1; else if (mused.selected_wavetable < 0) mused.selected_wavetable = 0; } void change_octave(void *delta, void *unused1, void *unused2) { mused.octave += CASTPTR(int,delta); if (mused.octave > 7) mused.octave = 7; else if (mused.octave < 0) mused.octave = 0; } void change_oversample(void *oversample, void *unused1, void *unused2) { cyd_set_oversampling(&mused.cyd, CASTPTR(int,oversample)); mused.oversample = CASTPTR(int,oversample); for (int i = 0 ; i < 4; ++i) { if (oversamplemenu[i].p1 == oversample) oversamplemenu[i].flags |= MENU_BULLET; else oversamplemenu[i].flags &= ~MENU_BULLET; } } void change_song_rate(void *delta, void *unused1, void *unused2) { if (CASTPTR(int,delta) > 0) { if ((int)mused.song.song_rate + CASTPTR(int,delta) <= 0xff) mused.song.song_rate += CASTPTR(int,delta); else mused.song.song_rate = 0xff; } else if (CASTPTR(int,delta) < 0) { if ((int)mused.song.song_rate + CASTPTR(int,delta) >= 0x1) mused.song.song_rate += CASTPTR(int,delta); else mused.song.song_rate = 1; } enable_callback(true); } void change_time_signature(void *beat, void *unused1, void *unused2) { if (!beat) { mused.time_signature = (mused.time_signature & 0x00ff) | (((((mused.time_signature >> 8) + 1) & 0xff) % 17) << 8); if ((mused.time_signature & 0xff00) == 0) mused.time_signature |= 0x100; } else { mused.time_signature = (mused.time_signature & 0xff00) | ((((mused.time_signature & 0xff) + 1) & 0xff) % 17); if ((mused.time_signature & 0xff) == 0) mused.time_signature |= 1; } } void play(void *from_cursor, void *unused1, void *unused2) { int pos = from_cursor ? mused.current_sequencepos : 0; mused.play_start_at = get_playtime_at(pos); enable_callback(true); mus_set_song(&mused.mus, &mused.song, pos); mused.flags |= SONG_PLAYING; if (mused.flags & STOP_EDIT_ON_PLAY) mused.flags &= ~EDIT_MODE; } void play_position(void *unused1, void *unused2, void *unused3) { if (!(mused.flags & LOOP_POSITION)) { int p = current_pattern(), len; if (p < 0) len = mused.sequenceview_steps; else len = mused.song.pattern[p].num_steps; mused.flags |= LOOP_POSITION; mused.loop_store_length = mused.song.song_length; mused.loop_store_loop = mused.song.loop_point; mused.song.song_length = mused.current_sequencepos + len; mused.song.loop_point = mused.current_sequencepos; debug("%d Looping %d-%d", p, mused.current_sequencepos, mused.current_sequencepos + len); play(MAKEPTR(1), 0, 0); } } void stop(void *unused1, void *unused2, void *unused3) { mus_set_song(&mused.mus, NULL, 0); if (mused.flags & LOOP_POSITION) { mused.song.song_length = mused.loop_store_length; mused.song.loop_point = mused.loop_store_loop; } mused.flags &= ~(SONG_PLAYING | LOOP_POSITION); } void change_song_speed(void *speed, void *delta, void *unused) { if (!speed) { if ((int)mused.song.song_speed + CASTPTR(int,delta) >= 1 && (int)mused.song.song_speed + CASTPTR(int,delta) <= 15) mused.song.song_speed += CASTPTR(int,delta); } else { if ((int)mused.song.song_speed2 + CASTPTR(int,delta) >= 1 && (int)mused.song.song_speed2 + CASTPTR(int,delta) <= 15) mused.song.song_speed2 += CASTPTR(int,delta); } } void select_instrument_param(void *idx, void *unused1, void *unused2) { mused.selected_param = CASTPTR(int,idx); } void select_program_step(void *idx, void *digit, void *unused2) { mused.current_program_step = CASTPTR(int,idx); mused.editpos = CASTPTR(int, digit); } void new_song_action(void *unused1, void *unused2, void *unused3) { if (confirm(domain, mused.slider_bevel, &mused.largefont, "Clear song and data?")) { stop(0,0,0); new_song(); } } void kill_instrument(void *unused1, void *unused2, void *unused3) { cyd_lock(&mused.cyd, 1); mus_get_default_instrument(&mused.song.instrument[mused.current_instrument]); cyd_lock(&mused.cyd, 0); } void generic_action(void *func, void *unused1, void *unused2) { mus_set_song(&mused.mus, NULL, 0); cyd_lock(&mused.cyd, 1); ((void *(*)(void))func)(); /* I love the smell of C in the morning */ cyd_lock(&mused.cyd, 0); } void quit_action(void *unused1, void *unused2, void *unused3) { mused.done = 1; } void change_mode_action(void *mode, void *unused1, void *unused2) { change_mode(CASTPTR(int,mode)); } void enable_channel(void *channel, void *unused1, void *unused2) { debug("Toggle chn %d", CASTPTR(int,channel)); mused.mus.channel[CASTPTR(int,channel)].flags ^= MUS_CHN_DISABLED; set_info_message("%s channel %d", (mused.mus.channel[CASTPTR(int,channel)].flags & MUS_CHN_DISABLED) ? "Muted" : "Unmuted", CASTPTR(int,channel)); } void solo_channel(void *_channel, void *unused1, void *unused2) { int c = 0; int channel = CASTPTR(int,channel); if (channel == -1) channel = mused.current_sequencetrack; for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) if (!(mused.mus.channel[i].flags & MUS_CHN_DISABLED)) ++c; if (c == 1 && !(mused.mus.channel[channel].flags & MUS_CHN_DISABLED)) { debug("Unmuted all"); for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) mused.mus.channel[i].flags &= ~MUS_CHN_DISABLED; set_info_message("Unmuted all channels"); } else { debug("Solo chn %d", CASTPTR(int,channel)); for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) mused.mus.channel[i].flags |= MUS_CHN_DISABLED; mused.mus.channel[channel].flags &= ~MUS_CHN_DISABLED; set_info_message("Channel %d solo", channel); } } void unmute_all_action(void *unused1, void *unused2, void *unused3) { for(int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) mused.mus.channel[i].flags &= ~MUS_CHN_DISABLED; } void select_all(void *unused1, void *unused2, void *unused3) { switch (mused.focus) { case EDITPATTERN: mused.selection.start = 0; mused.selection.end = mused.song.pattern[current_pattern(NULL)].num_steps; break; case EDITPROG: mused.selection.start = 0; mused.selection.end = MUS_PROG_LEN; break; case EDITSEQUENCE: mused.selection.start = 0; mused.selection.end = mused.song.song_length; break; } } void clear_selection(void *unused1, void *unused2, void *unused3) { mused.selection.start = 0; mused.selection.end = 0; } void cycle_focus(void *_views, void *_focus, void *_mode) { View **viewlist = _views; int *focus = _focus, *mode = _mode; View *views = viewlist[*mode]; int i; for (i = 0 ; views[i].handler ; ++i) { if (views[i].focus == *focus) break; } if (!views[i].handler) return; int next; for (next = i + 1 ; i != next ; ++next) { if (views[next].handler == NULL) { next = -1; continue; } if (views[next].focus != -1 && views[next].focus != *focus) { *focus = views[next].focus; break; } } } void change_song_length(void *delta, void *unused1, void *unused2) { int l = mused.song.song_length; l += CASTPTR(int, delta); l = l - (l % mused.sequenceview_steps); mused.song.song_length = my_max(0, my_min(0xfffe, l)); } void change_loop_point(void *delta, void *unused1, void *unused2) { if (CASTPTR(int,delta) < 0) { if (mused.song.loop_point >= -CASTPTR(int,delta)) mused.song.loop_point += CASTPTR(int,delta); else mused.song.loop_point = 0; } else if (CASTPTR(int,delta) > 0) { mused.song.loop_point += CASTPTR(int,delta); if (mused.song.loop_point >= mused.song.song_length) mused.song.loop_point = mused.song.song_length; } } void change_seq_steps(void *delta, void *unused1, void *unused2) { if (CASTPTR(int,delta) < 0) { if (mused.sequenceview_steps > -CASTPTR(int,delta)) { mused.sequenceview_steps += CASTPTR(int,delta); } else mused.sequenceview_steps = 1; } else if (CASTPTR(int,delta) > 0) { if (mused.sequenceview_steps == 1 && CASTPTR(int,delta) > 1) mused.sequenceview_steps = 0; if (mused.sequenceview_steps < 128) { mused.sequenceview_steps += CASTPTR(int,delta); } else mused.sequenceview_steps = 128; } mused.current_sequencepos = (mused.current_sequencepos/mused.sequenceview_steps) * mused.sequenceview_steps; if (mused.flags & LOCK_SEQUENCE_STEP_AND_PATTERN_LENGTH) change_default_pattern_length(MAKEPTR(mused.sequenceview_steps), NULL, NULL); } void show_about_box(void *unused1, void *unused2, void *unused3) { msgbox(domain, mused.slider_bevel, &mused.largefont, VERSION_STRING "\n" KLYSTRON_VERSION_STRING, MB_OK); } void change_channels(void *delta, void *unused1, void *unused2) { if (CASTPTR(int,delta) < 0 && mused.song.num_channels > 1) { set_channels(mused.song.num_channels - 1); } else if (CASTPTR(int,delta) > 0 && mused.song.num_channels < MUS_MAX_CHANNELS) { set_channels(mused.song.num_channels + 1); } } void change_master_volume(void *delta, void *unused1, void *unused2) { if (CASTPTR(int,delta) < 0 && mused.song.master_volume > 0) { mused.mus.volume = --mused.song.master_volume; } else if (CASTPTR(int,delta) > 0 && mused.song.master_volume < MAX_VOLUME) { mused.mus.volume = ++mused.song.master_volume; } } void begin_selection_action(void *unused1, void *unused2, void *unused3) { switch (mused.focus) { case EDITPATTERN: begin_selection(current_patternstep()); break; case EDITSEQUENCE: begin_selection(mused.current_sequencepos); break; case EDITPROG: begin_selection(mused.current_program_step); break; } } void end_selection_action(void *unused1, void *unused2, void *unused3) { switch (mused.focus) { case EDITPATTERN: select_range(current_patternstep()); break; case EDITSEQUENCE: select_range(mused.current_sequencepos); break; case EDITPROG: select_range(mused.current_program_step); break; } } void toggle_pixel_scale(void *a, void*b, void*c) { change_pixel_scale(MAKEPTR(((domain->scale) & 3) + 1), 0, 0); } void change_pixel_scale(void *scale, void*b, void*c) { mused.pixel_scale = CASTPTR(int,scale); domain->screen_w = my_max(320, mused.window_w / mused.pixel_scale); domain->screen_h = my_max(240, mused.window_h / mused.pixel_scale); domain->scale = mused.pixel_scale; gfx_domain_update(domain, true); set_scaled_cursor(); for (int i = 0 ; i < 4; ++i) { if (pixelmenu[i].p1 == scale) pixelmenu[i].flags |= MENU_BULLET; else pixelmenu[i].flags &= ~MENU_BULLET; } } void toggle_fullscreen(void *a, void*b, void*c) { SDL_Event e; e.button.button = SDL_BUTTON_LEFT; mouse_released(&e); mused.flags ^= FULLSCREEN; change_fullscreen(0,0,0); } void change_fullscreen(void *a, void*b, void*c) { domain->fullscreen = (mused.flags & FULLSCREEN) != 0; if (!(mused.flags & FULLSCREEN)) { domain->screen_w = mused.window_w / domain->scale; domain->screen_h = mused.window_h / domain->scale; } gfx_domain_update(domain, true); } void toggle_render_to_texture(void *a, void*b, void*c) { SDL_Event e; e.button.button = SDL_BUTTON_LEFT; mouse_released(&e); mused.flags ^= DISABLE_RENDER_TO_TEXTURE; change_render_to_texture(0,0,0); } void toggle_mouse_cursor(void *a, void*b, void*c) { SDL_Event e; e.button.button = SDL_BUTTON_LEFT; mouse_released(&e); mused.flags ^= USE_SYSTEM_CURSOR; set_scaled_cursor(); } void change_render_to_texture(void *a, void*b, void*c) { domain->flags = (domain->flags & ~GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE) | ((mused.flags & DISABLE_RENDER_TO_TEXTURE) ? GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE : 0); gfx_domain_update(domain, true); } void load_theme_action(void *name, void*b, void*c) { load_theme((char*)name); } void load_keymap_action(void *name, void*b, void*c) { load_keymap((char*)name); } void change_timesig(void *delta, void *b, void *c) { // http://en.wikipedia.org/wiki/Time_signature says the following signatures are common. // I'm a 4/4 or 3/4 man myself so I'll trust the article :) static const Uint16 sigs[] = { 0x0404, 0x0304, 0x0604, 0x0308, 0x0608, 0x0908, 0x0c08 }; int i; for (i = 0 ; i < sizeof(sigs) / sizeof(sigs[0]) ; ++i) { if (sigs[i] == mused.time_signature) break; } i += CASTPTR(int,delta); if (i >= (int)(sizeof(sigs) / sizeof(sigs[0]))) i = 0; if (i < 0) i = sizeof(sigs) / sizeof(sigs[0]) - 1; mused.time_signature = sigs[i]; } void export_wav_action(void *a, void*b, void*c) { char def[1000]; if (strlen(mused.previous_song_filename) == 0) { snprintf(def, sizeof(def), "%s.wav", mused.song.title); } else { strncpy(def, mused.previous_export_filename, sizeof(mused.previous_export_filename) - 1); } char filename[5000]; if (open_dialog_fn("wb", "Export .WAV", "wav", domain, mused.slider_bevel, &mused.largefont, &mused.smallfont, def, filename, sizeof(filename))) { strncpy(mused.previous_export_filename, filename, sizeof(mused.previous_export_filename) - 1); FILE *f = fopen(filename, "wb"); if (f) { export_wav(&mused.song, mused.mus.cyd->wavetable_entries, f, -1); fclose(f); } } } void export_channels_action(void *a, void*b, void*c) { char def[1000]; if (strlen(mused.previous_song_filename) == 0) { snprintf(def, sizeof(def), "%s.wav", mused.song.title); } else { strncpy(def, mused.previous_export_filename, sizeof(mused.previous_export_filename) - 1); } char filename[5000]; if (open_dialog_fn("wb", "Export .WAV", "wav", domain, mused.slider_bevel, &mused.largefont, &mused.smallfont, def, filename, sizeof(filename))) { strncpy(mused.previous_export_filename, filename, sizeof(mused.previous_export_filename) - 1); for (int i = 0 ; i < mused.song.num_channels ; ++i) { char c_filename[1000], tmp[1000]; strncpy(tmp, filename, sizeof(c_filename) - 1); for (int c = strlen(tmp) - 1 ; c >= 0 ; --c) { if (tmp[c] == '.') { tmp[c] = '\0'; break; } } sprintf(c_filename, "%s-%02d.wav", tmp, i); debug("Exporting channel %d to %s", i, c_filename); FILE *f = fopen(c_filename, "wb"); if (f) { export_wav(&mused.song, mused.mus.cyd->wavetable_entries, f, i); fclose(f); } } } } void do_undo(void *a, void*b, void*c) { UndoFrame *frame = a ? undo(&mused.redo) : undo(&mused.undo); debug("%s frame %p", a ? "Redo" : "Undo", frame); if (!frame) return; if (!a) { UndoStack tmp = mused.redo; mused.redo = mused.undo; mused.undo = tmp; } switch (frame->type) { case UNDO_PATTERN: undo_store_pattern(&mused.undo, frame->event.pattern.idx, &mused.song.pattern[frame->event.pattern.idx], mused.modified); resize_pattern(&mused.song.pattern[frame->event.pattern.idx], frame->event.pattern.n_steps); memcpy(mused.song.pattern[frame->event.pattern.idx].step, frame->event.pattern.step, frame->event.pattern.n_steps * sizeof(frame->event.pattern.step[0])); break; case UNDO_SEQUENCE: mused.current_sequencetrack = frame->event.sequence.channel; undo_store_sequence(&mused.undo, mused.current_sequencetrack, mused.song.sequence[mused.current_sequencetrack], mused.song.num_sequences[mused.current_sequencetrack], mused.modified); mused.song.num_sequences[mused.current_sequencetrack] = frame->event.sequence.n_seq; memcpy(mused.song.sequence[mused.current_sequencetrack], frame->event.sequence.seq, frame->event.sequence.n_seq * sizeof(frame->event.sequence.seq[0])); break; case UNDO_MODE: change_mode(frame->event.mode.old_mode); mused.focus = frame->event.mode.focus; break; case UNDO_INSTRUMENT: mused.current_instrument = frame->event.instrument.idx; undo_store_instrument(&mused.undo, mused.current_instrument, &mused.song.instrument[mused.current_instrument], mused.modified); memcpy(&mused.song.instrument[mused.current_instrument], &frame->event.instrument.instrument, sizeof(frame->event.instrument.instrument)); break; case UNDO_FX: mused.fx_bus = frame->event.fx.idx; undo_store_fx(&mused.undo, mused.fx_bus, &mused.song.fx[mused.fx_bus], mused.song.multiplex_period, mused.modified); memcpy(&mused.song.fx[mused.fx_bus], &frame->event.fx.fx, sizeof(frame->event.fx.fx)); mused.song.multiplex_period = frame->event.fx.multiplex_period; mus_set_fx(&mused.mus, &mused.song); break; case UNDO_SONGINFO: { undo_store_songinfo(&mused.undo, &mused.song, mused.modified); MusSong *song = &mused.song; song->song_length = frame->event.songinfo.song_length; mused.sequenceview_steps = song->sequence_step = frame->event.songinfo.sequence_step; song->loop_point = frame->event.songinfo.loop_point; song->song_speed = frame->event.songinfo.song_speed; song->song_speed2 = frame->event.songinfo.song_speed2; song->song_rate = frame->event.songinfo.song_rate; song->time_signature = frame->event.songinfo.time_signature; song->flags = frame->event.songinfo.flags; song->num_channels = frame->event.songinfo.num_channels; strcpy(song->title, frame->event.songinfo.title); song->master_volume = frame->event.songinfo.master_volume; memcpy(song->default_volume, frame->event.songinfo.default_volume, sizeof(frame->event.songinfo.default_volume)); memcpy(song->default_panning, frame->event.songinfo.default_panning, sizeof(frame->event.songinfo.default_panning)); } break; case UNDO_WAVE_PARAM: { mused.selected_wavetable = frame->event.wave_param.idx; undo_store_wave_param(&mused.undo, mused.selected_wavetable, &mused.mus.cyd->wavetable_entries[mused.selected_wavetable], mused.modified); CydWavetableEntry *entry = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; entry->flags = frame->event.wave_param.flags; entry->sample_rate = frame->event.wave_param.sample_rate; entry->samples = frame->event.wave_param.samples; entry->loop_begin = frame->event.wave_param.loop_begin; entry->loop_end = frame->event.wave_param.loop_end; entry->base_note = frame->event.wave_param.base_note; } break; case UNDO_WAVE_DATA: { mused.selected_wavetable = frame->event.wave_param.idx; undo_store_wave_data(&mused.undo, mused.selected_wavetable, &mused.mus.cyd->wavetable_entries[mused.selected_wavetable], mused.modified); CydWavetableEntry *entry = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; entry->data = realloc(entry->data, frame->event.wave_data.length * sizeof(entry->data[0])); memcpy(entry->data, frame->event.wave_data.data, frame->event.wave_data.length * sizeof(entry->data[0])); entry->samples = frame->event.wave_data.length; entry->sample_rate = frame->event.wave_data.sample_rate; entry->samples = frame->event.wave_data.samples; entry->loop_begin = frame->event.wave_data.loop_begin; entry->loop_end = frame->event.wave_data.loop_end; entry->flags = frame->event.wave_data.flags; entry->base_note = frame->event.wave_data.base_note; invalidate_wavetable_view(); } break; case UNDO_WAVE_NAME: { mused.selected_wavetable = frame->event.wave_name.idx; undo_store_wave_name(&mused.undo, mused.selected_wavetable, mused.song.wavetable_names[mused.selected_wavetable], mused.modified); strcpy(mused.song.wavetable_names[mused.selected_wavetable], frame->event.wave_name.name); invalidate_wavetable_view(); } break; default: warning("Undo type %d not handled", frame->type); break; } mused.modified = frame->modified; if (!a) { UndoStack tmp = mused.redo; mused.redo = mused.undo; mused.undo = tmp; } mused.last_snapshot_a = -1; /*#ifdef DEBUG undo_show_stack(&mused.undo); undo_show_stack(&mused.redo); #endif*/ undo_destroy_frame(frame); } void kill_wavetable_entry(void *a, void*b, void*c) { snapshot(S_T_WAVE_DATA); cyd_wave_entry_init(&mused.mus.cyd->wavetable_entries[mused.selected_wavetable], NULL, 0, 0, 0, 0, 0); } void open_menu_action(void*a,void*b,void*c) { my_open_menu(mainmenu, NULL); } void flip_bit_action(void *a, void *b, void *c) { *(Uint32*)a ^= CASTPTR(Uint32,b); } void set_note_jump(void *steps, void *unused1, void *unused2) { mused.note_jump = CASTPTR(int, steps); set_info_message("Note jump set to %d", mused.note_jump); } void change_default_pattern_length(void *length, void *unused1, void *unused2) { for (int i = 0 ; i < NUM_PATTERNS ; ++i) { if (mused.song.pattern[i].num_steps == mused.default_pattern_length && is_pattern_empty(&mused.song.pattern[i])) { resize_pattern(&mused.song.pattern[i], CASTPTR(int,length)); } } mused.sequenceview_steps = mused.default_pattern_length = CASTPTR(int,length); for (Menu *m = patternlengthmenu ; m->text ; ++m) { if (CASTPTR(int, m->p1) == mused.default_pattern_length) m->flags |= MENU_BULLET; else m->flags &= ~MENU_BULLET; } } void toggle_visualizer(void *unused1, void *unused2, void *unused3) { ++mused.current_visualizer; if (mused.current_visualizer >= VIS_NUM_TOTAL) mused.current_visualizer = 0; } void change_visualizer_action(void *vis, void *unused1, void *unused2) { change_visualizer(CASTPTR(int,vis)); } void open_help(void *unused0, void *unused1, void *unused2) { cyd_lock(&mused.cyd, 0); helpbox("Help", domain, mused.slider_bevel, &mused.largefont, &mused.smallfont); cyd_lock(&mused.cyd, 1); } void toggle_follow_play_position(void *unused1, void *unused2, void *unused3) { mused.flags ^= FOLLOW_PLAY_POSITION; if (mused.flags & FOLLOW_PLAY_POSITION) set_info_message("Following song position"); else set_info_message("Not following song position"); } klystrack-0.20171212/klystrack/src/help.c0000644000000000000000000002332613214501362016513 0ustar rootroot#include "help.h" #include "gui/msgbox.h" #include "gui/bevel.h" #include "gui/bevdefs.h" #include "gui/dialog.h" #include "gfx/gfx.h" #include "gui/view.h" #include "gui/mouse.h" #include "gui/toolutil.h" #include "gui/slider.h" #include "command.h" #include "shortcutdefs.h" #include #define SCROLLBAR 10 #define TOP_LEFT 0 #define TOP_RIGHT 0 #define MARGIN 8 #define SCREENMARGIN 32 #define TITLE 14 #define FIELD 14 #define CLOSE_BUTTON 12 #define ELEMWIDTH data.elemwidth #define LIST_WIDTH data.list_width #define BUTTONS 16 static struct { int mode; int selected_line; const char *title; SliderParam scrollbar; char **lines; int n_lines; int list_position; int quit; const Font *largefont, *smallfont; GfxSurface *gfx; int elemwidth, list_width; } data; extern const KeyShortcut shortcuts[]; static void help_list_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param); static const View filebox_view[] = { {{ SCREENMARGIN, SCREENMARGIN, -SCREENMARGIN, -SCREENMARGIN }, window_view, &data, -1}, {{ MARGIN+SCREENMARGIN, SCREENMARGIN+MARGIN, -MARGIN-SCREENMARGIN, TITLE - 2 }, title_view, &data, -1}, {{ -SCROLLBAR-MARGIN-SCREENMARGIN, SCREENMARGIN+MARGIN + TITLE, SCROLLBAR, -MARGIN-SCREENMARGIN-BUTTONS }, slider, &data.scrollbar, -1}, {{ SCREENMARGIN+MARGIN, SCREENMARGIN+MARGIN + TITLE, -SCROLLBAR-MARGIN-1-SCREENMARGIN, -MARGIN-SCREENMARGIN-BUTTONS }, help_list_view, &data, -1}, {{ SCREENMARGIN+MARGIN, -SCREENMARGIN-MARGIN-BUTTONS+2, -MARGIN-SCREENMARGIN, BUTTONS-2 }, buttons_view, &data, -1}, {{0, 0, 0, 0}, NULL} }; static void deinit_lines() { for (int i = 0 ; i < data.n_lines ; ++i) if (data.lines[i]) free(data.lines[i]); free(data.lines); data.lines = NULL; data.n_lines = 0; } static void init_lines(void * section, void * unused1, void * unused2) { deinit_lines(); data.mode = CASTPTR(int, section); switch (data.mode) { case 0: { data.n_lines = 0; const InstructionDesc *commands = list_all_commands(); for (const InstructionDesc *d = commands ; d->name ; ++d) ++data.n_lines; data.lines = realloc(data.lines, sizeof(*data.lines) * data.n_lines); for (int i = 0 ; i < data.n_lines ; ++i) { int params = 0; char paramstr[] = "xxxx"; while ((~0 << (params * 4 + 4) & commands[i].mask) == commands[i].mask) ++params; paramstr[params] = '\0'; char buffer[500]; snprintf(buffer, sizeof(buffer), "%0*X%s %s", 4-params, commands[i].opcode >> (params * 4), paramstr, commands[i].name); if (strlen(buffer) > LIST_WIDTH / data.smallfont->w - 4) { strcpy(&buffer[LIST_WIDTH / data.smallfont->w - 4], "..."); } data.lines[i] = strdup(buffer); } } break; case 1: { data.n_lines = 0; for (const KeyShortcut *s = shortcuts ; s->action ; ++s) if (s->description) ++data.n_lines; data.lines = realloc(data.lines, sizeof(*data.lines) * data.n_lines); for (int i = 0 ; i < data.n_lines ; ++i) { if (shortcuts[i].description) { char buffer[500]; snprintf(buffer, sizeof(buffer), "%-10s %s", get_shortcut_string(&shortcuts[i]), shortcuts[i].description); if (strlen(buffer) > LIST_WIDTH / data.smallfont->w - 4) { strcpy(&buffer[LIST_WIDTH / data.smallfont->w - 4], "..."); } data.lines[i] = strdup(buffer); } } } break; } } static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect button; copy_rect(&button, area); button.w = strlen("Commands") * data.smallfont->w + 12; button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, data.mode == 0 ? BEV_BUTTON_ACTIVE : BEV_BUTTON, BEV_BUTTON_ACTIVE, "Commands", init_lines, 0, 0, 0); button.x += button.w + 1; button.w = strlen("Shortcuts") * data.smallfont->w + 12; button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, data.mode == 1 ? BEV_BUTTON_ACTIVE : BEV_BUTTON, BEV_BUTTON_ACTIVE, "Shortcuts", init_lines, MAKEPTR(1), 0, 0); button.x += button.w + 1; } void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { bevel(dest_surface, area, data.gfx, BEV_MENU); } void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { const char* title = data.title; SDL_Rect titlearea, button; copy_rect(&titlearea, area); titlearea.w -= CLOSE_BUTTON - 4; copy_rect(&button, area); adjust_rect(&button, titlearea.h - CLOSE_BUTTON); button.w = CLOSE_BUTTON; button.x = area->w + area->x - CLOSE_BUTTON; font_write(data.largefont, dest_surface, &titlearea, title); if (button_event(dest_surface, event, &button, data.gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_CLOSE, NULL, MAKEPTR(1), 0, 0) & 1) data.quit = 1; } void help_list_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param) { SDL_Rect content, pos; copy_rect(&content, area); adjust_rect(&content, 1); copy_rect(&pos, &content); pos.h = data.largefont->h; bevel(dest_surface,area, data.gfx, BEV_FIELD); gfx_domain_set_clip(dest_surface, &content); for (int i = data.list_position ; i < data.n_lines && pos.y < content.h + content.y ; ++i) { if (data.selected_line == i) { bevel(dest_surface,&pos, data.gfx, BEV_SELECTED_ROW); } font_write(data.smallfont, dest_surface, &pos, data.lines[i]); if (pos.y + pos.h <= content.h + content.y) slider_set_params(&data.scrollbar, 0, data.n_lines - 1, data.list_position, i, &data.list_position, 1, SLIDER_VERTICAL, data.gfx); //check_event(event, &pos, pick_file_action, MAKEPTR(i), 0, 0); update_rect(&content, &pos); } gfx_domain_set_clip(dest_surface, NULL); check_mouse_wheel_event(event, area, &data.scrollbar); } int helpbox(const char *title, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont) { set_repeat_timer(NULL); memset(&data, 0, sizeof(data)); data.title = title; data.largefont = largefont; data.smallfont = smallfont; data.gfx = gfx; data.elemwidth = domain->screen_w - SCREENMARGIN * 2 - MARGIN * 2 - 16 - 2; data.list_width = domain->screen_w - SCREENMARGIN * 2 - MARGIN * 2 - SCROLLBAR - 2; init_lines(0, 0, 0); slider_set_params(&data.scrollbar, 0, data.n_lines - 1, data.list_position, 0, &data.list_position, 1, SLIDER_VERTICAL, data.gfx); /*for (int i = 0 ; i < data.n_files ; ++i) { if (strcmp(data.files[i].name, last_picked_file) == 0) { data.selected_file = i; // We need to draw the view once so the slider gets visibility info SDL_Event e = {0}; draw_view(gfx_domain_get_surface(domain), filebox_view, &e); slider_move_position(&data.selected_file, &data.list_position, &data.scrollbar, 0); break; } }*/ while (!data.quit) { SDL_Event e = { 0 }; int got_event = 0; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_QUIT: set_repeat_timer(NULL); SDL_PushEvent(&e); deinit_lines(); return 0; break; case SDL_KEYDOWN: { switch (e.key.keysym.sym) { case SDLK_F1: case SDLK_ESCAPE: set_repeat_timer(NULL); deinit_lines(); return 0; break; /*case SDLK_KP_ENTER: case SDLK_RETURN: if (data.selected_file != -1) data.picked_file = &data.files[data.selected_file]; else goto enter_pressed; break;*/ case SDLK_DOWN: slider_move_position(&data.selected_line, &data.list_position, &data.scrollbar, 1); break; case SDLK_UP: slider_move_position(&data.selected_line, &data.list_position, &data.scrollbar, -1); break; case SDLK_PAGEUP: case SDLK_PAGEDOWN: { int items = data.scrollbar.visible_last - data.scrollbar.visible_first; if (e.key.keysym.sym == SDLK_PAGEUP) items = -items; slider_move_position(&data.selected_line, &data.list_position, &data.scrollbar, items); } break; default: break; } } break; case SDL_USEREVENT: e.type = SDL_MOUSEBUTTONDOWN; break; case SDL_MOUSEMOTION: if (domain) { e.motion.xrel /= domain->scale; e.motion.yrel /= domain->scale; e.button.x /= domain->scale; e.button.y /= domain->scale; } break; case SDL_MOUSEBUTTONDOWN: if (domain) { e.button.x /= domain->scale; e.button.y /= domain->scale; } break; case SDL_MOUSEBUTTONUP: { if (e.button.button == SDL_BUTTON_LEFT) mouse_released(&e); } break; } if (e.type != SDL_MOUSEMOTION || (e.motion.state)) ++got_event; // ensure the last event is a mouse click so it gets passed to the draw/event code if (e.type == SDL_MOUSEBUTTONDOWN || (e.type == SDL_MOUSEMOTION && e.motion.state)) break; } if (got_event || gfx_domain_is_next_frame(domain)) { draw_view(domain, filebox_view, &e); gfx_domain_flip(domain); } else SDL_Delay(5); } deinit_lines(); return 0; } klystrack-0.20171212/klystrack/src/shortcutdefs.h0000644000000000000000000000232313214501362020277 0ustar rootroot#ifndef SHORTCUTDEFS_H #define SHORTCUTDEFS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "gui/shortcuts.h" extern const KeyShortcut shortcuts[]; #endif klystrack-0.20171212/klystrack/src/diskop.h0000644000000000000000000000331613214501362017056 0ustar rootroot#ifndef DISKOP_H #define DISKOP_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include #include "SDL_rwops.h" #include "songstats.h" enum { OD_T_SONG, OD_T_INSTRUMENT, OD_T_WAVETABLE, OD_T_WAVETABLE_RAW_S, OD_T_WAVETABLE_RAW_U, OD_T_FX, /*------*/ OD_T_N_TYPES }; enum { OD_A_OPEN, OD_A_SAVE }; int open_song(FILE *f); int save_song(SDL_RWops *f); int save_song_inner(SDL_RWops *f, SongStats *stats); int open_wavetable(FILE *f); int open_instrument(FILE *f); int save_instrument(SDL_RWops *f); int open_fx(FILE *f); int save_fx(SDL_RWops *f); /* action */ void open_data(void *type, void *action, void*c); #endif klystrack-0.20171212/klystrack/src/wave_action.c0000644000000000000000000002465713214501362020072 0ustar rootroot#include "wave_action.h" #include "mused.h" #include "view/wavetableview.h" #include "snd/freqs.h" #include #include "wavegen.h" #include "util/rnd.h" void wavetable_drop_lowest_bit(void *unused1, void *unused2, void *unused3) { if (!mused.wavetable_bits) { debug("Wave is silent"); return; } snapshot(S_T_WAVE_DATA); const CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; Uint16 mask = 0xffff << (__builtin_ffs(mused.wavetable_bits)); if (w->samples > 0) { int d = 0; for (; d < w->samples ; ++d) { w->data[d] &= mask; } invalidate_wavetable_view(); } } void wavetable_halve_samplerate(void *unused1, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { int s = 0, d = 0; for (; s < (w->samples & (~1)) ; s += 2, ++d) { w->data[d] = (w->data[s] + w->data[s + 1]) / 2; } w->samples /= 2; w->sample_rate /= 2; w->loop_begin /= 2; w->loop_end /= 2; invalidate_wavetable_view(); } } void wavetable_normalize(void *vol, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { int m = 0; for (int s = 0 ; s < w->samples ; ++s) { m = my_max(m, abs(w->data[s])); } debug("Peak = %d", m); if (m != 0) { for (int s = 0 ; s < w->samples ; ++s) { w->data[s] = my_max(my_min((Sint32)w->data[s] * CASTPTR(int, vol) / m, 32767), -32768); } } invalidate_wavetable_view(); } } void wavetable_remove_dc(void *unused1, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { double avg = 0; for (int s = 0 ; s < w->samples ; ++s) { avg += w->data[s]; } avg /= w->samples; for (int s = 0 ; s < w->samples ; ++s) { double new_val = w->data[s] - avg; if (new_val < -32768) new_val = -32768; else if (new_val > 32767) new_val = 32767; w->data[s] = new_val; } invalidate_wavetable_view(); } } void wavetable_cut_tail(void *unused1, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { for (int s = w->samples - 1 ; s > 0 ; --s) { if (w->data[s] != 0) { debug("Cut %d samples", w->samples - (s + 1)); w->samples = s + 1; w->loop_end = my_min(w->samples, w->loop_end); w->loop_begin = my_min(w->samples, w->loop_begin); invalidate_wavetable_view(); break; } } } } void wavetable_cut_head(void *unused1, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { for (int s = 0 ; s < 0 ; --s) { if (w->data[s] != 0 && s != 0) { debug("Cut %d samples", s); w->samples -= s; memmove(&w->data[0], &w->data[s], w->samples); w->loop_end = my_min(w->samples, w->loop_end - s); w->loop_begin = my_max(0, (int)w->loop_begin - s); invalidate_wavetable_view(); break; } } } } void wavetable_chord(void *transpose, void *unused2, void *unused3) { CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { int denom = 1, nom = 1; // too lazy to add a LCM function so here's a table switch (CASTPTR(int, transpose)) { case 4: // perfect 4th denom = 4; nom = 3; break; case 5: // perfect 5th denom = 3; nom = 2; break; default: case 12: // perfect octave denom = 2; nom = 1; break; } int new_length = nom * w->samples; if (new_length < 100000000) { Sint16 *new_data = malloc(sizeof(Sint16) * new_length); if (new_data) { snapshot(S_T_WAVE_DATA); for (int s = 0 ; s < new_length ; ++s) { new_data[s] = ((int)w->data[s % w->samples] + (int)w->data[(s * denom / nom) % w->samples]) / 2; } free(w->data); w->data = new_data; w->samples = new_length; w->loop_begin *= nom; w->loop_end *= nom; invalidate_wavetable_view(); } else { set_info_message("Out of memory!"); } } else { set_info_message("Resulting wave was too big"); } } } void wavetable_create_one_cycle(void *_settings, void *unused2, void *unused3) { WgSettings *settings = _settings; CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { snapshot(S_T_WAVE_DATA); } int new_length = settings->length; Sint16 *new_data = malloc(sizeof(Sint16) * new_length); int lowest_mul = 999; for (int i = 0 ; i < settings->num_oscs ; ++i) { lowest_mul = my_min(lowest_mul, settings->chain[i].mult); } wg_gen_waveform(settings->chain, settings->num_oscs, new_data, new_length); if (w->data) free(w->data); w->data = new_data; w->sample_rate = new_length * 220 / lowest_mul; w->samples = new_length; w->loop_begin = 0; w->loop_end = new_length; w->flags = CYD_WAVE_LOOP; w->base_note = (MIDDLE_C + 9 - 12) << 8; invalidate_wavetable_view(); } void wavetable_draw(float x, float y, float width) { snapshot_cascade(S_T_WAVE_DATA, mused.selected_wavetable, 0); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { debug("draw %f,%f w = %f", x, y, width); int s = w->samples * x; int e = my_max(w->samples * (x + width), s + 1); for ( ; s < e && s < w->samples ; ++s) { w->data[s] = y * 65535 - 32768; } invalidate_wavetable_view(); } } void wavegen_randomize(void *unused1, void *unused2, void *unused3) { bool do_sines = !(rndu() & 3); bool do_shift = !(rndu() & 1); bool do_exp = !(rndu() & 3); bool do_highfreg = !(rndu() & 1); bool do_inharmonic = !(rndu() & 1); bool do_chop = !(rndu() & 3); mused.wgset.num_oscs = rnd(1, WG_CHAIN_OSCS); for (int i = 0 ; i < mused.wgset.num_oscs ; ++i) { mused.wgset.chain[i].flags = rnd(0, 3); if (do_sines) { if (do_chop && i > 0) { if (rndu() & 1) mused.wgset.chain[i].osc = WG_OSC_SINE; else mused.wgset.chain[i].osc = WG_OSC_SQUARE; } else mused.wgset.chain[i].osc = WG_OSC_SINE; } else { mused.wgset.chain[i].osc = rnd(0, WG_NUM_OSCS - 1); if (mused.wgset.chain[i].osc == WG_OSC_NOISE) mused.wgset.chain[i].osc = rnd(0, WG_NUM_OSCS - 1); } if (do_inharmonic) mused.wgset.chain[i].mult = rnd(1, do_highfreg ? 9 : 5); else mused.wgset.chain[i].mult = 1 << rnd(0, do_highfreg ? 3 : 2); mused.wgset.chain[i].op = rnd(0, WG_NUM_OPS - 1); if (do_shift) mused.wgset.chain[i].shift = rnd(0, 7); else mused.wgset.chain[i].shift = 0; if (do_exp) mused.wgset.chain[i].exp = rnd(5,95); else mused.wgset.chain[i].exp = 50; } } void wavegen_preset(void *_preset, void *_settings, void *unused3) { WgSettings *preset = &((WgPreset*)_preset)->settings; WgSettings *settings = _settings; settings->num_oscs = preset->num_oscs; memcpy(settings->chain, preset->chain, sizeof(preset->chain[0]) * preset->num_oscs); } void wavetable_amp(void *_amp, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { int amp = CASTPTR(int, _amp); debug("amp = %d", amp); for (int s = 0 ; s < w->samples ; ++s) { w->data[s] = my_max(my_min((Sint32)w->data[s] * amp / 32768, 32767), -32768); } invalidate_wavetable_view(); } } void wavetable_distort(void *_amp, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { for (int s = 0 ; s < w->samples ; ++s) { if (w->data[s] != 0) { float v = (float)w->data[s] / 32768.0; v *= pow(fabs(v), -0.333); w->data[s] = my_max(my_min(v * 32768, 32767), -32768); } } invalidate_wavetable_view(); } } void wavetable_randomize_and_create_one_cycle(void *_settings, void *unused2, void *unused3) { wavegen_randomize(NULL, NULL, NULL); wavetable_create_one_cycle(_settings, NULL, NULL); } void wavetable_filter(void *_filter_type, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 0) { int filter_type = CASTPTR(int, _filter_type); Sint16 * temp = malloc(sizeof(Sint16) * w->samples); memcpy(temp, w->data, sizeof(Sint16) * w->samples); for (int s = 0 ; s < w->samples ; ++s) { int filtered = ((int)temp[(s - 2 + w->samples) % w->samples] + (int)temp[(s - 1 + w->samples) % w->samples] * 2 + (int)temp[s % w->samples] * 4 + (int)temp[(s + 1) % w->samples] * 2 + (int)temp[(s + 2) % w->samples]) / 10; if (filter_type == 0) w->data[s] = my_max(my_min(filtered, 32767), -32768); else w->data[s] = my_max(my_min(w->data[s] - filtered, 32767), -32768); } free(temp); invalidate_wavetable_view(); } } void wavetable_find_zero(void *unused1, void *unused2, void *unused3) { snapshot(S_T_WAVE_DATA); CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; if (w->samples > 1) { int zero_crossing = 0; for (int s = 1 ; s < w->samples ; ++s) { if ((w->data[s] >= 0 && w->data[s - 1] < 0) || (w->data[s] <= 0 && w->data[s - 1] > 0)) { zero_crossing = s; break; } } debug("zero crossing at %d", zero_crossing); if (zero_crossing > 0) { Sint16 * temp = malloc(sizeof(Sint16) * w->samples); memcpy(temp, w->data, sizeof(Sint16) * w->samples); for (int s = 0 ; s < w->samples ; ++s) { w->data[s] = temp[(s + zero_crossing) % w->samples]; } free(temp); } invalidate_wavetable_view(); } } klystrack-0.20171212/klystrack/src/main.c0000644000000000000000000004270513214501362016511 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include "gfx/gfx.h" #include "snd/music.h" #include "gui/toolutil.h" #include "copypaste.h" #include "diskop.h" #include "event.h" #include "view.h" #include "gui/slider.h" #include "action.h" #include "gui/mouse.h" #include "gui/bevel.h" #include "gui/menu.h" #include "shortcutdefs.h" #include "version.h" #include "mused.h" #include "config.h" #include "mybevdefs.h" #include #include "util/rnd.h" #include "view/visu.h" #include "view/pattern.h" #include "view/sequence.h" #include "view/wavetableview.h" #include "view/timer.h" #include "mymsg.h" #include "key.h" #include "nostalgy.h" #include "theme.h" #ifdef MIDI #include "midi.h" #endif //#define DUMPKEYS Mused mused; /*---*/ int stat_song_position; int stat_pattern_position[MUS_MAX_CHANNELS]; MusPattern *stat_pattern[MUS_MAX_CHANNELS]; int stat_pattern_number[MUS_MAX_CHANNELS]; GfxDomain *domain; extern const Menu mainmenu[]; #define SCROLLBAR 10 #define INST_LIST (6*8 + 3*2) #define INFO 13 #define INST_VIEW2 (38+10+10+10+52) void change_pixel_scale(void *, void*, void*); static const View instrument_view_tab[] = { {{0, 0, -130, 14}, bevel_view, (void*)BEV_BACKGROUND, EDITINSTRUMENT }, {{2, 2, -130-2, 10}, instrument_name_view, (void*)1, EDITINSTRUMENT}, {{-130, 0, 130, 14}, instrument_disk_view, MAKEPTR(OD_T_INSTRUMENT), EDITINSTRUMENT}, {{0, 14, 154, -INFO }, instrument_view, NULL, EDITINSTRUMENT }, {{154, 14 + INST_LIST, 0, INST_VIEW2 }, instrument_view2, NULL, EDITINSTRUMENT }, {{154, 14, - SCROLLBAR, INST_LIST }, instrument_list, NULL, EDITINSTRUMENT}, {{154, 14 + INST_LIST + INST_VIEW2, 0 - SCROLLBAR, -INFO }, program_view, NULL, EDITPROG }, {{0 - SCROLLBAR, 14 + INST_LIST + INST_VIEW2, SCROLLBAR, -INFO }, slider, &mused.program_slider_param, EDITPROG }, {{0 - SCROLLBAR, 14, SCROLLBAR, INST_LIST }, slider, &mused.instrument_list_slider_param, EDITINSTRUMENT }, {{0, 0 - INFO, 0, INFO }, info_line, NULL, -1 }, {{0, 0, 0, 0}, NULL} }; static const View pattern_view_tab[] = { {{0, 0, 0, 14}, bevel_view, (void*)BEV_BACKGROUND, -1}, {{2, 2, -2, 10}, instrument_name_view, (void*)1, EDITINSTRUMENT}, {{0, 14, 0-SCROLLBAR, 0 - INFO}, pattern_view2, NULL, EDITPATTERN}, {{0-SCROLLBAR, 14, SCROLLBAR, 0 - INFO}, slider, &mused.pattern_slider_param, EDITPATTERN}, {{0, 0 - INFO, 0, INFO }, info_line, NULL, -1}, {{0, 0, 0, 0}, NULL} }; #define CLASSIC_PAT (0 / 2 + 20 - 2 - 7) #define CLASSIC_SONG_INFO (94) #define SONG_INFO1_H (24+10) #define SONG_INFO2_H (24+10) #define SONG_INFO3_H (15+10) #define TOOLBAR_H 12 #define CLASSIC_SONG_INFO_H (SONG_INFO1_H+SONG_INFO2_H+SONG_INFO3_H+TOOLBAR_H) #define TIMER_W (5*7+4) #define SEQ_VIEW_INFO_H (24+10) static const View classic_view_tab[] = { {{0,0,CLASSIC_SONG_INFO,TOOLBAR_H}, toolbar_view, NULL, -1}, {{0,TOOLBAR_H,CLASSIC_SONG_INFO,SONG_INFO1_H}, songinfo1_view, NULL, EDITSONGINFO}, {{0,TOOLBAR_H + SONG_INFO1_H,CLASSIC_SONG_INFO,SONG_INFO2_H}, songinfo2_view, NULL, EDITSONGINFO}, {{0,TOOLBAR_H + SONG_INFO1_H+SONG_INFO2_H,CLASSIC_SONG_INFO,SONG_INFO3_H}, songinfo3_view, NULL, EDITSONGINFO}, {{- PLAYSTOP_INFO_W, CLASSIC_SONG_INFO_H - 25,PLAYSTOP_INFO_W,25}, playstop_view, NULL, EDITSONGINFO}, {{0-SCROLLBAR, 0, SCROLLBAR, CLASSIC_SONG_INFO_H - 25}, slider, &mused.sequence_slider_param, EDITSEQUENCE}, {{CLASSIC_SONG_INFO, 0, 0-SCROLLBAR, CLASSIC_SONG_INFO_H - 25}, sequence_spectrum_view, NULL, EDITSEQUENCE}, {{CLASSIC_SONG_INFO, CLASSIC_SONG_INFO_H-25, - PLAYSTOP_INFO_W, 25}, bevel_view, (void*)BEV_BACKGROUND, -1}, {{CLASSIC_SONG_INFO + 2, CLASSIC_SONG_INFO_H - 25 + 2, -2 - PLAYSTOP_INFO_W - TIMER_W - 1, 10}, song_name_view, NULL, -1}, {{-2 - PLAYSTOP_INFO_W - TIMER_W, CLASSIC_SONG_INFO_H - 25 + 2, TIMER_W, 12}, timer_view, NULL, -1}, {{CLASSIC_SONG_INFO + 2, CLASSIC_SONG_INFO_H - 25 + 2 + 10 + 1, -2 - PLAYSTOP_INFO_W, 10}, instrument_name_view, (void*)1, -1}, {{0, CLASSIC_SONG_INFO_H, 0-SCROLLBAR, -INFO}, pattern_view2, NULL, EDITPATTERN}, {{0 - SCROLLBAR, CLASSIC_SONG_INFO_H, SCROLLBAR, -INFO}, slider, &mused.pattern_slider_param, EDITPATTERN}, {{0, 0 - INFO, 0, INFO }, info_line, NULL, -1}, {{0, 0, 0, 0}, NULL} }; static const View sequence_view_tab[] = { {{0,0,CLASSIC_SONG_INFO,SEQ_VIEW_INFO_H}, songinfo1_view, NULL, EDITSONGINFO}, {{CLASSIC_SONG_INFO,0,CLASSIC_SONG_INFO,SEQ_VIEW_INFO_H}, songinfo2_view, NULL, EDITSONGINFO}, {{CLASSIC_SONG_INFO*2,0,CLASSIC_SONG_INFO,SEQ_VIEW_INFO_H}, songinfo3_view, NULL, EDITSONGINFO}, {{CLASSIC_SONG_INFO*3,0,0,SEQ_VIEW_INFO_H}, playstop_view, NULL, EDITSONGINFO}, {{0, SEQ_VIEW_INFO_H, -130, 14}, bevel_view, (void*)BEV_BACKGROUND, -1}, {{2, SEQ_VIEW_INFO_H+2, -130-2-(TIMER_W+1), 10}, song_name_view, NULL, -1}, {{-130-2-TIMER_W, SEQ_VIEW_INFO_H+2, TIMER_W, 10}, timer_view, NULL, -1}, {{-130, SEQ_VIEW_INFO_H, 130, 14}, instrument_disk_view, MAKEPTR(OD_T_SONG), -1}, {{0, SEQ_VIEW_INFO_H+14, 0-SCROLLBAR, -INFO}, sequence_view2, NULL, EDITSEQUENCE}, {{0-SCROLLBAR, SEQ_VIEW_INFO_H+14, SCROLLBAR, -INFO}, slider, &mused.sequence_slider_param, EDITSEQUENCE}, {{0, 0 - INFO, 0, INFO }, info_line, NULL, -1}, {{0, 0, 0, 0}, NULL} }; static const View fx_view_tab[] = { {{0, 0, 0, 14}, fx_global_view, NULL, -1}, {{0, 14, -130, 14}, bevel_view, (void*)BEV_BACKGROUND, -1}, {{2, 16, -132, 10}, fx_name_view, NULL, -1}, {{-130, 14, 130, 14}, instrument_disk_view, MAKEPTR(OD_T_FX), -1}, {{0, 28, 0, -INFO}, fx_view, NULL, -1}, {{0, 0 - INFO, 0, INFO }, info_line, NULL, -1}, {{0, 0, 0, 0}, NULL} }; #define SAMPLEVIEW 128 static const View wavetable_view_tab[] = { {{0, 0, -130, 14}, bevel_view, (void*)BEV_BACKGROUND, -1}, {{2, 2, -132, 10}, wavetable_name_view, NULL, -1}, {{-130, 0, 130, 14}, instrument_disk_view, MAKEPTR(OD_T_WAVETABLE), -1}, {{0, 14, 204, -INFO-SAMPLEVIEW}, wavetable_view, NULL, -1}, {{204, 14, -SCROLLBAR, -INFO-SAMPLEVIEW}, wavetablelist_view, NULL, -1}, {{0 - SCROLLBAR, 14, SCROLLBAR, -INFO-SAMPLEVIEW }, slider, &mused.wavetable_list_slider_param, EDITWAVETABLE }, {{0, -INFO-SAMPLEVIEW, -148, SAMPLEVIEW}, wavetable_sample_area, NULL, -1}, {{-148, -INFO-SAMPLEVIEW, 148, SAMPLEVIEW}, wavetable_edit_area, NULL, -1}, {{0, 0 - INFO, 0, INFO }, info_line, NULL, -1}, {{0, 0, 0, 0}, NULL} }; const View *tab[] = { pattern_view_tab, sequence_view_tab, classic_view_tab, instrument_view_tab, fx_view_tab, wavetable_view_tab, }; static void menu_close_hook(void) { change_mode(mused.prev_mode); } void my_open_menu(const Menu *menu, const Menu *action) { debug("Menu opened"); change_mode(MENU); open_menu(menu, action, menu_close_hook, shortcuts, &mused.headerfont, &mused.headerfont_selected, &mused.menufont, &mused.menufont_selected, &mused.shortcutfont, &mused.shortcutfont_selected, mused.slider_bevel); } // mingw kludge for console output #if defined(DEBUG) && defined(WIN32) #undef main #endif int main(int argc, char **argv) { init_genrand(time(NULL)); init_resources_dir(); debug("Starting %s", VERSION_STRING); SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE|SDL_INIT_TIMER); atexit(SDL_Quit); default_settings(); load_config(TOSTRING(CONFIG_PATH), false); domain = gfx_create_domain(VERSION_STRING, SDL_WINDOW_RESIZABLE|SDL_WINDOW_OPENGL|((mused.flags & WINDOW_MAXIMIZED)?SDL_WINDOW_MAXIMIZED:0), mused.window_w, mused.window_h, mused.pixel_scale); domain->fps = 30; domain->scale = mused.pixel_scale; domain->window_min_w = 320; domain->window_min_h = 240; gfx_domain_update(domain, false); MusInstrument instrument[NUM_INSTRUMENTS]; MusPattern pattern[NUM_PATTERNS]; MusSeqPattern sequence[MUS_MAX_CHANNELS][NUM_SEQUENCES]; MusChannel channel[CYD_MAX_CHANNELS]; init(instrument, pattern, sequence, channel); load_config(TOSTRING(CONFIG_PATH), true); post_config_load(); init_scrollbars(); cyd_init(&mused.cyd, mused.mix_rate, MUS_MAX_CHANNELS); mus_init_engine(&mused.mus, &mused.cyd); new_song(); enable_callback(true); for (int i = 0 ; i < CYD_MAX_FX_CHANNELS ; ++i) cydfx_set(&mused.cyd.fx[i], &mused.song.fx[i]); cyd_register(&mused.cyd, mused.mix_buffer); if (argc > 1) { cyd_lock(&mused.cyd, 1); FILE *f = fopen(argv[1], "rb"); if (f) { open_song(f); fclose(f); } cyd_lock(&mused.cyd, 0); } else if (mused.flags & START_WITH_TEMPLATE) { cyd_lock(&mused.cyd, 1); FILE *f = fopen("Default.kt", "rb"); if (f) { open_song(f); fclose(f); } cyd_lock(&mused.cyd, 0); } #ifdef MIDI midi_init(); #endif #ifdef DEBUG float draw_calls = 0; int total_frames = 0; #endif int active = 1; if (!(mused.flags & DISABLE_NOSTALGY)) { nos_decrunch(domain); mused.flags |= DISABLE_NOSTALGY; } #ifdef DEBUG Uint32 start_ticks = SDL_GetTicks(); #endif while (1) { SDL_Event e = { 0 }; int got_event = 0, menu_closed = 0; while (SDL_PollEvent(&e)) { if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP) { translate_key_event(&e.key); } switch (e.type) { case SDL_QUIT: quit_action(0,0,0); break; case SDL_WINDOWEVENT: set_repeat_timer(NULL); switch (e.window.event) { case SDL_WINDOWEVENT_MINIMIZED: debug("SDL_WINDOWEVENT_MINIMIZED"); break; case SDL_WINDOWEVENT_RESTORED: debug("SDL_WINDOWEVENT_RESTORED"); mused.flags &= ~WINDOW_MAXIMIZED; break; case SDL_WINDOWEVENT_MAXIMIZED: debug("SDL_WINDOWEVENT_MAXIMIZED"); mused.flags |= WINDOW_MAXIMIZED; break; case SDL_WINDOWEVENT_SIZE_CHANGED: debug("SDL_WINDOWEVENT_SIZE_CHANGED %dx%d", e.window.data1, e.window.data2); break; case SDL_WINDOWEVENT_RESIZED: { debug("SDL_WINDOWEVENT_RESIZED %dx%d", e.window.data1, e.window.data2); domain->screen_w = my_max(320, e.window.data1 / domain->scale); domain->screen_h = my_max(240, e.window.data2 / domain->scale); if (!(mused.flags & FULLSCREEN)) { mused.window_w = domain->screen_w * domain->scale; mused.window_h = domain->screen_h * domain->scale; } gfx_domain_update(domain, false); } break; } break; case SDL_USEREVENT: e.type = SDL_MOUSEBUTTONDOWN; break; case SDL_MOUSEMOTION: gfx_convert_mouse_coordinates(domain, &e.motion.x, &e.motion.y); gfx_convert_mouse_coordinates(domain, &e.motion.xrel, &e.motion.yrel); break; case SDL_MOUSEBUTTONDOWN: gfx_convert_mouse_coordinates(domain, &e.button.x, &e.button.y); if (e.button.button == SDL_BUTTON_RIGHT) { my_open_menu(mainmenu, NULL); } else if (e.button.button == SDL_BUTTON_LEFT && mused.mode == MENU) { menu_closed = 1; } break; case SDL_MOUSEBUTTONUP: { gfx_convert_mouse_coordinates(domain, &e.button.x, &e.button.y); if (e.button.button == SDL_BUTTON_LEFT) { mouse_released(&e); if (mused.focus == EDITFX) mus_set_fx(&mused.mus, &mused.song); // for the chorus effect which does a heavy precalc } else if (e.button.button == SDL_BUTTON_RIGHT) menu_closed = 1; } break; case SDL_TEXTEDITING: case SDL_TEXTINPUT: switch (mused.focus) { case EDITBUFFER: edit_text(&e); break; } break; case SDL_KEYUP: case SDL_KEYDOWN: { /*#ifdef DUMPKEYS debug("SDL_KEYDOWN: time = %.1f sym = %x mod = %x unicode = %x scancode = %x", (double)SDL_GetTicks() / 1000.0, e.key.keysym.sym, e.key.keysym.mod, e.key.keysym.unicode, e.key.keysym.scancode); #endif*/ // Translate F12 into SDLK_INSERT (Issue 37) if (e.key.keysym.sym == SDLK_F12) e.key.keysym.sym = SDLK_INSERT; // Special multimedia keys look like a-z keypresses but the unicode value is zero // We don't care about the special keys and don't want fake keypresses either /*if (e.type == SDL_KEYDOWN && e.key.keysym.sym >= SDLK_a && e.key.keysym.sym <= SDLK_z) break;*/ // key events should go only to the edited text field if (mused.focus != EDITBUFFER) { cyd_lock(&mused.cyd, 1); do_shortcuts(&e.key, shortcuts); cyd_lock(&mused.cyd, 0); } if (e.key.keysym.sym != 0) { cyd_lock(&mused.cyd, 1); switch (mused.focus) { case EDITBUFFER: edit_text(&e); break; case EDITPROG: edit_program_event(&e); break; case EDITINSTRUMENT: edit_instrument_event(&e); break; case EDITPATTERN: pattern_event(&e); break; case EDITSEQUENCE: sequence_event(&e); break; case EDITFX: fx_event(&e); break; case EDITWAVETABLE: wave_event(&e); break; case EDITSONGINFO: songinfo_event(&e); break; } cyd_lock(&mused.cyd, 0); } } break; case MSG_NOTEON: case MSG_NOTEOFF: case MSG_PROGRAMCHANGE: note_event(&e); break; } if (mused.focus == EDITBUFFER && e.type == SDL_KEYDOWN) e.type = SDL_USEREVENT; if (e.type != SDL_MOUSEMOTION || (e.motion.state) || (e.type == SDL_MOUSEMOTION && mused.mode == MENU)) ++got_event; // ensure the last event is a mouse click so it gets passed to the draw/event code if (e.type == SDL_MOUSEBUTTONDOWN || (e.type == SDL_MOUSEMOTION && e.motion.state)) break; } int prev_position = mused.stat_song_position; if (active) mus_poll_status(&mused.mus, &mused.stat_song_position, mused.stat_pattern_position, mused.stat_pattern, channel, mused.vis.cyd_env, mused.stat_note, &mused.time_played); if (active && (got_event || gfx_domain_is_next_frame(domain) || prev_position != mused.stat_song_position)) { if ((mused.flags & FOLLOW_PLAY_POSITION) && (mused.flags & SONG_PLAYING)) { mused.current_sequencepos = mused.stat_song_position - mused.stat_song_position % mused.sequenceview_steps; mused.current_patternpos = mused.stat_song_position; update_position_sliders(); } for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { stat_pattern_number[i] = (stat_pattern[i] - &mused.song.pattern[0])/sizeof(mused.song.pattern[0]); } int m = mused.mode >= VIRTUAL_MODE ? mused.prev_mode : mused.mode; int prev_mode; do { prev_mode = mused.mode; if (mused.mode == MENU) { SDL_Event foo = {0}; my_draw_view(tab[m], &foo, domain); draw_menu(domain, &e); if (menu_closed) { const Menu *cm = get_current_menu(); const Menu *cm_action = get_current_menu_action(); close_menu(); if (SDL_GetModState() & KMOD_SHIFT) my_open_menu(cm, cm_action); } } else { my_draw_view(tab[m], &e, domain); } e.type = 0; // agh mused.current_patternpos = mused.pattern_position; } while (mused.mode != prev_mode); // Eliminates the one-frame long black screen #ifdef DEBUG total_frames++; draw_calls += domain->calls_per_frame; #endif gfx_domain_flip(domain); } else SDL_Delay(4); if (mused.done) { int r; if (mused.modified) r = confirm_ync(domain, mused.slider_bevel, &mused.largefont, "Save song?"); else break; if (r == 0) mused.done = 0; if (r == -1) break; if (r == 1) { int r; open_data(MAKEPTR(OD_T_SONG), MAKEPTR(OD_A_SAVE), &r); if (!r) mused.done = 0; else break; } } } #ifdef MIDI midi_deinit(); #endif cyd_unregister(&mused.cyd); debug("cyd_deinit"); cyd_deinit(&mused.cyd); save_config(TOSTRING(CONFIG_PATH)); debug("deinit"); deinit(); gfx_domain_free(domain); #ifdef DEBUG debug("Total frames = %d (%.1f fps)", total_frames, (double)total_frames / ((double)(SDL_GetTicks() - start_ticks) / 1000)); if (total_frames > 0) debug("Draw calls per frame: %.1f", draw_calls / total_frames); #endif debug("klystrack has left the building."); return 0; } klystrack-0.20171212/klystrack/src/stats.h0000644000000000000000000000020713214501362016717 0ustar rootroot#ifndef STATS_H #define STATS_H #include "songstats.h" void song_stats(void *unused1, void *unused2, void *unused3); #endif klystrack-0.20171212/klystrack/src/clipboard.h0000644000000000000000000000367313214501362017532 0ustar rootroot#ifndef CLIPBOARD_H #define CLIPBOARD_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include typedef struct { int type; void *data; size_t size; int position; } Clipboard; #include "mused.h" enum { CP_PATTERN=EDITPATTERN, CP_SEQUENCE=EDITSEQUENCE, CP_INSTRUMENT=EDITINSTRUMENT, CP_PROGRAM=EDITPROG, CP_PATTERNSEGMENT }; #define ALL_ITEMS 0xffffffff void cp_clear(Clipboard *cp); void cp_copy(Clipboard *cp, int type, void *data, const size_t size, int position); void cp_copy_items(Clipboard *cp, int type, void *data, const size_t dest_items, const size_t item_size, int position); void cp_paste(Clipboard *cp, int dest_type, void *dest, const size_t buffer_size); void cp_paste_items(Clipboard *cp, int target_type, void *dest, const size_t dest_items, const size_t item_size); size_t cp_get_item_count(Clipboard *cp, const size_t item_size); #endif klystrack-0.20171212/klystrack/src/wavewriter.c0000644000000000000000000000321713214501362017757 0ustar rootroot#include "wavewriter.h" #include #include "SDL.h" WaveWriter * ww_create(FILE * file, int sample_rate, int channels) { WaveWriter * ww = malloc(sizeof(WaveWriter)); ww->file = file; ww->channels = channels; Uint16 tmp16 = 0; Uint32 tmp32 = 0; fwrite("RIFF", 4, 1, ww->file); ww->riffsize_pos = ftell(ww->file); fwrite(&tmp32, 4, 1, ww->file); fwrite("WAVE", 4, 1, ww->file); fwrite("fmt ", 4, 1, ww->file); tmp32 = SDL_SwapLE32(16); // size of format data fwrite(&tmp32, 4, 1, ww->file); tmp16 = SDL_SwapLE16(1); // data type = PCM fwrite(&tmp16, 2, 1, ww->file); tmp16 = SDL_SwapLE16(channels); fwrite(&tmp16, 2, 1, ww->file); tmp32 = SDL_SwapLE32(sample_rate); fwrite(&tmp32, 4, 1, ww->file); tmp32 = SDL_SwapLE32(sample_rate * channels * sizeof(Sint16)); fwrite(&tmp32, 4, 1, ww->file); tmp16 = SDL_SwapLE16(channels * sizeof(Sint16)); fwrite(&tmp16, 2, 1, ww->file); tmp16 = SDL_SwapLE16(16); // bits per sample fwrite(&tmp16, 2, 1, ww->file); fwrite("data", 4, 1, ww->file); ww->chunksize_pos = ftell(ww->file); tmp32 = 0; fwrite(&tmp32, 4, 1, ww->file); return ww; } void ww_write(WaveWriter *ww, Sint16 * buffer, int samples) { fwrite(buffer, samples * ww->channels * sizeof(Sint16), 1, ww->file); } void ww_finish(WaveWriter *ww) { Uint32 sz = ftell(ww->file) - 8; Uint32 tmp32 = SDL_SwapLE32(sz); fseek(ww->file, ww->riffsize_pos, SEEK_SET); fwrite(&tmp32, sizeof(tmp32), 1, ww->file); tmp32 = SDL_SwapLE32(sz + 8 - (ww->chunksize_pos + 4)); fseek(ww->file, ww->chunksize_pos, SEEK_SET); fwrite(&tmp32, sizeof(tmp32), 1, ww->file); fclose(ww->file); free(ww); } klystrack-0.20171212/klystrack/src/nostalgy.h0000644000000000000000000000011713214501362017421 0ustar rootroot#pragma once #include "gfx/gfx.h" void nos_decrunch(GfxDomain *domain); klystrack-0.20171212/klystrack/src/nostalgy.c0000644000000000000000000000120213214501362017410 0ustar rootroot#include "nostalgy.h" #include void nos_decrunch(GfxDomain *domain) { static const Uint32 palette[] = { 0x000000, 0xFFFFFF, 0x68372B, 0x70A4B2, 0x6F3D86, 0x588D43, 0x352879, 0xB8C76F, 0x6F4F25, 0x433900, 0x9A6759, 0x444444, 0x6C6C6C, 0x9AD284, 0x6C5EB5, 0x959595 }; for (int i = 0 ; i < 60 ; ++i) { for (int y = 0 ; y < domain->screen_h ; ) { int h = rand() & 15; { SDL_Rect line = {0, y, domain->screen_w, h}; gfx_rect(domain, &line, palette[rand() & 15]); } y += h; } gfx_domain_flip(domain); SDL_Delay(15); } } klystrack-0.20171212/klystrack/src/export.c0000644000000000000000000000766713214501362017116 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "export.h" #include "gui/bevel.h" #include "snd/cyd.h" #include "macros.h" #include "mused.h" #include "gfx/gfx.h" #include "gui/view.h" #include "mybevdefs.h" #include "gfx/font.h" #include "theme.h" #include #include "wavewriter.h" extern GfxDomain *domain; void export_wav(MusSong *song, CydWavetableEntry * entry, FILE *f, int channel) { MusEngine mus; CydEngine cyd; cyd_init(&cyd, 44100, MUS_MAX_CHANNELS); cyd.flags |= CYD_SINGLE_THREAD; mus_init_engine(&mus, &cyd); mus.volume = song->master_volume; mus_set_fx(&mus, song); CydWavetableEntry * prev_entry = cyd.wavetable_entries; // save entries so they can be free'd cyd.wavetable_entries = entry; cyd_set_callback(&cyd, mus_advance_tick, &mus, song->song_rate); mus_set_song(&mus, song, 0); song->flags |= MUS_NO_REPEAT; if (channel >= 0) { // if channel is positive then only export that channel (mute other chans) for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) mus.channel[i].flags |= MUS_CHN_DISABLED; mus.channel[channel].flags &= ~MUS_CHN_DISABLED; } else { for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) mus.channel[i].flags &= ~MUS_CHN_DISABLED; } const int channels = 2; Sint16 buffer[2000 * channels]; int last_percentage = -1; WaveWriter *ww = ww_create(f, cyd.sample_rate, 2); for (;;) { memset(buffer, 0, sizeof(buffer)); // Zero the input to cyd cyd_output_buffer_stereo(&cyd, (Uint8*)buffer, sizeof(buffer)); if (cyd.samples_output > 0) ww_write(ww, buffer, cyd.samples_output); if (mus.song_position >= song->song_length) break; if (song->song_length != 0) { int percentage = (mus.song_position + (channel == -1 ? 0 : (channel * song->song_length))) * 100 / (song->song_length * (channel == -1 ? 1 : song->num_channels)); if (percentage > last_percentage) { last_percentage = percentage; SDL_Rect area = {domain->screen_w / 2 - 140, domain->screen_h / 2 - 24, 280, 48}; bevel(domain, &area, mused.slider_bevel, BEV_MENU); adjust_rect(&area, 8); area.h = 16; bevel(domain, &area, mused.slider_bevel, BEV_FIELD); adjust_rect(&area, 2); int t = area.w; area.w = area.w * percentage / 100; gfx_rect(domain, &area, colors[COLOR_PROGRESS_BAR]); area.y += 16 + 4 + 4; area.w = t; font_write_args(&mused.smallfont, domain, &area, "Exporting... Press ESC to abort."); SDL_Event e; while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) { goto abort; } } gfx_domain_flip(domain); } } } abort:; ww_finish(ww); cyd.wavetable_entries = prev_entry; cyd_deinit(&cyd); song->flags &= ~MUS_NO_REPEAT; } klystrack-0.20171212/klystrack/src/version0000644000000000000000000000000513214501362017014 0ustar rootroot1.7.4klystrack-0.20171212/klystrack/src/mused.c0000644000000000000000000003416713214501362016705 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "mused.h" #include "util/bundle.h" #include "gfx/font.h" #include "gfx/gfx.h" #include "action.h" #include "event.h" #include "theme.h" #include "undo.h" #include "edit.h" #include "key.h" #include "view/wavetableview.h" #include "zap.h" #include #include extern Mused mused; extern Menu editormenu[]; extern Menu analyzermenu[]; void set_edit_buffer(char *buffer, size_t size) { if (mused.edit_backup_buffer) free(mused.edit_backup_buffer); mused.edit_backup_buffer = strdup(buffer); mused.edit_buffer = buffer; mused.edit_buffer_size = size; mused.editpos = strlen(mused.edit_buffer); change_mode(EDITBUFFER); } void change_mode(int newmode) { if (newmode == EDITBUFFER) SDL_StartTextInput(); else SDL_StopTextInput(); if (newmode < VIRTUAL_MODE && mused.mode != MENU) { gfx_clear(domain, 0); } if (mused.mode < VIRTUAL_MODE) { for (int i = 0 ; editormenu[i].parent ; ++i) editormenu[i].flags = (editormenu[i].flags & ~MENU_BULLET) | (mused.mode == CASTPTR(int, editormenu[i].p1) ? MENU_BULLET : 0); mused.prev_mode = mused.mode; mused.cursor.w = mused.cursor.h = mused.cursor_target.w = mused.cursor_target.h = 0; if (newmode != mused.mode && newmode < VIRTUAL_MODE) snapshot(S_T_MODE); } switch (newmode) { case EDITFX: if (mused.mode == EDITINSTRUMENT) { mused.fx_bus = mused.song.instrument[mused.current_instrument].fx_bus; } break; case EDITWAVETABLE: if (mused.mode == EDITINSTRUMENT) { mused.selected_wavetable = mused.song.instrument[mused.current_instrument].wavetable_entry; } break; case EDITCLASSIC: case EDITPATTERN: if (mused.mode == EDITBUFFER) break; if (mused.mode == EDITSEQUENCE || (mused.mode == MENU && !mused.single_pattern_edit) || newmode == EDITCLASSIC) { slider_move_position(&mused.current_sequencetrack, &mused.pattern_horiz_position, &mused.pattern_horiz_slider_param, 0); //slider_move_position(&mused.current_patternstep, &mused.pattern_position, &mused.pattern_slider_param, 0, mused.song.pattern[mused.current_pattern].num_steps); } else { mused.single_pattern_edit = 1; mused.current_patternx = 0; } break; } mused.mode = newmode; mused.focus = newmode; if (mused.focus == EDITCLASSIC) mused.focus = EDITPATTERN; if (mused.mode == EDITCLASSIC || mused.mode == EDITPATTERN) { mused.selected_param = 0; } } void clear_pattern(MusPattern *pat) { snapshot(S_T_PATTERN); clear_pattern_range(pat, 0, pat->num_steps); } void clear_pattern_range(MusPattern *pat, int first, int last) { for (int i = my_max(0, first) ; i < my_min(pat->num_steps, last) ; ++i) { pat->step[i].note = MUS_NOTE_NONE; pat->step[i].instrument = MUS_NOTE_NO_INSTRUMENT; pat->step[i].ctrl = 0; pat->step[i].command = 0; pat->step[i].volume = MUS_NOTE_NO_VOLUME; } } void new_song() { debug("New song"); zap_instruments(MAKEPTR(1), NULL, NULL); zap_sequence(MAKEPTR(1), NULL, NULL); mused.song.master_volume = MAX_VOLUME; mused.song.num_channels = 4; mused.song.num_instruments = NUM_INSTRUMENTS; mused.song.num_patterns = NUM_PATTERNS; mused.song.num_wavetables = CYD_WAVE_MAX_ENTRIES; mused.song.song_speed = 6; mused.song.song_speed2 = 6; mused.song.song_rate = 50; memset(mused.song.title, 0, sizeof(mused.song.title)); strcpy(mused.previous_song_filename, ""); strcpy(mused.previous_export_filename, ""); zap_fx(MAKEPTR(1), NULL, NULL); zap_wavetable(MAKEPTR(1), NULL, NULL); undo_deinit(&mused.undo); undo_init(&mused.undo); undo_deinit(&mused.redo); undo_init(&mused.redo); mused.modified = false; set_channels(mused.song.num_channels); } void kt_default_instrument(MusInstrument *inst) { mus_get_default_instrument(inst); } void resize_pattern(MusPattern * pattern, Uint16 new_size) { int old_steps = pattern->num_steps; if (new_size == old_steps) return; pattern->num_steps = new_size; if (new_size > old_steps) { pattern->step = realloc(pattern->step, sizeof(pattern->step[0]) * (size_t)new_size); clear_pattern_range(pattern, old_steps, new_size); } if (mused.focus == EDITPATTERN) { mused.selection.start = my_min(mused.selection.start, pattern->num_steps - 1); mused.selection.end = my_min(mused.selection.end, pattern->num_steps - 1); } } void default_settings() { mused.window_w = 640; mused.window_h = 480; mused.pixel_scale = 1; } void init(MusInstrument *instrument, MusPattern *pattern, MusSeqPattern sequence[MUS_MAX_CHANNELS][NUM_SEQUENCES], MusChannel *channel) { debug("init"); memset(&mused, 0, sizeof(mused)); set_info_message("Welcome to klystrack!"); default_settings(); mused.flags = MULTICHANNEL_PREVIEW|ANIMATE_CURSOR|EDIT_MODE|SHOW_LOGO|FOLLOW_PLAY_POSITION|MULTIKEY_JAMMING|START_WITH_TEMPLATE; mused.visible_columns = VC_INSTRUMENT | VC_COMMAND; mused.done = 0; mused.octave = 4; mused.note_jump = 1; mused.current_instrument = 0; mused.selected_param = 0; mused.editpos = 0; mused.mode = EDITINSTRUMENT; mused.current_patternx = 0; mused.current_sequencepos = 0; mused.default_pattern_length = mused.sequenceview_steps = 64; mused.current_sequencetrack = 0; mused.time_signature = 0x0404; mused.prev_mode = 0; mused.edit_backup_buffer = NULL; mused.mix_rate = 44100; mused.mix_buffer = 2048; mused.fx_room_size = 16; mused.fx_room_vol = 16; mused.fx_room_dec = 5; mused.oversample = 2; strcpy(mused.themename, "Default"); strcpy(mused.keymapname, "Default"); memset(&mused.cp, 0, sizeof(mused.cp)); memset(&mused.song, 0, sizeof(mused.song)); mused.song.instrument = instrument; mused.song.pattern = pattern; mused.channel = channel; for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) { mused.song.sequence[i] = sequence[i]; } for (int i = 0 ; i < NUM_PATTERNS ; ++i) { mused.song.pattern[i].step = NULL; mused.song.pattern[i].num_steps = 0; mused.song.pattern[i].color = 0; resize_pattern(&mused.song.pattern[i], mused.default_pattern_length); } undo_init(&mused.undo); undo_init(&mused.redo); enum_themes(); enum_keymaps(); //change_mode(EDITCLASSIC); mused.mode = EDITCLASSIC; mused.focus = EDITPATTERN; mused.single_pattern_edit = 1; debug("undo = %p redo = %p", mused.undo, mused.redo); for (int i = 0 ; i < WG_CHAIN_OSCS ; ++i) { mused.wgset.chain[i].osc = WG_OSC_SINE; mused.wgset.chain[i].mult = 1; mused.wgset.chain[i].op = WG_OP_MUL; mused.wgset.chain[i].shift = 0; mused.wgset.chain[i].exp = 50; mused.wgset.chain[i].flags = 0; } mused.wgset.num_oscs = 1; mused.wgset.length = 256; mused.prev_wavetable_x = -1; mused.prev_wavetable_y = -1; debug("init done"); } void init_scrollbars() { slider_set_params(&mused.sequence_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_VERTICAL, mused.slider_bevel); slider_set_params(&mused.pattern_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_VERTICAL, mused.slider_bevel); slider_set_params(&mused.instrument_list_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_VERTICAL, mused.slider_bevel); slider_set_params(&mused.pattern_horiz_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_HORIZONTAL, mused.slider_bevel); slider_set_params(&mused.sequence_horiz_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_HORIZONTAL, mused.slider_bevel); slider_set_params(&mused.program_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_VERTICAL, mused.slider_bevel); slider_set_params(&mused.wavetable_list_slider_param, 0, 0, 0, 0, &mused.sequence_position, 1, SLIDER_VERTICAL, mused.slider_bevel); } void deinit() { undo_deinit(&mused.undo); undo_deinit(&mused.redo); console_destroy(mused.console); if (mused.slider_bevel) gfx_free_surface(mused.slider_bevel); if (mused.vu_meter) gfx_free_surface(mused.vu_meter); if (mused.analyzer) gfx_free_surface(mused.analyzer); if (mused.logo) gfx_free_surface(mused.logo); if (mused.catometer) gfx_free_surface(mused.catometer); if (mused.mouse_cursor_surface) gfx_free_surface(mused.mouse_cursor_surface); if (mused.mouse_cursor) SDL_FreeCursor(mused.mouse_cursor); if (mused.icon_surface) gfx_free_surface(mused.icon_surface); font_destroy(&mused.smallfont); font_destroy(&mused.largefont); font_destroy(&mused.tinyfont); font_destroy(&mused.tinyfont_sequence_counter); font_destroy(&mused.tinyfont_sequence_normal); font_destroy(&mused.menufont); font_destroy(&mused.menufont_selected); font_destroy(&mused.shortcutfont); font_destroy(&mused.shortcutfont_selected); font_destroy(&mused.headerfont); font_destroy(&mused.headerfont_selected); font_destroy(&mused.buttonfont); free_themes(); if (mused.wavetable_preview) gfx_free_surface(mused.wavetable_preview); } void mirror_flags() { // We need to mirror the flags to the corresponding Cyd flags for (int fx = 0 ; fx < CYD_MAX_FX_CHANNELS ; ++fx) { mused.cyd.fx[fx].flags = mused.song.fx[fx].flags; } mused.mus.volume = mused.song.master_volume; } int viscol(int col) { const int tab[PED_PARAMS] = { -1, VC_INSTRUMENT, VC_INSTRUMENT, VC_VOLUME, VC_VOLUME, VC_CTRL, VC_CTRL, VC_CTRL, VC_COMMAND, VC_COMMAND, VC_COMMAND, VC_COMMAND }; return !(mused.flags & COMPACT_VIEW) || (mused.visible_columns & tab[col]); } void post_config_load() { int new_val = mused.default_pattern_length; mused.default_pattern_length = 16; change_default_pattern_length(MAKEPTR(new_val), 0, 0); change_visualizer(mused.current_visualizer); } static int tick_cb(void *data) { return mus_advance_tick(data); } void enable_callback(bool state) { if (state) cyd_set_callback(&mused.cyd, tick_cb, &mused.mus, mused.song.song_rate); else cyd_set_callback(&mused.cyd, NULL, NULL, 0); } int get_pattern(int abspos, int track) { int p = -1; const MusSeqPattern *sp = &mused.song.sequence[track][0]; for (int i = 0 ; i < mused.song.num_sequences[track] && sp->position <= abspos ; ++i, ++sp) { if (sp->position <= abspos && sp->position + mused.song.pattern[sp->pattern].num_steps > abspos) p = sp->pattern; } return p; } int get_patternstep(int abspos, int track) { int p = -1; const MusSeqPattern *sp = &mused.song.sequence[track][0]; for (int i = 0 ; i < mused.song.num_sequences[track] && sp->position <= abspos ; ++i, ++sp) { if (sp->position <= abspos && sp->position + mused.song.pattern[sp->pattern].num_steps > abspos) p = abspos - sp->position; } return p; } int current_pattern() { return current_pattern_for_channel(mused.current_sequencetrack); } int current_pattern_for_channel(int channel) { int p = -1; const MusSeqPattern *sp = &mused.song.sequence[channel][0]; for (int i = 0 ; i < mused.song.num_sequences[channel] && sp->position <= mused.current_patternpos ; ++i, ++sp) { if (sp->position <= mused.current_patternpos && sp->position + mused.song.pattern[sp->pattern].num_steps > mused.current_patternpos) p = sp->pattern; } return p; } int current_patternstep() { int p = -1; const MusSeqPattern *sp = &mused.song.sequence[mused.current_sequencetrack][0]; for (int i = 0 ; i < mused.song.num_sequences[mused.current_sequencetrack] && sp->position <= mused.current_patternpos ; ++i, ++sp) { if (sp->position <= mused.current_patternpos && sp->position + mused.song.pattern[sp->pattern].num_steps > mused.current_patternpos) p = mused.current_patternpos - sp->position; } return p; } MusStep * get_current_step() { MusPattern *pat = get_current_pattern(); if (!pat) return NULL; return &pat->step[current_patternstep()]; } MusPattern * get_current_pattern() { int p = current_pattern(); if (p < 0) return NULL; return &mused.song.pattern[p]; } void change_visualizer(int vis) { mused.current_visualizer = vis; for (int i = 0 ; analyzermenu[i].parent ; ++i) analyzermenu[i].flags = (analyzermenu[i].flags & ~MENU_BULLET) | (mused.current_visualizer == CASTPTR(int, analyzermenu[i].p1) ? MENU_BULLET : 0); } static Uint32 info_message_cb(Uint32 interval, void *param) { strcpy(mused.info_message, ""); SDL_RemoveTimer(mused.info_message_timer); mused.info_message_timer = 0; return 0; } void set_info_message(const char *message, ...) { if (mused.info_message_timer) SDL_RemoveTimer(mused.info_message_timer); va_list args; va_start(args, message); vsnprintf(mused.info_message, sizeof(mused.info_message), message, args); va_end(args); mused.info_message_timer = SDL_AddTimer(5000, info_message_cb, NULL); } void set_channels(int channels) { debug("Changed num_channels = %d", channels); mused.song.num_channels = channels; cyd_reserve_channels(&mused.cyd, channels); } Uint32 get_playtime_at(int position) { return mus_get_playtime_at(&mused.song, position); } klystrack-0.20171212/klystrack/src/songstats.h0000644000000000000000000000045513214501362017613 0ustar rootroot#ifndef SONG_STATS_H #define SONG_STATS_H enum { STATS_HEADER, STATS_FX, STATS_DEFVOLPAN, STATS_INSTRUMENTS, STATS_SEQUENCE, STATS_PATTERNS, STATS_WAVETABLE, STATS_WAVETABLE_NAMES, N_STATS }; typedef struct { int size[N_STATS]; int total_size; } SongStats; #endif klystrack-0.20171212/klystrack/src/stats.c0000644000000000000000000000305413214501362016715 0ustar rootroot#include "stats.h" #include "memwriter.h" #include "diskop.h" #include "macros.h" #include "mused.h" #include "gui/msgbox.h" static void get_stats(SongStats *stats) { SDL_RWops *rw = create_memwriter(NULL); save_song_inner(rw, stats); SDL_RWclose(rw); } void song_stats(void *unused1, void *unused2, void *unused3) { SongStats stats; get_stats(&stats); char str[1000]; snprintf(str, sizeof(str), "Header: %6d bytes %2d %%\n" "FX: %6d bytes %2d %%\n" "Def.vol/pan: %6d bytes %2d %%\n" "Instruments: %6d bytes %2d %%\n" "Sequence: %6d bytes %2d %%\n" "Patterns: %6d bytes %2d %%\n" "Wavetable: %6d bytes %2d %%\n" "Wave names: %6d bytes %2d %%\n" "-------------------------------\n" "TOTAL: %6d bytes", stats.size[STATS_HEADER], stats.size[STATS_HEADER] * 100 / stats.total_size, stats.size[STATS_FX], stats.size[STATS_FX] * 100 / stats.total_size, stats.size[STATS_DEFVOLPAN], stats.size[STATS_DEFVOLPAN] * 100 / stats.total_size, stats.size[STATS_INSTRUMENTS], stats.size[STATS_INSTRUMENTS] * 100 / stats.total_size, stats.size[STATS_SEQUENCE], stats.size[STATS_SEQUENCE] * 100 / stats.total_size, stats.size[STATS_PATTERNS], stats.size[STATS_PATTERNS] * 100 / stats.total_size, stats.size[STATS_WAVETABLE], stats.size[STATS_WAVETABLE] * 100 / stats.total_size, stats.size[STATS_WAVETABLE_NAMES], stats.size[STATS_WAVETABLE_NAMES] * 100 / stats.total_size, stats.total_size ); msgbox(domain, mused.slider_bevel, &mused.largefont, str, MB_OK); } klystrack-0.20171212/klystrack/src/console.c0000644000000000000000000000567613214501362017235 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "console.h" #include "util/bundle.h" #include "mused.h" #include "theme.h" #include extern Mused mused; extern Uint32 colors[]; void console_set_background(Console * c, int enabled) { c->background = enabled; /*c->font.surface->surface = c->fontsurface[enabled]; int l = strlen(c->font.charmap); for (int i = 0 ; i < l ; ++i) c->font.tiledescriptor[i].surface = c->font.surface;*/ } void console_set_color(Console* console, Uint32 color) { if (console->current_color != color) { console->current_color = color; font_set_color(&console->font, console->current_color); } } const SDL_Rect * console_write(Console* console, const char *string) { static SDL_Rect bounds; bounds.w = bounds.h = 0; font_write_cursor(&console->font, domain, &console->clip, &console->cursor, &bounds, string); return &bounds; } const SDL_Rect * console_write_args(Console* console, const char *string, ...) { static SDL_Rect bounds; bounds.w = bounds.h = 0; va_list va; va_start(va, string); font_write_va(&console->font, domain, &console->clip, &console->cursor, &bounds, string, va); va_end(va); return &bounds; } void console_clear(Console *console) { gfx_rect(domain, &console->clip, colors[COLOR_BACKGROUND]); console->cursor = 0; } Console * console_create(Bundle *b) { Console * c = calloc(1, sizeof(*c)); c->cursor = 0; font_load(domain, &c->font, b, "8x8.fnt"); console_set_background(c, 0); c->clip.x = 0; c->clip.y = 0; c->clip.w = domain->screen_w; c->clip.h = domain->screen_h; return c; } void console_destroy(Console *c) { font_destroy(&c->font); free(c); } void console_set_clip(Console * c, const SDL_Rect *rect) { memcpy(&c->clip, rect, sizeof(*rect)); } void console_reset_cursor(Console * c) { c->cursor = 0; } klystrack-0.20171212/klystrack/src/wavegen.c0000644000000000000000000000343013214501362017211 0ustar rootroot#include "wavegen.h" #include "util/rnd.h" #include #include "macros.h" float wg_osc(WgOsc *osc, float _phase) { double intpart = 0.0f; double phase = pow(modf(_phase * osc->mult + (float)osc->shift / 8, &intpart), osc->exp_c); float output = 0; switch (osc->osc) { default: case WG_OSC_SINE: output = sin(phase * M_PI * 2.0f); break; case WG_OSC_SQUARE: output = phase >= 0.5f ? -1.0f : 1.0f; break; case WG_OSC_TRIANGLE: if (phase < 0.5f) output = phase * 4.0f - 1.0f; else output = 1.0f - (phase - 0.5f) * 4.0f; break; case WG_OSC_SAW: output = phase * 2.0f - 1.0f; break; case WG_OSC_NOISE: output = rndf() * 2.0f - 1.0f; } if (osc->flags & WG_OSC_FLAG_ABS) { output = output * 0.5 + 0.5f; } if (osc->flags & WG_OSC_FLAG_NEG) { output = -output; } return output; } float wg_get_sample(WgOsc *chain, int num_oscs, float phase) { float sample = 0; WgOpType op = WG_OP_ADD; for (int i = 0 ; i < num_oscs ; ++i) { WgOsc *osc = &chain[i]; float output = wg_osc(osc, phase); switch (op) { default: case WG_OP_ADD: sample += output; break; case WG_OP_MUL: sample *= output; break; } op = osc->op; } return sample; } void wg_init_osc(WgOsc *osc) { osc->exp_c = log(0.5f) / log((float)osc->exp / 100); } void wg_gen_waveform(WgOsc *chain, int num_oscs, Sint16 *data, int len) { for (int i = 0 ; i < num_oscs ; ++i) { wg_init_osc(&chain[i]); } for (int i = 0 ; i < len ; ++i) { double s = wg_get_sample(chain, num_oscs, (float)i / len); if (s > 1.0) s = 1.0; else if (s < -1.0) s = -1.0; data[i] = 32767 * s; } } klystrack-0.20171212/klystrack/src/action.h0000644000000000000000000001043413214501362017041 0ustar rootroot#ifndef ACTION_H #define ACTION_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ void select_sequence_position(void *channel, void *position, void *); void select_pattern_param(void *id, void *position, void *pattern); void select_instrument_param(void *idx, void *, void *); void select_instrument(void *idx, void *relative, void *pagey); void select_wavetable(void *idx, void *, void *); void select_instrument_page(void *page, void *relative, void *); void change_default_pattern_length(void *length, void *, void *); void select_program_step(void *idx, void *, void *); void change_octave(void *delta, void *, void *); void change_song_rate(void *delta, void *, void *); void change_time_signature(void *beat, void *, void *); void play(void *from_cursor, void*, void*); void play_position(void *, void*, void*); void stop(void*,void*,void*); void change_song_speed(void *speed, void *delta, void *); void new_song_action(void *, void *, void *); void kill_instrument(void *, void *, void *); void generic_action(void *func, void *, void *); void quit_action(void *, void *, void *); void change_mode_action(void *mode, void *, void *); void enable_channel(void *channel, void *, void *); void solo_channel(void *channel, void *, void *); void enable_reverb(void *unused1, void *unused2, void *unused3); void select_all(void *, void *, void*); void clear_selection(void *, void *, void*); void cycle_focus(void *views, void *focus, void *mode); void change_song_length(void *delta, void *, void *); void change_loop_point(void *delta, void *, void *); void change_seq_steps(void *delta, void *, void *); void change_timesig(void *delta, void *, void *); void show_about_box(void *unused1, void *unused2, void *unused3); void change_channels(void *delta, void *unused1, void *unused2); void change_master_volume(void *delta, void *unused1, void *unused2); void begin_selection_action(void *unused1, void *unused2, void *unused3); void end_selection_action(void *unused1, void *unused2, void *unused3); void toggle_pixel_scale(void *, void*, void*); void change_pixel_scale(void *scale, void*, void*); void toggle_fullscreen(void *a, void*b, void*c); void change_fullscreen(void *a, void*b, void*c); void toggle_render_to_texture(void *a, void*b, void*c); void change_render_to_texture(void *a, void*b, void*c); void load_theme_action(void *a, void*b, void*c); void load_keymap_action(void *a, void*b, void*c); void unmute_all_action(void*, void*, void*); void export_wav_action(void *a, void*b, void*c); void export_channels_action(void *a, void*b, void*c); void open_data(void *type, void*b, void*c); void do_undo(void *stack, void*b, void*c); void kill_wavetable_entry(void *a, void*b, void*c); void open_menu_action(void*,void*,void*); void flip_bit_action(void *bits, void *mask, void *); void set_note_jump(void *steps, void *, void *); void change_visualizer_action(void *vis, void *unused1, void *unused2); void open_help(void *unused0, void *unused1, void *unused2); void change_oversample(void *oversample, void *unused1, void *unused2); void toggle_follow_play_position(void *unused1, void *unused2, void *unused3); void toggle_visualizer(void *unused1, void *unused2, void *unused3); void toggle_mouse_cursor(void *a, void*b, void*c); #endif klystrack-0.20171212/klystrack/src/event.c0000644000000000000000000015474313214501362016714 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "event.h" #include "mused.h" #include "action.h" #include "edit.h" #include "util/rnd.h" #include #include "snd/cydwave.h" #include "snd/freqs.h" #include "mymsg.h" #include "command.h" extern Mused mused; #define flipbit(val, bit) { val ^= bit; }; void editparambox(int v) { MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; Uint16 *param = &inst->program[mused.current_program_step]; Uint32 mask = 0xffff0fff >> (mused.editpos*4); if (*param == MUS_FX_NOP) *param = 0; if (mused.editpos != 0 || v < 0xf) { // Keeps the exec next command bit intact *param = (*param & 0x8000) | (((*param & mask) | ((v&0xf) <<((3-mused.editpos)*4))) & 0x7fff); } else { *param = ((*param & mask) | ((v&0xf) <<((3-mused.editpos)*4))); } if (++mused.editpos > 3) { *param = validate_command(*param); mused.editpos = 3; } } int find_note(int sym, int oct) { static const int keys[] = { SDLK_z, SDLK_s, SDLK_x, SDLK_d, SDLK_c, SDLK_v, SDLK_g, SDLK_b, SDLK_h, SDLK_n, SDLK_j, SDLK_m, SDLK_q, SDLK_2, SDLK_w, SDLK_3, SDLK_e, SDLK_r, SDLK_5, SDLK_t, SDLK_6, SDLK_y, SDLK_7, SDLK_u, SDLK_i, SDLK_9, SDLK_o, SDLK_0, SDLK_p, -1}; int n = 0; for (const int *i = keys ; *i != -1 ; ++i, ++n) { if (*i == sym) return n + oct*12; } return -1; } void instrument_add_param(int a) { MusInstrument *i = &mused.song.instrument[mused.current_instrument]; if (a < 0) a = -1; else if (a > 0) a = 1; if (SDL_GetModState() & KMOD_SHIFT) { switch (mused.selected_param) { case P_BASENOTE: a *= 12; break; case P_BUZZ_SEMI: a *= 12; break; default: a *= 16; break; } } switch (mused.selected_param) { case P_INSTRUMENT: clamp(mused.current_instrument, a, 0, NUM_INSTRUMENTS - 1); break; case P_BASENOTE: clamp(i->base_note, a, 0, 95); break; case P_FINETUNE: clamp(i->finetune, a, -128, 127); break; case P_LOCKNOTE: flipbit(i->flags, MUS_INST_LOCK_NOTE); break; case P_DRUM: flipbit(i->flags, MUS_INST_DRUM); break; case P_KEYSYNC: flipbit(i->cydflags, CYD_CHN_ENABLE_KEY_SYNC); break; case P_SYNC: flipbit(i->cydflags, CYD_CHN_ENABLE_SYNC); break; case P_SYNCSRC: { int x = (Uint8)(i->sync_source+1); clamp(x, a, 0, MUS_MAX_CHANNELS); i->sync_source = x-1; } break; case P_WAVE: flipbit(i->cydflags, CYD_CHN_ENABLE_WAVE); break; case P_WAVE_ENTRY: clamp(i->wavetable_entry, a, 0, CYD_WAVE_MAX_ENTRIES - 1); break; case P_WAVE_OVERRIDE_ENV: flipbit(i->cydflags, CYD_CHN_WAVE_OVERRIDE_ENV); break; case P_WAVE_LOCK_NOTE: flipbit(i->flags, MUS_INST_WAVE_LOCK_NOTE); break; case P_PULSE: flipbit(i->cydflags, CYD_CHN_ENABLE_PULSE); break; case P_SAW: flipbit(i->cydflags, CYD_CHN_ENABLE_SAW); break; case P_TRIANGLE: flipbit(i->cydflags, CYD_CHN_ENABLE_TRIANGLE); break; case P_LFSR: flipbit(i->cydflags, CYD_CHN_ENABLE_LFSR); break; case P_LFSRTYPE: clamp(i->lfsr_type, a, 0, CYD_NUM_LFSR - 1); break; case P_NOISE: flipbit(i->cydflags, CYD_CHN_ENABLE_NOISE); break; case P_METAL: flipbit(i->cydflags, CYD_CHN_ENABLE_METAL); break; case P_RELVOL: flipbit(i->flags, MUS_INST_RELATIVE_VOLUME); break; case P_FX: flipbit(i->cydflags, CYD_CHN_ENABLE_FX); break; case P_FXBUS: clamp(i->fx_bus, a, 0, CYD_MAX_FX_CHANNELS - 1); break; case P_ATTACK: clamp(i->adsr.a, a, 0, 32 * ENVELOPE_SCALE - 1); break; case P_DECAY: clamp(i->adsr.d, a, 0, 32 * ENVELOPE_SCALE - 1); break; case P_SUSTAIN: clamp(i->adsr.s, a, 0, 31); break; case P_RELEASE: clamp(i->adsr.r, a, 0, 32 * ENVELOPE_SCALE - 1); break; case P_BUZZ: flipbit(i->flags, MUS_INST_YM_BUZZ); break; case P_BUZZ_SHAPE: clamp(i->ym_env_shape, a, 0, 3); break; case P_BUZZ_FINE: { clamp(i->buzz_offset, a, -32768, 32767); } break; case P_BUZZ_SEMI: { int f = i->buzz_offset >> 8; clamp(f, a, -99, 99); i->buzz_offset = (i->buzz_offset & 0xff) | f << 8; } break; case P_PW: clamp(i->pw, a*16, 0, 0x7ff); break; case P_1_4TH: flipbit(i->flags, MUS_INST_QUARTER_FREQ); break; case P_VOLUME: clamp(i->volume, a, 0, 255); // 255 = ~2x boost break; case P_PROGPERIOD: clamp(i->prog_period, a, 0, 0xff); break; case P_SLIDESPEED: clamp(i->slide_speed, a, 0, 0xff); break; case P_VIBDEPTH: clamp(i->vibrato_depth, a, 0, 0xff); break; case P_VIBDELAY: clamp(i->vib_delay, a, 0, 0xff); break; case P_VIBSHAPE: clamp(i->vib_shape, a, 0, MUS_NUM_SHAPES - 1); break; case P_VIBSPEED: clamp(i->vibrato_speed, a, 0, 0xff); break; case P_PWMDEPTH: clamp(i->pwm_depth, a, 0, 0xff); break; case P_PWMSPEED: clamp(i->pwm_speed, a, 0, 0xff); break; case P_PWMSHAPE: clamp(i->pwm_shape, a, 0, MUS_NUM_SHAPES - 1); break; case P_RINGMOD: flipbit(i->cydflags, CYD_CHN_ENABLE_RING_MODULATION); break; case P_SETPW: flipbit(i->flags, MUS_INST_SET_PW); break; case P_SETCUTOFF: flipbit(i->flags, MUS_INST_SET_CUTOFF); break; case P_INVVIB: flipbit(i->flags, MUS_INST_INVERT_VIBRATO_BIT); break; case P_FILTER: flipbit(i->cydflags, CYD_CHN_ENABLE_FILTER); break; case P_RINGMODSRC: { int x = (Uint8)(i->ring_mod+1); clamp(x, a, 0, MUS_MAX_CHANNELS); i->ring_mod = x-1; } break; case P_CUTOFF: clamp(i->cutoff, a*16, 0, 2047); break; case P_RESONANCE: clamp(i->resonance, a, 0, 3); break; case P_FLTTYPE: clamp(i->flttype, a, 0, FLT_TYPES - 1); break; case P_NORESTART: flipbit(i->flags, MUS_INST_NO_PROG_RESTART); break; case P_MULTIOSC: flipbit(i->flags, MUS_INST_MULTIOSC); break; case P_FM_MODULATION: clamp(i->fm_modulation, a, 0, 0x7f); break; case P_FM_FEEDBACK: clamp(i->fm_feedback, a, 0, 0x7); break; case P_FM_ATTACK: clamp(i->fm_adsr.a, a, 0, 32 * ENVELOPE_SCALE - 1); break; case P_FM_DECAY: clamp(i->fm_adsr.d, a, 0, 32 * ENVELOPE_SCALE - 1); break; case P_FM_SUSTAIN: clamp(i->fm_adsr.s, a, 0, 31); break; case P_FM_RELEASE: clamp(i->fm_adsr.r, a, 0, 32 * ENVELOPE_SCALE - 1); break; case P_FM_ENV_START: clamp(i->fm_attack_start, a, 0, 31); break; case P_FM_WAVE: flipbit(i->fm_flags, CYD_FM_ENABLE_WAVE); break; case P_FM_ENABLE: flipbit(i->cydflags, CYD_CHN_ENABLE_FM); break; case P_FM_HARMONIC_CARRIER: { Uint8 carrier = (i->fm_harmonic >> 4); Uint8 modulator = i->fm_harmonic & 0xf; clamp(carrier, a, 0, 15); i->fm_harmonic = carrier << 4 | modulator; } break; case P_FM_HARMONIC_MODULATOR: { Uint8 carrier = (i->fm_harmonic >> 4); Uint8 modulator = i->fm_harmonic & 0xf; clamp(modulator, a, 0, 15); i->fm_harmonic = carrier << 4 | modulator; } break; case P_FM_WAVE_ENTRY: clamp(i->fm_wave, a, 0, CYD_WAVE_MAX_ENTRIES - 1); break; default: break; } } static void play_the_jams(int sym, int chn, int state) { if (sym == SDLK_SPACE && state == 0) { for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) cyd_enable_gate(mused.mus.cyd, &mused.mus.cyd->channel[i], 0); } else { int note = find_note(sym, mused.octave); if (note != -1) { if (mused.flags & MULTIKEY_JAMMING) { SDL_Event e; e.type = state ? MSG_NOTEON : MSG_NOTEOFF; e.user.code = note; e.user.data1 = NULL; SDL_PushEvent(&e); } else { if (state == 1) { if (chn == -1 && !(mused.flags & MULTICHANNEL_PREVIEW)) chn = 0; int c = mus_trigger_instrument(&mused.mus, chn, &mused.song.instrument[mused.current_instrument], note << 8, CYD_PAN_CENTER); mused.mus.song_track[c].extarp1 = 0; mused.mus.song_track[c].extarp2 = 0; } } } } } static void wave_the_jams(int sym) { if (sym == SDLK_SPACE) { for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i) cyd_enable_gate(mused.mus.cyd, &mused.mus.cyd->channel[i], 0); } else { int note = find_note(sym, mused.octave); if (note != -1) { static MusInstrument inst; mus_get_default_instrument(&inst); inst.wavetable_entry = mused.selected_wavetable; inst.cydflags &= ~WAVEFORMS; inst.cydflags |= CYD_CHN_WAVE_OVERRIDE_ENV | CYD_CHN_ENABLE_WAVE; inst.flags &= ~MUS_INST_DRUM; mus_trigger_instrument(&mused.mus, 0, &inst, note << 8, CYD_PAN_CENTER); } } } void edit_instrument_event(SDL_Event *e) { switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_RETURN: { if (mused.selected_param == P_NAME) set_edit_buffer(mused.song.instrument[mused.current_instrument].name, sizeof(mused.song.instrument[mused.current_instrument].name)); } break; case SDLK_DOWN: { ++mused.selected_param; if (mused.mode == EDITINSTRUMENT) { if (mused.selected_param >= P_PARAMS) mused.selected_param = P_PARAMS - 1; } else { if (mused.selected_param >= P_NAME) mused.selected_param = P_NAME; } } break; case SDLK_UP: { --mused.selected_param; if (mused.selected_param < 0) mused.selected_param = 0; } break; case SDLK_RIGHT: { instrument_add_param(+1); } break; case SDLK_LEFT: { instrument_add_param(-1); } break; default: { play_the_jams(e->key.keysym.sym, -1, 1); } break; } break; case SDL_KEYUP: play_the_jams(e->key.keysym.sym, -1, 0); break; } } static int gethex(int key) { if (key >= SDLK_0 && key <= SDLK_9) { return key - SDLK_0; } else if (key >= SDLK_KP_0 && key <= SDLK_KP_9) { return key - SDLK_KP_0; } else if (key >= SDLK_a && key <= SDLK_f) { return key - SDLK_a + 0xa; } else return -1; } static int getalphanum(const SDL_Keysym *keysym) { int key = keysym->sym; if (key >= SDLK_0 && key <= SDLK_9) { return key - SDLK_0; } else if (key >= SDLK_KP_0 && key <= SDLK_KP_9) { return key - SDLK_KP_0; } else if (!(keysym->mod & KMOD_SHIFT) && key >= SDLK_a && key <= SDLK_z) { return key - SDLK_a + 0xa; } else if ((keysym->mod & KMOD_SHIFT) && key >= SDLK_a && key <= SDLK_z) { return key - SDLK_a + 0xa + (SDLK_z - SDLK_a) + 1; } else return -1; } static int seqsort(const void *_a, const void *_b) { const MusSeqPattern *a = _a; const MusSeqPattern *b = _b; if (a->position > b->position) return 1; if (a->position < b->position) return -1; return 0; } void add_sequence(int channel, int position, int pattern, int offset) { if(mused.song.pattern[pattern].num_steps == 0) resize_pattern(&mused.song.pattern[pattern], mused.sequenceview_steps); for (int i = 0 ; i < mused.song.num_sequences[channel] ; ++i) if (mused.song.sequence[channel][i].position == position) { mused.song.sequence[channel][i].pattern = pattern; mused.song.sequence[channel][i].note_offset = offset; return; } if (mused.song.num_sequences[channel] >= NUM_SEQUENCES) return; mused.song.sequence[channel][mused.song.num_sequences[channel]].position = position; mused.song.sequence[channel][mused.song.num_sequences[channel]].pattern = pattern; mused.song.sequence[channel][mused.song.num_sequences[channel]].note_offset = offset; ++mused.song.num_sequences[channel]; qsort(mused.song.sequence[channel], mused.song.num_sequences[channel], sizeof(mused.song.sequence[channel][0]), seqsort); } Uint8 get_pattern_at(int channel, int position) { for (int i = 0 ; i < mused.song.num_sequences[channel] ; ++i) if (mused.song.sequence[channel][i].position == position) { return mused.song.sequence[channel][i].pattern; } return 0; } void del_sequence(int first,int last,int track) { if (mused.song.num_sequences[track] == 0) return; for (int i = 0 ; i < mused.song.num_sequences[mused.current_sequencetrack] ; ++i) if (mused.song.sequence[track][i].position >= first && mused.song.sequence[track][i].position < last) { mused.song.sequence[track][i].position = 0xffff; } qsort(mused.song.sequence[track], mused.song.num_sequences[track], sizeof(mused.song.sequence[track][0]), seqsort); while (mused.song.num_sequences[track] > 0 && mused.song.sequence[track][mused.song.num_sequences[track]-1].position == 0xffff) --mused.song.num_sequences[track]; } void add_note_offset(int a) { { for (int i = (int)mused.song.num_sequences[mused.current_sequencetrack] - 1 ; i >= 0 ; --i) { if (mused.current_sequencepos >= mused.song.sequence[mused.current_sequencetrack][i].position && mused.song.sequence[mused.current_sequencetrack][i].position + mused.song.pattern[mused.song.sequence[mused.current_sequencetrack][i].pattern].num_steps > mused.current_sequencepos) { mused.song.sequence[mused.current_sequencetrack][i].note_offset += a; break; } } } } static void update_sequence_slider(int d) { int o = mused.current_sequencepos - mused.current_patternpos; slider_move_position(&mused.current_sequencepos, &mused.sequence_position, &mused.sequence_slider_param, d); if (!(mused.flags & SONG_PLAYING)) mused.pattern_position = mused.current_patternpos = mused.current_sequencepos - o; } static void update_pattern_slider(int d) { /*if (mused.flags & CENTER_PATTERN_EDITOR) { mused.pattern_position = current_patternstep() + d; if (mused.pattern_position < 0) mused.pattern_position += mused.song.pattern[current_pattern()].num_steps; if (mused.pattern_position >= mused.song.pattern[current_pattern()].num_steps) mused.pattern_position -= mused.song.pattern[current_pattern()].num_steps; current_patternstep() = mused.pattern_position; } else */ slider_move_position(&mused.current_patternpos, &mused.pattern_position, &mused.pattern_slider_param, d); mused.pattern_position = mused.current_patternpos; if (!(mused.flags & SONG_PLAYING)) mused.current_sequencepos = mused.current_patternpos - mused.current_patternpos % mused.sequenceview_steps; } void update_position_sliders() { update_pattern_slider(0); update_sequence_slider(0); } void update_horiz_sliders() { slider_move_position(&mused.current_sequencetrack, &mused.sequence_horiz_position, &mused.sequence_horiz_slider_param, 0); slider_move_position(&mused.current_sequencetrack, &mused.pattern_horiz_position, &mused.pattern_horiz_slider_param, 0); } void sequence_event(SDL_Event *e) { switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_SPACE: { if ((mused.flags & TOGGLE_EDIT_ON_STOP) || !(mused.flags & SONG_PLAYING)) mused.flags ^= EDIT_MODE; if (mused.flags & SONG_PLAYING) stop(0, 0, 0); } break; case SDLK_RETURN: { if (mused.mode != EDITCLASSIC) change_mode(EDITPATTERN); else mused.focus = EDITPATTERN; //mused.current_patternpos = mused.current_sequencepos; update_position_sliders(); } break; case SDLK_LSHIFT: case SDLK_RSHIFT: begin_selection(mused.current_sequencepos); break; case SDLK_PAGEDOWN: case SDLK_DOWN: { if (e->key.keysym.mod & KMOD_ALT) { snapshot(S_T_SEQUENCE); add_note_offset(-1); break; } int steps = mused.sequenceview_steps; if (e->key.keysym.sym == SDLK_PAGEDOWN) steps *= 16; if (e->key.keysym.mod & KMOD_CTRL) { snapshot_cascade(S_T_SONGINFO, SI_LOOP, -1); if (e->key.keysym.mod & KMOD_SHIFT) { change_loop_point(MAKEPTR(steps), 0, 0); } else { change_song_length(MAKEPTR(steps), 0, 0); } } else { update_sequence_slider(steps); } if (((e->key.keysym.mod & KMOD_SHIFT) && !(e->key.keysym.mod & KMOD_CTRL)) ) { select_range(mused.current_sequencepos); } } break; case SDLK_PAGEUP: case SDLK_UP: { if (e->key.keysym.mod & KMOD_ALT) { snapshot(S_T_SEQUENCE); add_note_offset(1); break; } int steps = mused.sequenceview_steps; if (e->key.keysym.sym == SDLK_PAGEUP) steps *= 16; if (e->key.keysym.mod & KMOD_CTRL) { snapshot_cascade(S_T_SONGINFO, SI_LOOP, -1); if (e->key.keysym.mod & KMOD_SHIFT) { change_loop_point(MAKEPTR(-steps), 0,0); } else { change_song_length(MAKEPTR(-steps), 0, 0); } } else { update_sequence_slider(-steps); } if (((e->key.keysym.mod & KMOD_SHIFT) && !(e->key.keysym.mod & KMOD_CTRL)) ) { select_range(mused.current_sequencepos); } } break; case SDLK_INSERT: { snapshot(S_T_SEQUENCE); for (int i = 0; i < mused.song.num_sequences[mused.current_sequencetrack] ; ++i) { if (mused.song.sequence[mused.current_sequencetrack][i].position >= mused.current_sequencepos) mused.song.sequence[mused.current_sequencetrack][i].position += mused.sequenceview_steps; } } break; case SDLK_PERIOD: { snapshot(S_T_SEQUENCE); del_sequence(mused.current_sequencepos, mused.current_sequencepos+mused.sequenceview_steps, mused.current_sequencetrack); if (mused.song.song_length > mused.current_sequencepos + mused.sequenceview_steps) mused.current_sequencepos += mused.sequenceview_steps; } break; case SDLK_DELETE: { snapshot(S_T_SEQUENCE); del_sequence(mused.current_sequencepos, mused.current_sequencepos+mused.sequenceview_steps, mused.current_sequencetrack); if (!(mused.flags & DELETE_EMPTIES)) { for (int i = 0; i < mused.song.num_sequences[mused.current_sequencetrack] ; ++i) { if (mused.song.sequence[mused.current_sequencetrack][i].position >= mused.current_sequencepos) mused.song.sequence[mused.current_sequencetrack][i].position -= mused.sequenceview_steps; } } } break; case SDLK_RIGHT: { if (e->key.keysym.mod & KMOD_CTRL) { change_seq_steps((void *)1, 0, 0); } else { if (mused.flags & EDIT_SEQUENCE_DIGITS) { if (mused.sequence_digit < 1) { ++mused.sequence_digit; break; } } mused.sequence_digit = 0; ++mused.current_sequencetrack; if (mused.current_sequencetrack >= mused.song.num_channels) mused.current_sequencetrack = 0; update_horiz_sliders(); } } break; case SDLK_LEFT: { if (e->key.keysym.mod & KMOD_CTRL) { change_seq_steps((void *)-1, 0, 0); } else { if (mused.flags & EDIT_SEQUENCE_DIGITS) { if (mused.sequence_digit > 0) { --mused.sequence_digit; break; } } mused.sequence_digit = 0; --mused.current_sequencetrack; if (mused.current_sequencetrack < 0) mused.current_sequencetrack = mused.song.num_channels - 1; update_horiz_sliders(); } } break; default: { if (mused.flags & EDIT_SEQUENCE_DIGITS) { int k; if ((k = gethex(e->key.keysym.sym)) != -1) { snapshot(S_T_SEQUENCE); Uint8 p = get_pattern_at(mused.current_sequencetrack, mused.current_sequencepos); if (mused.sequence_digit == 0) p = (p & (0x0f)) | (k << 4); else p = (p & (0xf0)) | k; add_sequence(mused.current_sequencetrack, mused.current_sequencepos, p, 0); if (mused.song.song_length > mused.current_sequencepos + mused.sequenceview_steps) { mused.current_sequencepos += mused.sequenceview_steps; mused.current_patternpos += mused.sequenceview_steps; update_position_sliders(); } } } else { int p = getalphanum(&e->key.keysym); if (p != -1 && p < NUM_PATTERNS) { snapshot(S_T_SEQUENCE); add_sequence(mused.current_sequencetrack, mused.current_sequencepos, p, 0); if (mused.song.song_length > mused.current_sequencepos + mused.sequenceview_steps) { mused.current_sequencepos += mused.sequenceview_steps; mused.current_patternpos += mused.sequenceview_steps; update_position_sliders(); } } } } break; } break; } //update_ghost_patterns(); } static void switch_track(int d) { mused.current_sequencetrack = (mused.current_sequencetrack + (int)mused.song.num_channels + d) % mused.song.num_channels; update_horiz_sliders(); mused.sequence_digit = 0; } void pattern_event(SDL_Event *e) { int last_param = PED_PARAMS - 1; if (!viscol(PED_COMMAND1)) last_param = my_max(PED_COMMAND1 - 1, last_param); else if (!viscol(PED_CTRL)) last_param = my_max(PED_CTRL - 1, last_param); else if (!viscol(PED_VOLUME1)) last_param = my_max(PED_VOLUME1 - 1, last_param); else if (!viscol(PED_INSTRUMENT1)) last_param = my_max(PED_INSTRUMENT1 - 1, last_param); switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_RETURN: { if (e->key.keysym.mod & KMOD_CTRL) { Uint8 p = get_pattern_at(mused.current_sequencetrack, mused.current_sequencepos); add_sequence(mused.current_sequencetrack, mused.current_patternpos, p, 0); } else { if (mused.mode != EDITCLASSIC) change_mode(EDITSEQUENCE); else mused.focus = EDITSEQUENCE; mused.flags &= ~SHOW_LOGO; // hide logo when jumping to sequence mused.current_sequencepos = mused.current_patternpos; update_position_sliders(); } } break; case SDLK_LSHIFT: case SDLK_RSHIFT: begin_selection(mused.current_patternpos); break; case SDLK_END: case SDLK_PAGEDOWN: case SDLK_DOWN: { if (e->key.keysym.mod & KMOD_CTRL) { update_sequence_slider(mused.sequenceview_steps); } else { int steps = 1; if (e->key.keysym.sym == SDLK_PAGEDOWN) steps = steps * 16; if (get_current_pattern()) { if (e->key.keysym.sym == SDLK_END) steps = get_current_pattern()->num_steps - current_patternstep() - 1; if ((e->key.keysym.mod & KMOD_SHIFT) && get_current_pattern()) steps = my_min(steps, get_current_pattern()->num_steps - current_patternstep() - 1); } update_pattern_slider(steps); if (e->key.keysym.mod & KMOD_SHIFT) { select_range(mused.current_patternpos); } } } break; case SDLK_HOME: case SDLK_PAGEUP: case SDLK_UP: { if (e->key.keysym.mod & KMOD_CTRL) { update_sequence_slider(-mused.sequenceview_steps); } else { int steps = 1; if (e->key.keysym.sym == SDLK_PAGEUP) steps = steps * 16; if (e->key.keysym.sym == SDLK_HOME) steps = current_patternstep(); if (e->key.keysym.mod & KMOD_SHIFT) steps = my_min(steps, current_patternstep()); update_pattern_slider(-steps); if (e->key.keysym.mod & KMOD_SHIFT) { select_range(mused.current_patternpos); } } } break; case SDLK_INSERT: { if (!(mused.flags & EDIT_MODE)) break; if (get_current_step()) { snapshot(S_T_PATTERN); if ((e->key.keysym.mod & KMOD_ALT)) { resize_pattern(get_current_pattern(), get_current_pattern()->num_steps + 1); zero_step(&mused.song.pattern[current_pattern()].step[mused.song.pattern[current_pattern()].num_steps - 1]); break; } for (int i = mused.song.pattern[current_pattern()].num_steps-1; i >= current_patternstep() ; --i) memcpy(&mused.song.pattern[current_pattern()].step[i], &mused.song.pattern[current_pattern()].step[i-1], sizeof(mused.song.pattern[current_pattern()].step[0])); zero_step(&mused.song.pattern[current_pattern()].step[current_patternstep()]); } } break; case SDLK_BACKSPACE: case SDLK_DELETE: { if (!(mused.flags & EDIT_MODE)) break; if (get_current_step()) { if (e->key.keysym.sym == SDLK_BACKSPACE) { if (current_patternstep() > 0) update_pattern_slider(-1); else break; } snapshot(S_T_PATTERN); if ((e->key.keysym.mod & KMOD_ALT)) { if (mused.song.pattern[current_pattern()].num_steps > 1) resize_pattern(&mused.song.pattern[current_pattern()], mused.song.pattern[current_pattern()].num_steps - 1); if (current_patternstep() >= mused.song.pattern[current_pattern()].num_steps) --mused.current_patternpos; break; } if (!(mused.flags & DELETE_EMPTIES) || e->key.keysym.sym == SDLK_BACKSPACE) { for (int i = current_patternstep() ; i < mused.song.pattern[current_pattern()].num_steps ; ++i) memcpy(&mused.song.pattern[current_pattern()].step[i], &mused.song.pattern[current_pattern()].step[i+1], sizeof(mused.song.pattern[current_pattern()].step[0])); zero_step(&mused.song.pattern[current_pattern()].step[mused.song.pattern[current_pattern()].num_steps - 1]); if (current_patternstep() >= mused.song.pattern[current_pattern()].num_steps) --mused.current_patternpos; } else { if (e->key.keysym.mod & KMOD_SHIFT) { zero_step(&mused.song.pattern[current_pattern()].step[current_patternstep()]); } else { switch (mused.current_patternx) { case PED_NOTE: mused.song.pattern[current_pattern()].step[current_patternstep()].note = MUS_NOTE_NONE; mused.song.pattern[current_pattern()].step[current_patternstep()].instrument = MUS_NOTE_NO_INSTRUMENT; break; case PED_INSTRUMENT1: case PED_INSTRUMENT2: mused.song.pattern[current_pattern()].step[current_patternstep()].instrument = MUS_NOTE_NO_INSTRUMENT; break; case PED_VOLUME1: case PED_VOLUME2: mused.song.pattern[current_pattern()].step[current_patternstep()].volume = MUS_NOTE_NO_VOLUME; break; case PED_LEGATO: case PED_SLIDE: case PED_VIB: mused.song.pattern[current_pattern()].step[current_patternstep()].ctrl = 0; break; case PED_COMMAND1: case PED_COMMAND2: case PED_COMMAND3: case PED_COMMAND4: mused.song.pattern[current_pattern()].step[current_patternstep()].command = 0; break; } } update_pattern_slider(mused.note_jump); } } } break; case SDLK_RIGHT: { if (e->key.keysym.mod & KMOD_CTRL) { int x = mused.current_patternx; switch_track(+1); if (e->key.keysym.mod & KMOD_SHIFT) mused.current_patternx = x; } else { ++mused.current_patternx; if (!viscol(mused.current_patternx) && (mused.current_patternx == PED_INSTRUMENT1 || mused.current_patternx == PED_INSTRUMENT2)) mused.current_patternx = PED_VOLUME1; if (!viscol(mused.current_patternx) && (mused.current_patternx == PED_VOLUME1 || mused.current_patternx == PED_VOLUME2)) mused.current_patternx = PED_CTRL; if (!viscol(mused.current_patternx) && (mused.current_patternx >= PED_CTRL && mused.current_patternx < PED_COMMAND1)) mused.current_patternx = PED_COMMAND1; if (!viscol(mused.current_patternx) && (mused.current_patternx >= PED_COMMAND1 && mused.current_patternx <= PED_COMMAND4)) mused.current_patternx = PED_PARAMS; if (mused.current_patternx >= PED_PARAMS) { mused.current_patternx = 0; switch_track(+1); } } } break; case SDLK_LEFT: { if (e->key.keysym.mod & KMOD_CTRL) { int x = mused.current_patternx; switch_track(-1); if (e->key.keysym.mod & KMOD_SHIFT) mused.current_patternx = x; } else { --mused.current_patternx; if (mused.current_patternx < 0) { mused.current_patternx = PED_PARAMS - 1; switch_track(-1); } if (!viscol(mused.current_patternx) && (mused.current_patternx >= PED_COMMAND1 && mused.current_patternx <= PED_COMMAND4)) mused.current_patternx = PED_VIB; if (!viscol(mused.current_patternx) && (mused.current_patternx < PED_COMMAND1 && mused.current_patternx > PED_VOLUME2)) mused.current_patternx = PED_VOLUME2; if (!viscol(mused.current_patternx) && (mused.current_patternx == PED_VOLUME1 || mused.current_patternx == PED_VOLUME2)) mused.current_patternx = PED_INSTRUMENT2; if (!viscol(mused.current_patternx) && (mused.current_patternx == PED_INSTRUMENT1 || mused.current_patternx == PED_INSTRUMENT2)) mused.current_patternx = PED_NOTE; if (mused.current_patternx < 0) { if (mused.single_pattern_edit) { mused.current_patternx = 0; } else { mused.current_patternx = last_param; switch_track(-1); } } } } break; default: { if (e->key.keysym.sym == SDLK_SPACE) { if ((mused.flags & TOGGLE_EDIT_ON_STOP) || !(mused.flags & SONG_PLAYING)) mused.flags ^= EDIT_MODE; if (mused.flags & SONG_PLAYING) stop(0, 0, 0); play_the_jams(e->key.keysym.sym, -1, 1); } if (!(mused.flags & EDIT_MODE)) { /* still has to play a note */ if (mused.current_patternx == PED_NOTE) { play_the_jams(e->key.keysym.sym, mused.current_sequencetrack, 1); } break; } if (get_current_step()) { if (mused.current_patternx == PED_NOTE) { if (e->key.keysym.sym == SDLK_PERIOD) { mused.song.pattern[current_pattern()].step[current_patternstep()].note = MUS_NOTE_NONE; snapshot(S_T_PATTERN); update_pattern_slider(mused.note_jump); } else if (e->key.keysym.sym == SDLK_1) { mused.song.pattern[current_pattern()].step[current_patternstep()].note = MUS_NOTE_RELEASE; snapshot(S_T_PATTERN); update_pattern_slider(mused.note_jump); } else { int note = find_note(e->key.keysym.sym, mused.octave); if (note != -1) { play_the_jams(e->key.keysym.sym, mused.current_sequencetrack, 1); snapshot(S_T_PATTERN); mused.song.pattern[current_pattern()].step[current_patternstep()].note = note; mused.song.pattern[current_pattern()].step[current_patternstep()].instrument = mused.current_instrument; update_pattern_slider(mused.note_jump); } } } else if (mused.current_patternx == PED_INSTRUMENT1 || mused.current_patternx == PED_INSTRUMENT2) { if (e->key.keysym.sym == SDLK_PERIOD) { mused.song.pattern[current_pattern()].step[current_patternstep()].instrument = MUS_NOTE_NO_INSTRUMENT; snapshot(S_T_PATTERN); update_pattern_slider(mused.note_jump); } else if (gethex(e->key.keysym.sym) != -1) { if (mused.song.num_instruments > 0) { Uint8 inst = mused.song.pattern[current_pattern()].step[current_patternstep()].instrument; if ((inst == MUS_NOTE_NO_INSTRUMENT)) inst = 0; switch (mused.current_patternx) { case PED_INSTRUMENT1: inst = (inst & 0x0f) | ((gethex(e->key.keysym.sym) << 4) & 0xf0); break; case PED_INSTRUMENT2: inst = (inst & 0xf0) | gethex(e->key.keysym.sym); break; } if (inst > (mused.song.num_instruments-1)) inst = (mused.song.num_instruments-1); snapshot(S_T_PATTERN); mused.song.pattern[current_pattern()].step[current_patternstep()].instrument = inst; mused.current_instrument = inst % mused.song.num_instruments; } update_pattern_slider(mused.note_jump); } } else if (mused.current_patternx == PED_VOLUME1 || mused.current_patternx == PED_VOLUME2) { switch (e->key.keysym.sym) { case SDLK_PERIOD: snapshot(S_T_PATTERN); mused.song.pattern[current_pattern()].step[current_patternstep()].volume = MUS_NOTE_NO_VOLUME; update_pattern_slider(mused.note_jump); break; default: if (mused.current_patternx == PED_VOLUME1) { int cmd = 0; switch (e->key.keysym.sym) { case SDLK_u: cmd = MUS_NOTE_VOLUME_FADE_UP; break; case SDLK_d: cmd = MUS_NOTE_VOLUME_FADE_DN; break; case SDLK_p: cmd = MUS_NOTE_VOLUME_SET_PAN; break; case SDLK_l: cmd = MUS_NOTE_VOLUME_PAN_LEFT; break; case SDLK_r: cmd = MUS_NOTE_VOLUME_PAN_RIGHT; break; default: break; } snapshot(S_T_PATTERN); if (cmd != 0) { if (mused.song.pattern[current_pattern()].step[current_patternstep()].volume == MUS_NOTE_NO_VOLUME) mused.song.pattern[current_pattern()].step[current_patternstep()].volume = 0; if (mused.current_patternx == PED_VOLUME1) mused.song.pattern[current_pattern()].step[current_patternstep()].volume = (mused.song.pattern[current_pattern()].step[current_patternstep()].volume & 0xf) | cmd; update_pattern_slider(mused.note_jump); break; } } if (gethex(e->key.keysym.sym) != -1) { Uint8 vol = mused.song.pattern[current_pattern()].step[current_patternstep()].volume; if ((vol == MUS_NOTE_NO_VOLUME)) vol = 0; switch (mused.current_patternx) { case PED_VOLUME1: vol = (vol & 0x0f) | ((gethex(e->key.keysym.sym) << 4) & 0xf0); break; case PED_VOLUME2: vol = (vol & 0xf0) | gethex(e->key.keysym.sym); break; } snapshot(S_T_PATTERN); if ((vol & 0xf0) != MUS_NOTE_VOLUME_FADE_UP && (vol & 0xf0) != MUS_NOTE_VOLUME_FADE_DN && (vol & 0xf0) != MUS_NOTE_VOLUME_PAN_LEFT && (vol & 0xf0) != MUS_NOTE_VOLUME_PAN_RIGHT && (vol & 0xf0) != MUS_NOTE_VOLUME_SET_PAN) mused.song.pattern[current_pattern()].step[current_patternstep()].volume = my_min(MAX_VOLUME, vol); else mused.song.pattern[current_pattern()].step[current_patternstep()].volume = vol; update_pattern_slider(mused.note_jump); } break; } } else if (mused.current_patternx >= PED_COMMAND1 && mused.current_patternx <= PED_COMMAND4) { if (gethex(e->key.keysym.sym) != -1) { Uint16 inst = mused.song.pattern[current_pattern()].step[current_patternstep()].command; switch (mused.current_patternx) { case PED_COMMAND1: inst = (inst & 0x0fff) | ((gethex(e->key.keysym.sym) << 12) & 0xf000); break; case PED_COMMAND2: inst = (inst & 0xf0ff) | ((gethex(e->key.keysym.sym) << 8) & 0x0f00); break; case PED_COMMAND3: inst = (inst & 0xff0f) | ((gethex(e->key.keysym.sym) << 4) & 0x00f0); break; case PED_COMMAND4: inst = (inst & 0xfff0) | gethex(e->key.keysym.sym); break; } snapshot(S_T_PATTERN); mused.song.pattern[current_pattern()].step[current_patternstep()].command = validate_command(inst) & 0x7fff; update_pattern_slider(mused.note_jump); } } else if (mused.current_patternx >= PED_CTRL && mused.current_patternx < PED_COMMAND1) { if (e->key.keysym.sym == SDLK_PERIOD || e->key.keysym.sym == SDLK_0) { snapshot(S_T_PATTERN); mused.song.pattern[current_pattern()].step[current_patternstep()].ctrl &= ~(MUS_CTRL_BIT << (mused.current_patternx - PED_CTRL)); update_pattern_slider(mused.note_jump); } if (e->key.keysym.sym == SDLK_1) { snapshot(S_T_PATTERN); mused.song.pattern[current_pattern()].step[current_patternstep()].ctrl |= (MUS_CTRL_BIT << (mused.current_patternx - PED_CTRL)); update_pattern_slider(mused.note_jump); } } } } break; } break; case SDL_KEYUP: play_the_jams(e->key.keysym.sym, -1, 0); break; } } void edit_program_event(SDL_Event *e) { switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_LSHIFT: case SDLK_RSHIFT: begin_selection(mused.current_program_step); break; case SDLK_PERIOD: snapshot(S_T_INSTRUMENT); mused.song.instrument[mused.current_instrument].program[mused.current_program_step] = MUS_FX_NOP; break; case SDLK_SPACE: { snapshot(S_T_INSTRUMENT); if ((mused.song.instrument[mused.current_instrument].program[mused.current_program_step] & 0xf000) != 0xf000) mused.song.instrument[mused.current_instrument].program[mused.current_program_step] ^= 0x8000; } break; case SDLK_RETURN: { MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; Uint16 *param = &inst->program[mused.current_program_step]; *param = validate_command(*param); } break; case SDLK_PAGEDOWN: case SDLK_DOWN: { MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; Uint16 *param = &inst->program[mused.current_program_step]; *param = validate_command(*param); int steps = 1; if (e->key.keysym.sym == SDLK_PAGEDOWN) steps *= 16; slider_move_position(&mused.current_program_step, &mused.program_position, &mused.program_slider_param, steps); if (e->key.keysym.mod & KMOD_SHIFT) { select_range(mused.current_program_step); } } break; case SDLK_PAGEUP: case SDLK_UP: { MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; Uint16 *param = &inst->program[mused.current_program_step]; *param = validate_command(*param); int steps = 1; if (e->key.keysym.sym == SDLK_PAGEUP) steps *= 16; slider_move_position(&mused.current_program_step, &mused.program_position, &mused.program_slider_param, -steps); if (e->key.keysym.mod & KMOD_SHIFT) { select_range(mused.current_program_step); } } break; case SDLK_INSERT: { snapshot(S_T_INSTRUMENT); for (int i = MUS_PROG_LEN-1; i > mused.current_program_step ; --i) mused.song.instrument[mused.current_instrument].program[i] = mused.song.instrument[mused.current_instrument].program[i-1]; mused.song.instrument[mused.current_instrument].program[mused.current_program_step] = MUS_FX_NOP; } break; case SDLK_BACKSPACE: case SDLK_DELETE: { snapshot(S_T_INSTRUMENT); if (e->key.keysym.sym == SDLK_BACKSPACE) { if (mused.current_program_step > 0) slider_move_position(&mused.current_program_step, &mused.program_position, &mused.program_slider_param, -1); else break; } if (!(mused.flags & DELETE_EMPTIES) || e->key.keysym.sym == SDLK_BACKSPACE) { for (int i = mused.current_program_step ; i < MUS_PROG_LEN-1 ; ++i) mused.song.instrument[mused.current_instrument].program[i] = mused.song.instrument[mused.current_instrument].program[i+1]; mused.song.instrument[mused.current_instrument].program[MUS_PROG_LEN-1] = MUS_FX_NOP; } else { mused.song.instrument[mused.current_instrument].program[mused.current_program_step] = MUS_FX_NOP; ++mused.current_program_step; if (mused.current_program_step >= MUS_PROG_LEN) mused.current_program_step = MUS_PROG_LEN - 1; } } break; case SDLK_RIGHT: { clamp(mused.editpos,+1,0,3); } break; case SDLK_LEFT: { clamp(mused.editpos,-1,0,3); } break; default: { int v = gethex(e->key.keysym.sym); if (v != -1) { snapshot(S_T_INSTRUMENT); editparambox(v); } } break; } break; case SDL_KEYUP: play_the_jams(e->key.keysym.sym, -1, 0); break; } } void edit_text(SDL_Event *e) { int r = generic_edit_text(e, mused.edit_buffer, mused.edit_buffer_size, &mused.editpos); if (r == -1) { strcpy(mused.edit_buffer, mused.edit_backup_buffer); change_mode(mused.prev_mode); } else if (r == 1) { change_mode(mused.prev_mode); } } void set_room_size(int fx, int size, int vol, int dec) { snapshot(S_T_FX); int min_delay = 5; int ms = (CYDRVB_SIZE - min_delay) * size / 64; if (mused.fx_room_ticks) { ms = 1000 * size / 16 * mused.song.song_speed / mused.song.song_rate; min_delay = ms; } int low = CYDRVB_LOW_LIMIT + 300; // +30 dB for (int i = 0 ; i < CYDRVB_TAPS ;++i) { int p, g, e = 1; if (mused.fx_room_ticks) { p = i * ms + min_delay; g = low - low * pow(1.0 - (double)p / CYDRVB_SIZE, (double)dec / 3) * vol / 16; } else { p = rnd(i * ms / CYDRVB_TAPS, (i + 1) * ms / CYDRVB_TAPS) + min_delay; g = low - low * pow(1.0 - (double)p / ms, (double)dec / 3) * vol / 16; } if (p >= CYDRVB_SIZE) { p = CYDRVB_SIZE - 1; e = 0; } mused.song.fx[fx].rvb.tap[i].delay = p; mused.song.fx[fx].rvb.tap[i].gain = g; mused.song.fx[fx].rvb.tap[i].flags = e; } mus_set_fx(&mused.mus, &mused.song); } void fx_add_param(int d) { if (d < 0) d = -1; else if (d > 0) d = 1; if (SDL_GetModState() & KMOD_SHIFT) { switch (mused.edit_reverb_param) { case R_DELAY: if (mused.flags & SHOW_DELAY_IN_TICKS) d *= (1000 / (float)mused.song.song_rate) * mused.song.song_speed; else d *= 100; break; default: d *= 10; break; } } snapshot_cascade(S_T_FX, mused.fx_bus, mused.edit_reverb_param); switch (mused.edit_reverb_param) { case R_FX_BUS: { clamp(mused.fx_bus, d, 0, CYD_MAX_FX_CHANNELS - 1); } break; case R_CRUSH: { flipbit(mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_CRUSH); } break; case R_CRUSHDITHER: { flipbit(mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_CRUSH_DITHER); } break; case R_CRUSHGAIN: { clamp(mused.song.fx[mused.fx_bus].crushex.gain, d, 0, 128); mus_set_fx(&mused.mus, &mused.song); } break; case R_CRUSHBITS: { clamp(mused.song.fx[mused.fx_bus].crush.bit_drop, d, 0, 15); mus_set_fx(&mused.mus, &mused.song); } break; case R_CRUSHDOWNSAMPLE: { clamp(mused.song.fx[mused.fx_bus].crushex.downsample, d, 0, 64); mus_set_fx(&mused.mus, &mused.song); } break; case R_CHORUS: { flipbit(mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_CHORUS); } break; case R_MINDELAY: { clamp(mused.song.fx[mused.fx_bus].chr.min_delay, d, 0, mused.song.fx[mused.fx_bus].chr.max_delay); clamp(mused.song.fx[mused.fx_bus].chr.min_delay, 0, mused.song.fx[mused.fx_bus].chr.min_delay, 255); } break; case R_MAXDELAY: { clamp(mused.song.fx[mused.fx_bus].chr.max_delay, d, mused.song.fx[mused.fx_bus].chr.min_delay, 255); clamp(mused.song.fx[mused.fx_bus].chr.min_delay, 0, 0, mused.song.fx[mused.fx_bus].chr.max_delay); } break; case R_SEPARATION: { clamp(mused.song.fx[mused.fx_bus].chr.sep, d, 0, 64); } break; case R_RATE: { clamp(mused.song.fx[mused.fx_bus].chr.rate, d, 0, 255); } break; case R_PITCH_INACCURACY: { clamp(mused.song.pitch_inaccuracy, d, 0, 12); } break; case R_MULTIPLEX: { flipbit(mused.song.fx[mused.fx_bus].flags, MUS_ENABLE_MULTIPLEX); } break; case R_MULTIPLEX_PERIOD: { clamp(mused.song.multiplex_period, d, 0, 255); } break; case R_ENABLE: { flipbit(mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_REVERB); } break; case R_ROOMSIZE: { clamp(mused.fx_room_size, d, 1, 64); } break; case R_ROOMDECAY: { clamp(mused.fx_room_dec, d, 1, 9); } break; case R_ROOMVOL: { clamp(mused.fx_room_vol, d, 1, 16); } break; case R_SNAPTICKS: { flipbit(mused.fx_room_ticks, 1); } break; case R_TAP: { clamp(mused.fx_tap, d, 0, CYDRVB_TAPS - 1); } break; case R_DELAY: { clamp(mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].delay, d * 1, 0, CYDRVB_SIZE - 1); mus_set_fx(&mused.mus, &mused.song); } break; case R_GAIN: { clamp(mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain, d * 1, CYDRVB_LOW_LIMIT, 0); mus_set_fx(&mused.mus, &mused.song); } break; case R_PANNING: { clamp(mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning, d * 8, CYD_PAN_LEFT, CYD_PAN_RIGHT); mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning &= ~7; mus_set_fx(&mused.mus, &mused.song); } break; case R_TAPENABLE: { flipbit(mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].flags, 1); } break; } } void fx_event(SDL_Event *e) { switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_DOWN: { ++mused.edit_reverb_param; if (mused.edit_reverb_param >= R_N_PARAMS) mused.edit_reverb_param = R_N_PARAMS - 1; } break; case SDLK_UP: { --mused.edit_reverb_param; if (mused.edit_reverb_param < 0) mused.edit_reverb_param = 0; } break; case SDLK_RIGHT: { fx_add_param(+1); } break; case SDLK_LEFT: { fx_add_param(-1); } break; default: play_the_jams(e->key.keysym.sym, -1, 1); break; } break; case SDL_KEYUP: play_the_jams(e->key.keysym.sym, -1, 0); break; } } void wave_add_param(int d) { CydWavetableEntry *w = &mused.mus.cyd->wavetable_entries[mused.selected_wavetable]; WgOsc *osc = &mused.wgset.chain[mused.selected_wg_osc]; if (d < 0) d = -1; else if (d > 0) d = 1; if (SDL_GetModState() & KMOD_SHIFT) { switch (mused.wavetable_param) { case W_BASE: d *= 12; break; case W_BASEFINE: d *= 16; break; default: d *= 256; break; } } snapshot_cascade(S_T_WAVE_PARAM, mused.selected_wavetable, mused.wavetable_param); switch (mused.wavetable_param) { case W_INTERPOLATE: { flipbit(w->flags, CYD_WAVE_NO_INTERPOLATION); } break; case W_WAVE: { clamp(mused.selected_wavetable, d, 0, CYD_WAVE_MAX_ENTRIES - 1); } break; case W_RATE: { clamp(w->sample_rate, d, 1, 192000); } break; case W_BASE: { clamp(w->base_note, d * 256, 0, (FREQ_TAB_SIZE - 1) * 256); } break; case W_BASEFINE: { clamp(w->base_note, d, 0, (FREQ_TAB_SIZE - 1) * 256); } break; case W_LOOP: { flipbit(w->flags, CYD_WAVE_LOOP); } break; case W_LOOPPINGPONG: { flipbit(w->flags, CYD_WAVE_PINGPONG); } break; case W_LOOPBEGIN: { clamp(w->loop_begin, d, 0, my_min(w->samples, w->loop_end)); clamp(w->loop_end, 0, w->loop_begin, w->samples); } break; case W_LOOPEND: { clamp(w->loop_end, d, w->loop_begin, w->samples); clamp(w->loop_begin, 0, 0, my_min(w->samples, w->loop_end)); } break; case W_NUMOSCS: { mused.wgset.num_oscs += d; if (mused.wgset.num_oscs < 1) mused.wgset.num_oscs = 1; else if (mused.wgset.num_oscs > WG_CHAIN_OSCS) mused.wgset.num_oscs = WG_CHAIN_OSCS; } break; case W_OSCTYPE: { osc->osc = my_max(0, my_min(WG_NUM_OSCS - 1, (int)osc->osc + d)); } break; case W_OSCMUL: { osc->mult = my_max(1, my_min(9, osc->mult + d)); } break; case W_OSCSHIFT: { osc->shift = my_max(0, my_min(7, osc->shift + d)); } break; case W_OSCEXP: { osc->exp += d * 5; if (osc->exp < 5) osc->exp = 5; else if (osc->exp > 95) osc->exp = 95; } break; case W_OSCABS: flipbit(osc->flags, WG_OSC_FLAG_ABS); break; case W_OSCNEG: flipbit(osc->flags, WG_OSC_FLAG_NEG); break; case W_WAVELENGTH: { mused.wgset.length = my_max(16, my_min(65536, mused.wgset.length + d)); } break; } } void wave_event(SDL_Event *e) { switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_DOWN: { ++mused.wavetable_param; if (!(mused.flags & SHOW_WAVEGEN) && mused.wavetable_param >= W_NUMOSCS && mused.wavetable_param <= W_TOOLBOX) { mused.wavetable_param = W_TOOLBOX + 1; } if (mused.wavetable_param >= W_N_PARAMS) mused.wavetable_param = W_N_PARAMS - 1; } break; case SDLK_UP: { --mused.wavetable_param; if (!(mused.flags & SHOW_WAVEGEN) && mused.wavetable_param >= W_NUMOSCS && mused.wavetable_param <= W_TOOLBOX) { mused.wavetable_param = W_NUMOSCS - 1; } if (mused.wavetable_param < 0) mused.wavetable_param = 0; } break; case SDLK_RIGHT: { wave_add_param(+1); } break; case SDLK_LEFT: { wave_add_param(-1); } break; default: wave_the_jams(e->key.keysym.sym); break; } break; } } void songinfo_add_param(int d) { if (d < 0) d = -1; else if (d > 0) d = 1; if (SDL_GetModState() & KMOD_SHIFT) d *= 16; if (d) snapshot_cascade(S_T_SONGINFO, mused.songinfo_param, -1); switch (mused.songinfo_param) { case SI_MASTERVOL: change_master_volume(MAKEPTR(d), 0, 0); break; case SI_LENGTH: change_song_length(MAKEPTR(d * mused.sequenceview_steps), 0, 0); break; case SI_LOOP: change_loop_point(MAKEPTR(d * mused.sequenceview_steps), 0, 0); break; case SI_STEP: change_seq_steps(MAKEPTR(d), 0, 0); break; case SI_SPEED1: change_song_speed(MAKEPTR(0), MAKEPTR(d), 0); break; case SI_SPEED2: change_song_speed(MAKEPTR(1), MAKEPTR(d), 0); break; case SI_RATE: change_song_rate(MAKEPTR(d), 0, 0); break; case SI_TIME: change_timesig(MAKEPTR(d), 0, 0); break; case SI_OCTAVE: change_octave(MAKEPTR(d), 0, 0); break; case SI_CHANNELS: change_channels(MAKEPTR(d), 0, 0); break; } } void songinfo_event(SDL_Event *e) { switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_DOWN: { ++mused.songinfo_param; if (mused.songinfo_param >= SI_N_PARAMS) mused.songinfo_param = SI_N_PARAMS - 1; } break; case SDLK_UP: { --mused.songinfo_param; if (mused.songinfo_param < 0) mused.songinfo_param = 0; } break; case SDLK_RIGHT: { songinfo_add_param(+1); } break; case SDLK_LEFT: { songinfo_add_param(-1); } break; default: break; } break; } } static int note_playing[MUS_MAX_CHANNELS] = {-1}; static int find_playing_note(int n) { cyd_lock(&mused.cyd, 1); for (int i = 0 ; i < MUS_MAX_CHANNELS && i < mused.cyd.n_channels ; ++i) { if (note_playing[i] == n && mused.mus.channel[i].instrument == &mused.song.instrument[mused.current_instrument]) { cyd_lock(&mused.cyd, 0); return i; } } cyd_lock(&mused.cyd, 0); return -1; } void note_event(SDL_Event *e) { switch (e->type) { case MSG_NOTEON: if (find_playing_note(e->user.code) == -1 && e->user.code < FREQ_TAB_SIZE) { int c = mus_trigger_instrument(&mused.mus, -1, &mused.song.instrument[mused.current_instrument], e->user.code << 8, CYD_PAN_CENTER); note_playing[c] = e->user.code; mused.mus.song_track[c].extarp1 = 0; mused.mus.song_track[c].extarp2 = 0; } break; case MSG_NOTEOFF: { int c; if ((c = find_playing_note(e->user.code)) != -1) { mus_release(&mused.mus, c); note_playing[c] = -1; } } break; case MSG_PROGRAMCHANGE: { if (e->user.code >= 0 && e->user.code < NUM_INSTRUMENTS) mused.current_instrument = e->user.code; } break; } } klystrack-0.20171212/klystrack/src/theme.c0000644000000000000000000003505013214501362016662 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "macros.h" #include "theme.h" #include #include "util/bundle.h" #include "gfx/gfx.h" #include "mused.h" #include "gui/menu.h" #include #include #include #include #include "action.h" #include "console.h" extern Mused mused; #define MAX_THEMES 64 Menu thememenu[MAX_THEMES + 1]; extern const Menu prefsmenu[]; Uint32 colors[NUM_COLORS]; static void load_colors(const char *cfg) { char *temp = strdup(cfg); char *token = strtok(temp, "\n"); while (token) { char name[51], from[51]; Uint32 color; static const char *names[NUM_COLORS] = { "sequence_counter", "sequence_normal", "pattern_selected", "pattern_bar", "pattern_beat", "pattern_instrument", "pattern_instrument_bar", "pattern_instrument_beat", "pattern_volume", "pattern_volume_bar", "pattern_volume_beat", "pattern_ctrl", "pattern_ctrl_bar", "pattern_ctrl_beat", "pattern_command", "pattern_command_bar", "pattern_command_beat", "pattern_normal", "pattern_disabled", "program_selected", "program_even", "program_odd", "instrument_selected", "instrument_normal", "menu", "menu_selected", "menu_header", "menu_header_selected", "menu_shortcut", "menu_shortcut_selected", "main_text", "small_text", "background", "button_text", "text_shadow", "pattern_empty_data", "wavetable_sample", "wavetable_background", "progress_bar", "pattern_seq_number", "catometer_eyes", "statusbar_text" }; if (sscanf(token, "%50[^ =]%*[ =]%x", name, &color) == 2) { int i; for (i = 0 ; i < NUM_COLORS ; ++i) { if (strcasecmp(names[i], name) == 0) { colors[i] = color; FIX_ENDIAN(colors[i]); #if SDL_BYTEORDER == SDL_BIG_ENDIAN // fix so that the color is in the 24 bits of RGB8 colors[i] = (colors[i] >> 8) | ((colors[i] & 0xff) << 24); #endif break; } } if (i >= NUM_COLORS) warning("Unknown color name '%s'", name); } else if (sscanf(token, "%50[^ =]%*[ =]%50s", name, from) == 2) { int from_i, to_i; for (from_i = 0 ; from_i < NUM_COLORS ; ++from_i) { if (strcasecmp(names[from_i], from) == 0) { break; } } if (from_i >= NUM_COLORS) warning("Unknown color name '%s'", name); else { for (to_i = 0 ; to_i < NUM_COLORS ; ++to_i) { if (strcasecmp(names[to_i], name) == 0) { colors[to_i] = color; break; } } if (to_i >= NUM_COLORS) warning("Unknown color name '%s'", name); else { debug("%s=%s", name, from); colors[to_i] = colors[from_i]; } } } token = strtok(NULL, "\n"); } free(temp); } int font_load_and_set_color(Font *font, Bundle *b, char *name, Uint32 color) { if (font_load(domain, font, b, name)) { font_set_color(font, color); return 1; } else { return 0; } } static SDL_RWops *load_img_if_exists(Bundle *res, const char *base_name) { /* load base_name.bmp or .png */ char name[100]; const char *ext[] = {"bmp", "png", NULL}, **e; for (e = ext ; *e ; ++e) { snprintf(name, sizeof(name), "%s.%s", base_name, *e); if (bnd_exists(res, name)) { SDL_RWops *rw = SDL_RWFromBundle(res, name); if (rw) return rw; } } return NULL; } static char cwd[1000] = ""; void init_resources_dir(void) { if (SDL_getenv("KLYSTRACK") == NULL) { #if RESOURCES_IN_BINARY_DIR strncpy(cwd, SDL_GetBasePath(), sizeof(cwd)); #else strncpy(cwd, TOSTRING(RES_PATH), sizeof(cwd)); #endif } else { strncpy(cwd, SDL_getenv("KLYSTRACK"), sizeof(cwd)); } } char * query_resource_directory(void) { return cwd; } void set_scaled_cursor() { if (mused.mouse_cursor_surface == NULL) return; if (mused.mouse_cursor) SDL_FreeCursor(mused.mouse_cursor); if (mused.flags & USE_SYSTEM_CURSOR) { mused.mouse_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); } else { // We'll use SDL_Renderer here because SDL_BlitScaled seems to have an issue with the alpha channel // Additionally, transparency on a zoomed cursor seems to make the cursor an "XOR" cursor so we need // to set the transparent color separately after SDL_Renderer has done its thing. SDL bug maybe? SDL_Surface *temp = SDL_CreateRGBSurface(0, mused.mouse_cursor_surface->surface->w * mused.pixel_scale, mused.mouse_cursor_surface->surface->h * mused.pixel_scale, 32, 0, 0, 0, 0); SDL_Renderer *renderer = SDL_CreateSoftwareRenderer(temp); SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, mused.mouse_cursor_surface->surface); // Draw the texture on a magic pink background SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255); SDL_RenderFillRect(renderer, NULL); SDL_RenderCopy(renderer, tex, NULL, NULL); SDL_DestroyTexture(tex); SDL_DestroyRenderer(renderer); // Make magic pink transparent SDL_SetColorKey(temp, SDL_TRUE, SDL_MapRGB(temp->format, 255, 0, 255)); mused.mouse_cursor = SDL_CreateColorCursor(temp, 0, 0); SDL_FreeSurface(temp); } if (mused.mouse_cursor) { SDL_SetCursor(mused.mouse_cursor); } else { warning("SDL_SetCursor failed: %s", SDL_GetError()); } } void set_app_icon() { SDL_SetWindowIcon(domain->window, mused.icon_surface->surface); } void load_theme(const char *name) { char tmpname[1000]; strncpy(tmpname, name, sizeof(tmpname)); if (strcmp(name, "Default") != 0) load_theme("Default"); // for default stuff not in selected theme Bundle res; char fullpath[1000]; snprintf(fullpath, sizeof(fullpath) - 1, "%s/res/%s", query_resource_directory(), tmpname); debug("Loading theme '%s'", fullpath); if (bnd_open(&res, fullpath)) { SDL_RWops *rw; rw = load_img_if_exists(&res, "bevel"); if (rw) { if (mused.slider_bevel) gfx_free_surface(mused.slider_bevel); mused.slider_bevel = gfx_load_surface_RW(domain, rw, GFX_KEYED); /* TODO: do we need to store the surface in the params? */ mused.sequence_slider_param.gfx = mused.slider_bevel; mused.pattern_slider_param.gfx = mused.slider_bevel; mused.program_slider_param.gfx = mused.slider_bevel; mused.instrument_list_slider_param.gfx = mused.slider_bevel; mused.pattern_horiz_slider_param.gfx = mused.slider_bevel; mused.sequence_horiz_slider_param.gfx = mused.slider_bevel; } rw = load_img_if_exists(&res, "vu"); if (rw) { if (mused.vu_meter) gfx_free_surface(mused.vu_meter); mused.vu_meter = gfx_load_surface_RW(domain, rw, GFX_KEYED); } rw = load_img_if_exists(&res, "analyzor"); if (rw) { if (mused.analyzer) gfx_free_surface(mused.analyzer); mused.analyzer = gfx_load_surface_RW(domain, rw, GFX_KEYED); } rw = load_img_if_exists(&res, "catometer"); if (rw) { if (mused.catometer) gfx_free_surface(mused.catometer); mused.catometer = gfx_load_surface_RW(domain, rw, GFX_KEYED); } rw = load_img_if_exists(&res, "cursor"); if (rw) { if (mused.mouse_cursor_surface) gfx_free_surface(mused.mouse_cursor_surface); if (mused.mouse_cursor) SDL_FreeCursor(mused.mouse_cursor); mused.mouse_cursor_surface = gfx_load_surface_RW(domain, rw, GFX_KEYED); set_scaled_cursor(); } rw = load_img_if_exists(&res, "icon"); if (rw) { if (mused.icon_surface) gfx_free_surface(mused.icon_surface); mused.icon_surface = gfx_load_surface_RW(domain, rw, 0); set_app_icon(); } rw = load_img_if_exists(&res, "logo"); if (rw) { if (mused.logo) gfx_free_surface(mused.logo); mused.logo = gfx_load_surface_RW(domain, rw, GFX_KEYED); } if (bnd_exists(&res, "colors.txt")) { SDL_RWops *colors = SDL_RWFromBundle(&res, "colors.txt"); if (colors) { SDL_RWseek(colors, 0, SEEK_END); size_t s = SDL_RWtell(colors); char *temp = calloc(1, s + 2); SDL_RWseek(colors, 0, SEEK_SET); SDL_RWread(colors, temp, 1, s); strcat(temp, "\n"); SDL_RWclose(colors); load_colors(temp); free(temp); } } if (bnd_exists(&res, "7x6.fnt")) { font_destroy(&mused.smallfont); font_load_and_set_color(&mused.smallfont, &res, "7x6.fnt", colors[COLOR_SMALL_TEXT]); font_destroy(&mused.shortcutfont); font_load_and_set_color(&mused.shortcutfont, &res, "7x6.fnt", colors[COLOR_MENU_SHORTCUT]); font_destroy(&mused.shortcutfont_selected); font_load_and_set_color(&mused.shortcutfont_selected, &res, "7x6.fnt", colors[COLOR_MENU_SHORTCUT_SELECTED]); font_destroy(&mused.headerfont); font_load_and_set_color(&mused.headerfont, &res, "7x6.fnt", colors[COLOR_MENU_HEADER]); font_destroy(&mused.headerfont_selected); font_load_and_set_color(&mused.headerfont_selected, &res, "7x6.fnt", colors[COLOR_MENU_HEADER_SELECTED]); font_destroy(&mused.buttonfont); font_load_and_set_color(&mused.buttonfont, &res, "7x6.fnt", colors[COLOR_BUTTON_TEXT]); } else { font_set_color(&mused.smallfont, colors[COLOR_SMALL_TEXT]); font_set_color(&mused.shortcutfont, colors[COLOR_MENU_SHORTCUT]); font_set_color(&mused.shortcutfont_selected, colors[COLOR_MENU_SHORTCUT_SELECTED]); font_set_color(&mused.headerfont, colors[COLOR_MENU_HEADER]); font_set_color(&mused.headerfont_selected, colors[COLOR_MENU_HEADER_SELECTED]); font_set_color(&mused.buttonfont, colors[COLOR_BUTTON_TEXT]); } if (bnd_exists(&res, "8x8.fnt")) { if (mused.console) console_destroy(mused.console); mused.console = console_create(&res); font_destroy(&mused.largefont); font_load_and_set_color(&mused.largefont, &res, "8x8.fnt", colors[COLOR_MAIN_TEXT]); font_destroy(&mused.menufont); font_load_and_set_color(&mused.menufont, &res, "8x8.fnt", colors[COLOR_MENU_NORMAL]); font_destroy(&mused.menufont_selected); font_load_and_set_color(&mused.menufont_selected, &res, "8x8.fnt", colors[COLOR_MENU_SELECTED]); } else { font_set_color(&mused.largefont, colors[COLOR_MAIN_TEXT]); font_set_color(&mused.menufont, colors[COLOR_MENU_NORMAL]); font_set_color(&mused.menufont_selected, colors[COLOR_MENU_SELECTED]); } if (bnd_exists(&res, "4x6.fnt")) { font_destroy(&mused.tinyfont); font_load_and_set_color(&mused.tinyfont, &res, "4x6.fnt", colors[COLOR_MAIN_TEXT]); font_destroy(&mused.tinyfont_sequence_counter); font_load_and_set_color(&mused.tinyfont_sequence_counter, &res, "4x6.fnt", colors[COLOR_SEQUENCE_COUNTER]); font_destroy(&mused.tinyfont_sequence_normal); font_load_and_set_color(&mused.tinyfont_sequence_normal, &res, "4x6.fnt", colors[COLOR_SEQUENCE_NORMAL]); } else { font_set_color(&mused.tinyfont, colors[COLOR_MAIN_TEXT]); font_set_color(&mused.tinyfont_sequence_counter, colors[COLOR_SEQUENCE_COUNTER]); font_set_color(&mused.tinyfont_sequence_normal, colors[COLOR_SEQUENCE_NORMAL]); } bnd_free(&res); strncpy(mused.themename, tmpname, sizeof(mused.themename)); update_theme_menu(); debug("Theme opened ok"); } else { warning("Theme loading failed"); if (strcmp(name, "Default") != 0) { load_theme("Default"); } else { char message[100]; snprintf(message, sizeof(message), "Default theme at '%s' could not be loaded.", fullpath); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Theme files missing", message, domain->window); fatal("Default theme at '%s' could not be loaded.", fullpath); exit(1); } } } void enum_themes() { memset(thememenu, 0, sizeof(thememenu)); char path[1000]; snprintf(path, sizeof(path) - 1, "%s/res", query_resource_directory()); DIR *dir = opendir(path); debug("Enumerating themes at %s", path); if (!dir) { warning("Could not enumerate themes at %s", path); return; } struct dirent *de = NULL; int themes = 0; while ((de = readdir(dir)) != NULL) { char fullpath[1000]; snprintf(fullpath, sizeof(fullpath) - 1, "%s/res/%s", query_resource_directory(), de->d_name); struct stat attribute; if (stat(fullpath, &attribute) != -1 && !(attribute.st_mode & S_IFDIR)) { if (themes >= MAX_THEMES) { warning("Maximum themes exceeded"); break; } thememenu[themes].parent = prefsmenu; thememenu[themes].text = strdup(de->d_name); thememenu[themes].action = load_theme_action; thememenu[themes].p1 = (void*)thememenu[themes].text; ++themes; } } debug("Got %d themes", themes); closedir(dir); } void update_theme_menu() { for (int i = 0 ; thememenu[i].text ; ++i) { if (strcmp(mused.themename, (char*)thememenu[i].p1) == 0) { thememenu[i].flags |= MENU_BULLET; } else thememenu[i].flags &= ~MENU_BULLET; } } void free_themes() { for (int i = 0 ; i < MAX_THEMES ; ++i) { if (thememenu[i].text != NULL) free((void*)thememenu[i].text); } memset(thememenu, 0, sizeof(thememenu)); } Uint32 mix_colors(Uint32 a, Uint32 b) { Sint32 ba = 255 - ((b >> 24) & 0xff); Sint32 ar = a & 0xff; Sint32 ag = (a >> 8) & 0xff; Sint32 ab = (a >> 16) & 0xff; Sint32 br = (b & 0xff) - ar; Sint32 bg = ((b >> 8) & 0xff) - ag; Sint32 bb = ((b >> 16) & 0xff) - ab; Uint32 fr = ar + br * ba / 256; Uint32 fg = ag + bg * ba / 256; Uint32 fb = ab + bb * ba / 256; return fr | (fg << 8) | (fb << 16); } klystrack-0.20171212/klystrack/src/midi.c0000644000000000000000000001532713214501362016507 0ustar rootroot#include "midi.h" #ifdef MIDI #include "mused.h" #include "mymsg.h" #define MAX_MIDI_DEVICES 32 extern Menu prefsmenu[]; Menu midi_menu[]; Menu midi_device_menu[MAX_MIDI_DEVICES + 1]; Menu midi_channel_menu[] = { { 0, midi_menu, "1", NULL, midi_set_channel, 0, 0, 0 }, { 0, midi_menu, "2", NULL, midi_set_channel, MAKEPTR(1), 0, 0 }, { 0, midi_menu, "3", NULL, midi_set_channel, MAKEPTR(2), 0, 0 }, { 0, midi_menu, "4", NULL, midi_set_channel, MAKEPTR(3), 0, 0 }, { 0, midi_menu, "5", NULL, midi_set_channel, MAKEPTR(4), 0, 0 }, { 0, midi_menu, "6", NULL, midi_set_channel, MAKEPTR(5), 0, 0 }, { 0, midi_menu, "7", NULL, midi_set_channel, MAKEPTR(6), 0, 0 }, { 0, midi_menu, "8", NULL, midi_set_channel, MAKEPTR(7), 0, 0 }, { 0, midi_menu, "9", NULL, midi_set_channel, MAKEPTR(8), 0, 0 }, { 0, midi_menu, "10", NULL, midi_set_channel, MAKEPTR(9), 0, 0 }, { 0, midi_menu, "11", NULL, midi_set_channel, MAKEPTR(10), 0, 0 }, { 0, midi_menu, "12", NULL, midi_set_channel, MAKEPTR(11), 0, 0 }, { 0, midi_menu, "13", NULL, midi_set_channel, MAKEPTR(12), 0, 0 }, { 0, midi_menu, "14", NULL, midi_set_channel, MAKEPTR(13), 0, 0 }, { 0, midi_menu, "15", NULL, midi_set_channel, MAKEPTR(14), 0, 0 }, { 0, midi_menu, "16", NULL, midi_set_channel, MAKEPTR(15), 0, 0 }, { 0, NULL, NULL } }; Menu midi_menu[] = { { 0, prefsmenu, "MIDI sync", NULL, MENU_CHECK, &mused.flags, (void*)MIDI_SYNC, 0 }, { 0, prefsmenu, "Device", midi_device_menu, NULL, 0, 0, 0 }, { 0, prefsmenu, "Channel", midi_channel_menu, NULL, 0, 0, 0 }, { 0, NULL, NULL } }; static char midi_device_names[MAX_MIDI_DEVICES][100]; static void midi_clock(Uint32 ms) { if (mused.tick_ctr == 0 && mused.midi_start) { mused.midi_last_clock = ms; } else if (mused.tick_ctr == 12) { mused.tick_ctr = 0; if (ms - mused.midi_last_clock) mused.midi_rate = 1000 / ((ms - mused.midi_last_clock) / 12); mused.midi_last_clock = ms; if (mused.midi_rate) { enable_callback(true); mused.song.song_rate = mused.midi_rate; } } if (mused.midi_start) { mused.flags |= SONG_PLAYING; } if (mused.mus.flags & MUS_EXT_SYNC) mus_ext_sync(&mused.mus); mused.midi_start = false; ++mused.tick_ctr; } static void midi_start() { debug("MIDI start"); mused.midi_start = true; mused.tick_ctr = 0; mus_set_song(&mused.mus, &mused.song, 0); mused.mus.flags |= MUS_EXT_SYNC; mused.mus.ext_sync_ticks = 0; if (mused.midi_rate) { enable_callback(true); mused.song.song_rate = mused.midi_rate; } } static void midi_stop() { debug("MIDI stop"); mused.midi_start = false; mused.flags &= ~SONG_PLAYING; mused.mus.flags &= ~MUS_EXT_SYNC; enable_callback(false); mus_set_song(&mused.mus, NULL, 0); } static void midi_continue() { debug("MIDI continue"); mused.midi_start = true; /*mused.tick_ctr = 0; mus_set_song(&mused.mus, &mused.song, mused.mus.song_position);*/ } static void midi_spp(Uint16 position) { debug("MIDI SPP (%d)", position); mus_set_song(&mused.mus, &mused.song, position); } static Uint16 midi_14bit(Uint8 first, Uint8 second) { return ((Uint16)(second & 0x7f) << 7) | ((Uint16)first & 0x7f); } #ifdef WIN32 #include #include static HMIDIIN hMidiIn = 0; static void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { if (MIM_DATA == wMsg) { if ((dwParam1 & 0xF0) != 0xf0) { Uint8 channel = dwParam1 & 0xf; if (channel == mused.midi_channel) { Uint8 command = dwParam1 & 0xf0; switch (command) { case 0x90: { SDL_Event e; e.type = MSG_NOTEON; e.user.code = (dwParam1 >> 8) & 0xff; e.user.data1 = MAKEPTR((dwParam1 >> 16) & 0xff); SDL_PushEvent(&e); } break; case 0x80: { SDL_Event e; e.type = MSG_NOTEOFF; e.user.code = (dwParam1 >> 8) & 0xff; e.user.data1 = MAKEPTR((dwParam1 >> 16) & 0xff); SDL_PushEvent(&e); } break; case 0xC0: { SDL_Event e; e.type = MSG_PROGRAMCHANGE; e.user.code = (dwParam1 >> 8) & 0xff; SDL_PushEvent(&e); } break; } } } else { if (MIDI_SYNC & mused.flags) { switch ((dwParam1 & 0xFF)) { case 0xF8: midi_clock(dwParam2); break; case 0xFA: { midi_start(); } break; case 0xFB: { midi_continue(); } break; case 0xFC: { midi_stop(); } break; case 0xF2: { midi_spp(midi_14bit((dwParam1 >> 8) & 0xff, (dwParam1 >> 16) & 0xff)); } break; } } } } } void midi_set_device(void *dev, void *unused1, void *unused2) { midi_deinit(); mused.midi_device = my_min(midiInGetNumDevs() - 1, CASTPTR(int, dev)); MMRESULT err = midiInOpen(&hMidiIn, mused.midi_device, (DWORD_PTR)MidiInProc, 0, CALLBACK_FUNCTION); if (MMSYSERR_NOERROR != err) { warning("midiInOpen returned %d", err); } else { midiInStart(hMidiIn); for (int i = 0, p = 0 ; p < MAX_MIDI_DEVICES && i < midiInGetNumDevs() ; ++i, ++p) { if (i == mused.midi_device) midi_device_menu[p].flags |= MENU_BULLET; else midi_device_menu[p].flags &= ~MENU_BULLET; } } } void midi_set_channel(void *chn, void *unused1, void *unused2) { mused.midi_channel = my_min(CASTPTR(int, chn), 15); for (int i = 0 ; i < 16 ; ++i) if (i == mused.midi_channel) midi_channel_menu[i].flags |= MENU_BULLET; else midi_channel_menu[i].flags &= ~MENU_BULLET; } void midi_init() { debug("MIDI initializing"); memset(midi_device_menu, 0, sizeof(midi_device_menu)); midi_set_channel(MAKEPTR(mused.midi_channel), 0, 0); if (midiInGetNumDevs() == 0) { midi_device_menu[0].parent = midi_menu; debug("No MIDI devices detected"); return; } for (int i = 0, p = 0 ; p < MAX_MIDI_DEVICES && i < midiInGetNumDevs() ; ++i) { MIDIINCAPS caps; if (MMSYSERR_NOERROR == midiInGetDevCaps(i, &caps, sizeof(caps))) { midi_device_menu[p].parent = midi_menu; strncpy(midi_device_names[p], caps.szPname, sizeof(midi_device_names[p])); midi_device_menu[p].text = midi_device_names[p]; midi_device_menu[p].action = midi_set_device; midi_device_menu[p].p1 = MAKEPTR(i); ++p; } } midi_set_device(MAKEPTR(mused.midi_device), 0, 0); } void midi_deinit() { if (hMidiIn) { midiInClose(hMidiIn); } hMidiIn = 0; } #else void midi_init(Uint32 uDeviceID) {} void midi_deinit() {} #endif // WIN32 #endif // MIDI klystrack-0.20171212/klystrack/src/help.h0000644000000000000000000000031313214501362016507 0ustar rootroot#ifndef HELP_H #define HELP_H #include "mused.h" #include "gfx/gfx.h" int helpbox(const char *title, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont); #endif klystrack-0.20171212/klystrack/src/wavegen.h0000644000000000000000000000146613214501362017225 0ustar rootroot#pragma once #include "SDL.h" #define WG_CHAIN_OSCS 4 typedef enum { WG_OSC_SINE, WG_OSC_SQUARE, WG_OSC_SAW, WG_OSC_TRIANGLE, WG_OSC_NOISE, WG_NUM_OSCS } WgOscType; typedef enum { WG_OP_ADD, WG_OP_MUL, WG_NUM_OPS } WgOpType; typedef struct { WgOscType osc; WgOpType op; int mult, shift; int exp; float exp_c; Uint32 flags; } WgOsc; enum { WG_OSC_FLAG_ABS = 1, WG_OSC_FLAG_NEG = 2 }; typedef struct { WgOsc chain[WG_CHAIN_OSCS]; int num_oscs, length; } WgSettings; typedef struct { const char *name; WgSettings settings; } WgPreset; void wg_gen_waveform(WgOsc *chain, int num_oscs, Sint16 *data, int len); float wg_osc(WgOsc *osc, float _phase); void wg_init_osc(WgOsc *osc); float wg_get_sample(WgOsc *chain, int num_oscs, float phase); klystrack-0.20171212/klystrack/src/undo.c0000644000000000000000000001577313214501362016537 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "undo.h" #include "macros.h" #include "mused.h" #include #include extern bool inside_undo; extern Mused mused; void undo_add_frame(UndoStack *stack, UndoFrame *frame) { frame->prev = *stack; *stack = frame; //debug("Added undo frame %p to %p", frame, stack); } static UndoEvent * get_frame(UndoType type, UndoStack *stack, bool modified) { if (inside_undo) return NULL; UndoFrame *frame = calloc(sizeof(UndoFrame), 1); undo_add_frame(stack, frame); frame->type = type; frame->modified = modified; /*#ifdef DEBUG undo_show_stack(stack); #endif */ return &frame->event; } void undo_destroy_frame(UndoFrame *frame) { switch (frame->type) { case UNDO_SEQUENCE: free(frame->event.sequence.seq); break; case UNDO_PATTERN: free(frame->event.pattern.step); break; case UNDO_WAVE_DATA: free(frame->event.wave_data.data); break; case UNDO_WAVE_NAME: free(frame->event.wave_name.name); break; default: break; } free(frame); } void undo_store_mode(UndoStack *stack, int old_mode, int focus, bool modified) { UndoEvent *frame = get_frame(UNDO_MODE, stack, modified); if (!frame) return; frame->mode.old_mode = old_mode; frame->mode.focus = focus; } void undo_store_instrument(UndoStack *stack, int idx, const MusInstrument *instrument, bool modified) { UndoEvent *frame = get_frame(UNDO_INSTRUMENT, stack, modified); if (!frame) return; frame->instrument.idx = idx; memcpy(&frame->instrument.instrument, instrument, sizeof(*instrument)); } void undo_store_pattern(UndoStack *stack, int idx, const MusPattern *pattern, bool modified) { UndoEvent *frame = get_frame(UNDO_PATTERN, stack, modified); if (!frame) return; frame->pattern.idx = idx; frame->pattern.n_steps = pattern->num_steps; frame->pattern.step = malloc(pattern->num_steps * sizeof(frame->pattern.step[0])); memcpy(frame->pattern.step, pattern->step, pattern->num_steps * sizeof(frame->pattern.step[0])); } void undo_store_sequence(UndoStack *stack, int channel, const MusSeqPattern *sequence, int n_seq, bool modified) { UndoEvent *frame = get_frame(UNDO_SEQUENCE, stack, modified); if (!frame) return; frame->sequence.channel = channel; frame->sequence.n_seq = n_seq; frame->sequence.seq = malloc(n_seq * sizeof(frame->sequence.seq[0])); memcpy(frame->sequence.seq, sequence, n_seq * sizeof(frame->sequence.seq[0])); } void undo_store_songinfo(UndoStack *stack, const MusSong *song, bool modified) { UndoEvent *frame = get_frame(UNDO_SONGINFO, stack, modified); if (!frame) return; frame->songinfo.song_length = song->song_length; frame->songinfo.loop_point = song->loop_point; frame->songinfo.sequence_step = mused.sequenceview_steps; frame->songinfo.song_speed = song->song_speed; frame->songinfo.song_speed2 = song->song_speed2; frame->songinfo.song_rate = song->song_rate; frame->songinfo.time_signature = song->time_signature; frame->songinfo.flags = song->flags; frame->songinfo.num_channels = song->num_channels; strcpy(frame->songinfo.title, song->title); frame->songinfo.master_volume = song->master_volume; memcpy(frame->songinfo.default_volume, song->default_volume, sizeof(frame->songinfo.default_volume)); memcpy(frame->songinfo.default_panning, song->default_panning, sizeof(frame->songinfo.default_panning)); } void undo_store_fx(UndoStack *stack, int idx, const CydFxSerialized *fx, Uint8 multiplex_period, bool modified) { UndoEvent *frame = get_frame(UNDO_FX, stack, modified); if (!frame) return; frame->fx.idx = idx; memcpy(&frame->fx.fx, fx, sizeof(*fx)); frame->fx.multiplex_period = multiplex_period; } void undo_init(UndoStack *stack) { *stack = NULL; } void undo_deinit(UndoStack *stack) { while (*stack) { UndoFrame *frame = *stack; *stack = frame->prev; undo_destroy_frame(frame); } *stack = NULL; } UndoFrame *undo(UndoStack *stack) { if (!*stack) return NULL; UndoFrame *frame = *stack; *stack = (*stack)->prev; return frame; } void undo_pop(UndoStack *stack) { UndoFrame *f = undo(stack); if (f) undo_destroy_frame(f); } #ifdef DEBUG void undo_show_stack(UndoStack *stack) { UndoFrame *frame = *stack; printf("%p [", stack); while (frame) { printf(" %d ", frame->type); frame = frame->prev; } printf("]\n"); } #endif void undo_store_wave_data(UndoStack *stack, int idx, const CydWavetableEntry *entry, bool modified) { UndoEvent *frame = get_frame(UNDO_WAVE_DATA, stack, modified); if (!frame) return; frame->wave_data.idx = idx; frame->wave_data.length = entry->samples; frame->wave_data.sample_rate = entry->sample_rate; frame->wave_data.samples = entry->samples; frame->wave_data.loop_begin = entry->loop_begin; frame->wave_data.loop_end = entry->loop_end; frame->wave_data.flags = entry->flags; frame->wave_data.base_note = entry->base_note; frame->wave_data.data = malloc(entry->samples * sizeof(entry->data[0])); memcpy(frame->wave_data.data, entry->data, entry->samples * sizeof(entry->data[0])); } void undo_store_wave_param(UndoStack *stack, int idx, const CydWavetableEntry *entry, bool modified) { UndoEvent *frame = get_frame(UNDO_WAVE_PARAM, stack, modified); if (!frame) return; frame->wave_param.idx = idx; frame->wave_param.flags = entry->flags; frame->wave_param.sample_rate = entry->sample_rate; frame->wave_param.samples = entry->samples; frame->wave_param.loop_begin = entry->loop_begin; frame->wave_param.loop_end = entry->loop_end; frame->wave_param.base_note = entry->base_note; } void undo_store_wave_name(UndoStack *stack, int idx, const char *name, bool modified) { UndoEvent *frame = get_frame(UNDO_WAVE_NAME, stack, modified); if (!frame) return; frame->wave_name.idx = idx; frame->wave_name.name = strdup(name); } klystrack-0.20171212/klystrack/src/keytab.h0000644000000000000000000000310713214501362017042 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #ifndef KEYTAB_H #define KEYTAB_H #include "SDL.h" typedef enum { KEYSYM, SCANCODE } KeyTranType; typedef struct { KeyTranType type; int focus; int from_mod; int from_key; int from_scancode; int to_mod; int to_key; int to_scancode; } KeyTran; typedef struct { const char *name; int key; } KeyDef; #define KEYDEF(key) {"K_"#key, SDLK_##key} #define MODDEF(key) {"M_"#key, KMOD_##key} extern const KeyDef keydefs[]; extern const KeyDef moddefs[]; #endif klystrack-0.20171212/klystrack/src/key.h0000644000000000000000000000237413214501362016360 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #ifndef KEY_H #define KEY_H #include "SDL.h" void translate_key_event(SDL_KeyboardEvent *e); void load_keymap(const char *name); void enum_keymaps(); #endif klystrack-0.20171212/klystrack/src/command.h0000644000000000000000000000303413214501362017200 0ustar rootroot#ifndef COMMAND_H #define COMMAND_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "SDL.h" #include typedef struct { Uint16 opcode; Uint16 mask; char *name, *shortname; int minv, maxv; } InstructionDesc; const InstructionDesc * get_instruction_desc(Uint16 command); bool is_valid_command(Uint16 command); void get_command_desc(char *text, size_t buffer_size, Uint16 inst); Uint16 validate_command(Uint16 command); const InstructionDesc* list_all_commands(); #endif klystrack-0.20171212/klystrack/src/version.in0000644000000000000000000000024613214501362017430 0ustar rootroot#ifndef VERSION_H #define VERSION_H #include "version_number.h" #define REVISION "r$WCREV$" #define VERSION_STRING "klystrack " VERSION " " REVISION #endif klystrack-0.20171212/klystrack/src/copypaste.c0000644000000000000000000002161013214501362017564 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "copypaste.h" #include "clipboard.h" #include "mused.h" #include "event.h" #define swap(a,b) { a ^= b; b ^= a; a ^= b; } extern Mused mused; void copy() { cp_clear(&mused.cp); switch (mused.focus) { case EDITPATTERN: if (mused.selection.start == mused.selection.end && get_current_pattern()) cp_copy_items(&mused.cp, CP_PATTERN, get_current_pattern()->step, sizeof(MusStep), get_current_pattern()->num_steps, mused.selection.start); else if (get_pattern(mused.selection.start, mused.current_sequencetrack) != -1) cp_copy_items(&mused.cp, CP_PATTERNSEGMENT, &mused.song.pattern[get_pattern(mused.selection.start, mused.current_sequencetrack)].step[get_patternstep(mused.selection.start, mused.current_sequencetrack)], sizeof(MusStep), mused.selection.end-mused.selection.start, mused.selection.start); break; case EDITINSTRUMENT: { cp_copy(&mused.cp, CP_INSTRUMENT, &mused.song.instrument[mused.current_instrument], sizeof(mused.song.instrument[mused.current_instrument]), 0); } break; case EDITPROG: { cp_copy_items(&mused.cp, CP_PROGRAM, &mused.song.instrument[mused.current_instrument].program[mused.selection.start], mused.selection.end-mused.selection.start, sizeof(mused.song.instrument[mused.current_instrument].program[0]), mused.selection.start); } break; case EDITSEQUENCE: { int first = -1, last = -1; for (int i = 0 ; i < mused.song.num_sequences[mused.current_sequencetrack] ; ++i) { if (first == -1 && mused.song.sequence[mused.current_sequencetrack][i].position >= mused.selection.start && mused.song.sequence[mused.current_sequencetrack][i].position < mused.selection.end) first = i; if (mused.song.sequence[mused.current_sequencetrack][i].position < mused.selection.end) last = i; } // Check if no items inside the selection if (first == -1 || first >= mused.song.num_sequences[mused.current_sequencetrack]) break; cp_copy_items(&mused.cp, CP_SEQUENCE, &mused.song.sequence[mused.current_sequencetrack][first], last-first+1, sizeof(mused.song.sequence[mused.current_sequencetrack][0]), mused.selection.start); } break; } } void cut() { copy(); delete(); } void delete() { switch (mused.focus) { case EDITPATTERN: snapshot(S_T_PATTERN); if (mused.selection.start == mused.selection.end) clear_pattern(&mused.song.pattern[current_pattern()]); else clear_pattern_range(&mused.song.pattern[get_pattern(mused.selection.start, mused.current_sequencetrack)], get_patternstep(mused.selection.start, mused.current_sequencetrack), get_patternstep(mused.selection.end, mused.current_sequencetrack)); break; case EDITSEQUENCE: snapshot(S_T_SEQUENCE); del_sequence(mused.selection.start, mused.selection.end, mused.current_sequencetrack); break; } mused.selection.start = mused.selection.end = 0; } void paste() { switch (mused.focus) { case EDITSEQUENCE: { if (mused.cp.type != CP_SEQUENCE) break; size_t items = cp_get_item_count(&mused.cp, sizeof(mused.song.sequence[0][0])); if (items < 1) break; snapshot(S_T_SEQUENCE); int first = ((MusSeqPattern*)mused.cp.data)[0].position; int last = ((MusSeqPattern*)mused.cp.data)[items-1].position; del_sequence(mused.current_sequencepos, last-first+mused.current_sequencepos, mused.current_sequencetrack); for (int i = 0 ; i < items ; ++i) { add_sequence(mused.current_sequencetrack, ((MusSeqPattern*)mused.cp.data)[i].position-mused.cp.position+mused.current_sequencepos, ((MusSeqPattern*)mused.cp.data)[i].pattern, ((MusSeqPattern*)mused.cp.data)[i].note_offset); } } break; case EDITPATTERN: { size_t items = cp_get_item_count(&mused.cp, sizeof(mused.song.pattern[current_pattern()].step[0])); if (items < 1) break; if (mused.cp.type == CP_PATTERN) { snapshot(S_T_PATTERN); resize_pattern(&mused.song.pattern[current_pattern()], items); cp_paste_items(&mused.cp, CP_PATTERN, mused.song.pattern[current_pattern()].step, items, sizeof(mused.song.pattern[current_pattern()].step[0])); } else if (mused.cp.type == CP_PATTERNSEGMENT && (current_pattern() != -1)) { debug("paste to pattern %d", current_pattern()); snapshot(S_T_PATTERN); cp_paste_items(&mused.cp, CP_PATTERNSEGMENT, &mused.song.pattern[current_pattern()].step[current_patternstep()], mused.song.pattern[current_pattern()].num_steps-current_patternstep(), sizeof(mused.song.pattern[current_pattern()].step[0])); } } break; case EDITINSTRUMENT: { if (mused.cp.type == CP_INSTRUMENT) { snapshot(S_T_INSTRUMENT); cp_paste_items(&mused.cp, CP_INSTRUMENT, &mused.song.instrument[mused.current_instrument], 1, sizeof(mused.song.instrument[mused.current_instrument])); } } break; case EDITPROG: { size_t items = cp_get_item_count(&mused.cp, sizeof(mused.song.instrument[mused.current_instrument].program[0])); if (items < 1) break; if (mused.cp.type == CP_PROGRAM) { snapshot(S_T_INSTRUMENT); cp_paste_items(&mused.cp, CP_PROGRAM, &mused.song.instrument[mused.current_instrument].program[mused.current_program_step], MUS_PROG_LEN - mused.current_program_step, sizeof(mused.song.instrument[mused.current_instrument].program[0])); } } break; } } void join_paste() { switch (mused.focus) { case EDITSEQUENCE: { if (mused.cp.type != CP_SEQUENCE) break; snapshot(S_T_SEQUENCE); size_t items = cp_get_item_count(&mused.cp, sizeof(mused.song.sequence[0][0])); if (items < 1) break; int first = ((MusSeqPattern*)mused.cp.data)[0].position; for (int i = 0 ; i < items ; ++i) { add_sequence(mused.current_sequencetrack, ((MusSeqPattern*)mused.cp.data)[i].position-first+mused.current_sequencepos, ((MusSeqPattern*)mused.cp.data)[i].pattern, ((MusSeqPattern*)mused.cp.data)[i].note_offset); } } break; case EDITPATTERN: { size_t items = cp_get_item_count(&mused.cp, sizeof(mused.song.pattern[0].step[0])); if (items < 1) break; if (mused.cp.type == CP_PATTERNSEGMENT || mused.cp.type == CP_PATTERN) { snapshot(S_T_PATTERN); int ofs; if (mused.cp.type == CP_PATTERN) ofs = 0; else ofs = current_patternstep(); for (int i = 0 ; i < items && i + ofs < mused.song.pattern[current_pattern()].num_steps ; ++i) { const MusStep *s = &((MusStep*)mused.cp.data)[i]; MusStep *d = &mused.song.pattern[current_pattern()].step[ofs + i]; if (s->note != MUS_NOTE_NONE) d->note = s->note; if (s->volume != MUS_NOTE_NO_VOLUME) d->volume = s->volume; if (s->instrument != MUS_NOTE_NO_INSTRUMENT) d->instrument = s->instrument; if (s->command != 0) d->command = s->command; if (s->ctrl != 0) d->ctrl = s->ctrl; } } } break; } } void begin_selection(int position) { //mused.selection.start = mused.selection.end; mused.selection.keydown = position; debug("Selected from %d", position); } void select_range(int position) { mused.selection.start = mused.selection.keydown; if (mused.selection.end == position) { int extra = 1; if (mused.focus == EDITSEQUENCE) extra = mused.sequenceview_steps; mused.selection.end = position + extra; // so we can select the last row (can't move the cursor one element after the last) } else mused.selection.end = position; if (mused.selection.end < mused.selection.start) { swap(mused.selection.start, mused.selection.end); } debug("Selected from %d-%d", mused.selection.start, mused.selection.end); } klystrack-0.20171212/klystrack/src/edit.h0000644000000000000000000000370713214501362016516 0ustar rootroot#ifndef EDIT_H #define EDIT_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "snd/music.h" typedef enum { S_T_PATTERN, S_T_SEQUENCE, S_T_MODE, S_T_SONGINFO, S_T_FX, S_T_WAVE_PARAM, S_T_WAVE_DATA, S_T_WAVE_NAME, S_T_INSTRUMENT } SHType; /* a, b = id for cascading snapshots */ void snapshot(SHType type); void snapshot_cascade(SHType type, int a, int b); void zero_step(MusStep *step); void clone_pattern(void *, void *, void *); void clone_each_pattern(void *, void *, void *); void get_unused_pattern(void*, void*, void*); void get_unused_pattern_all_tracks(void *, void *, void *); void expand_pattern(void *factor, void *, void *); void shrink_pattern(void *factor, void *, void *); void interpolate(void *, void *, void *); void transpose_note_data(void *semitones, void *unused1, void *unused2); void split_pattern(void *unused1, void *unused2, void *unused3); #endif klystrack-0.20171212/klystrack/src/wave.c0000644000000000000000000000630613214501362016524 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "wave.h" #include "macros.h" #include #include typedef struct { char ckID[4]; Uint32 cksize; } Chunk; Wave * wave_load(FILE *f) { struct { Chunk c; char WAVEID[4]; } __attribute__((__packed__)) RIFF; if (fread(&RIFF, 1 , sizeof(RIFF), f) != sizeof(RIFF) || strncmp(RIFF.c.ckID, "RIFF", 4) != 0 || strncmp(RIFF.WAVEID, "WAVE", 4) != 0) { fatal("Not a RIFF wave file"); return NULL; } struct { Chunk c; Uint16 wFormatTag; Uint16 nChannels; Uint32 nSamplesPerSec; Uint32 nAvgBytesPerSec; Uint16 nBlockAlign; Uint16 wBitsPerSample; /*----*/ Uint16 cbSize; /*----*/ Uint16 wValidBitsPerSample; Uint32 dwChannelMask; char SubFormat[16]; } __attribute__((__packed__)) WAVE; size_t beginning_of_WAVE = ftell(f); if (fread(&WAVE, 1 , sizeof(WAVE), f) < 16 || strncmp(WAVE.c.ckID, "fmt ", 4) != 0) { fatal("No 'fmt ' chunk found"); return NULL; } if (WAVE.wFormatTag != WAVE_FORMAT_PCM/* && WAVE.wFormatTag != WAVE_FORMAT_FLOAT*/) { //fatal("Only PCM and float supported"); fatal("Only PCM supported"); return NULL; } fseek(f, beginning_of_WAVE + WAVE.c.cksize + 8, SEEK_SET); Chunk peek = { "", 0 }; fread(&peek, 1, sizeof(peek) ,f); if (strncmp(peek.ckID, "fact", 4) == 0) { fseek(f, sizeof(Uint32), SEEK_CUR); } else { fseek(f, beginning_of_WAVE + WAVE.c.cksize + 8, SEEK_SET); } fread(&peek, 1, sizeof(peek) ,f); if (strncmp(peek.ckID, "data", 4) != 0) { fatal("No 'data' chunk found"); return NULL; } Wave *w = malloc(sizeof(*w)); w->format = WAVE.wFormatTag; w->channels = WAVE.nChannels; w->sample_rate = WAVE.nSamplesPerSec; w->length = peek.cksize / (WAVE.wBitsPerSample / 8) / WAVE.nChannels; w->bits_per_sample = WAVE.wBitsPerSample; w->data = malloc(peek.cksize); debug("Reading %d bytes (chn = %d, bits = %d)", peek.cksize, w->channels, w->bits_per_sample); fread(w->data, 1, peek.cksize, f); return w; } void wave_destroy(Wave *wave) { if (wave) { free(wave->data); free(wave); } } klystrack-0.20171212/klystrack/src/optimize.h0000644000000000000000000000334513214501362017427 0ustar rootroot#ifndef OPTIMIZE_H #define OPTIMIZE_H /* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "snd/music.h" #include void optimize_duplicate_patterns(MusSong *song); void optimize_song(MusSong *song); bool is_pattern_empty(const MusPattern *a); bool is_pattern_equal(const MusPattern *a, const MusPattern *b); bool is_instrument_used(const MusSong *song, int instrument); bool is_wavetable_used(const MusSong *song, int wavetable); void optimize_patterns_action(void *unused1, void *unused2, void *unused3); void optimize_instruments_action(void *unused1, void *unused2, void *unused3); void optimize_wavetables_action(void *unused1, void *unused2, void *unused3); #endif klystrack-0.20171212/klystrack/src/view.c0000644000000000000000000016600513214501362016537 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "view.h" #include "event.h" #include "mused.h" #include "action.h" #include "diskop.h" #include "gui/mouse.h" #include "gui/dialog.h" #include "gui/bevel.h" #include "theme.h" #include "mybevdefs.h" #include "snd/freqs.h" #include "view/visu.h" #include "view/sequence.h" #include #include "edit.h" #include "mymsg.h" #include "command.h" #include extern Mused mused; extern int event_hit; /* Cyd envelope length in milliseconds */ #define envelope_length(slope) (slope!=0?(float)(((slope) * (slope) * 256 / (ENVELOPE_SCALE * ENVELOPE_SCALE))) / ((float)CYD_BASE_FREQ / 1000.0f) :0.0f) float percent_to_dB(float percent) { return 10 * log10(percent); } bool is_selected_param(int focus, int p) { if (focus == mused.focus) switch (focus) { case EDITINSTRUMENT: return p == mused.selected_param; break; case EDITFX: return p == mused.edit_reverb_param; break; case EDITWAVETABLE: return p == mused.wavetable_param; break; case EDITSONGINFO: return p == mused.songinfo_param; break; } return false; } void my_separator(const SDL_Rect *parent, SDL_Rect *rect) { separator(domain, parent, rect, mused.slider_bevel, BEV_SEPARATOR); } // note: since we need to handle the focus this piece of code is duplicated from gui/view.c void my_draw_view(const View* views, const SDL_Event *_event, GfxDomain *domain) { gfx_rect(domain, NULL, colors[COLOR_BACKGROUND]); SDL_Event event; memcpy(&event, _event, sizeof(event)); int orig_focus = mused.focus; for (int i = 0 ; views[i].handler ; ++i) { const View *view = &views[i]; SDL_Rect area; area.x = view->position.x >= 0 ? view->position.x : domain->screen_w + view->position.x; area.y = view->position.y >= 0 ? view->position.y : domain->screen_h + view->position.y; area.w = *(Sint16*)&view->position.w > 0 ? *(Sint16*)&view->position.w : domain->screen_w + *(Sint16*)&view->position.w - view->position.x; area.h = *(Sint16*)&view->position.h > 0 ? *(Sint16*)&view->position.h : domain->screen_h + *(Sint16*)&view->position.h - view->position.y; memcpy(&mused.console->clip, &area, sizeof(view->position)); int iter = 0; do { event_hit = 0; view->handler(domain, &area, &event, view->param); if (event_hit) { event.type = MSG_EVENTHIT; if (view->focus != -1 && mused.focus != view->focus && orig_focus != EDITBUFFER && mused.focus != EDITBUFFER) { mused.focus = view->focus; clear_selection(0,0,0); } ++iter; } } while (event_hit && iter <= 1); if (!event_hit && event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT && event.button.x >= area.x && event.button.x < area.x + area.w && event.button.y >= area.y && event.button.y < area.y + area.h) { if (view->focus != -1 && mused.focus != view->focus) { if (orig_focus == EDITBUFFER) change_mode(view->focus); mused.focus = view->focus; clear_selection(0,0,0); } } } mused.cursor.w = (mused.cursor_target.w + mused.cursor.w * 2) / 3; mused.cursor.h = (mused.cursor_target.h + mused.cursor.h * 2) / 3; mused.cursor.x = (mused.cursor_target.x + mused.cursor.x * 2) / 3; mused.cursor.y = (mused.cursor_target.y + mused.cursor.y * 2) / 3; if (mused.cursor.w < mused.cursor_target.w) ++mused.cursor.w; if (mused.cursor.w > mused.cursor_target.w) --mused.cursor.w; if (mused.cursor.h < mused.cursor_target.h) ++mused.cursor.h; if (mused.cursor.h > mused.cursor_target.h) --mused.cursor.h; if (mused.cursor.x < mused.cursor_target.x) ++mused.cursor.x; if (mused.cursor.x > mused.cursor_target.x) --mused.cursor.x; if (mused.cursor.y < mused.cursor_target.y) ++mused.cursor.y; if (mused.cursor.y > mused.cursor_target.y) --mused.cursor.y; if (mused.cursor.w > 0) bevelex(domain, &mused.cursor, mused.slider_bevel, (mused.flags & EDIT_MODE) ? BEV_EDIT_CURSOR : BEV_CURSOR, BEV_F_STRETCH_ALL|BEV_F_DISABLE_CENTER); } char * notename(int note) { note = my_min(my_max(0, note), FREQ_TAB_SIZE - 1); static char buffer[4]; static const char * notename[] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; sprintf(buffer, "%s%d", notename[note % 12], note / 12); return buffer; } void label(const char *_label, const SDL_Rect *area) { SDL_Rect r; copy_rect(&r, area); r.y = r.y + area->h / 2 - mused.smallfont.h / 2; font_write(&mused.smallfont, domain, &r, _label); } void set_cursor(const SDL_Rect *location) { if (location == NULL) { mused.cursor_target.w = 0; mused.cursor.w = 0; return; } if (mused.flags & ANIMATE_CURSOR) { copy_rect(&mused.cursor_target, location); if (mused.cursor.w == 0 || mused.cursor.h == 0) copy_rect(&mused.cursor, location); } else { copy_rect(&mused.cursor_target, location); copy_rect(&mused.cursor, location); } } bool check_mouse_hit(const SDL_Event *e, const SDL_Rect *area, int focus, int param) { if (param < 0) return false; if (check_event(e, area, NULL, NULL, NULL, NULL)) { switch (focus) { case EDITINSTRUMENT: mused.selected_param = param; break; case EDITFX: mused.edit_reverb_param = param; break; case EDITWAVETABLE: mused.wavetable_param = param; break; case EDITSONGINFO: mused.songinfo_param = param; break; } mused.focus = focus; return true; } return false; } int generic_field(const SDL_Event *e, const SDL_Rect *area, int focus, int param, const char *_label, const char *format, void *value, int width) { label(_label, area); SDL_Rect field, spinner_area; copy_rect(&field, area); field.w = width * mused.console->font.w + 2; field.x = area->x + area->w - field.w; copy_rect(&spinner_area, &field); spinner_area.x += field.w; spinner_area.w = 16; field.x -= spinner_area.w; spinner_area.x -= spinner_area.w; bevelex(domain, &field, mused.slider_bevel, BEV_FIELD, BEV_F_STRETCH_ALL); adjust_rect(&field, 1); font_write_args(&mused.largefont, domain, &field, format, value); int r = spinner(domain, e, &spinner_area, mused.slider_bevel, (Uint32)area->x << 16 | area->y); check_mouse_hit(e, area, focus, param); if (is_selected_param(focus, param)) { SDL_Rect r; copy_rect(&r, area); adjust_rect(&r, -2); set_cursor(&r); } return r * (SDL_GetModState() & KMOD_SHIFT ? 16 : 1); } void generic_flags(const SDL_Event *e, const SDL_Rect *_area, int focus, int p, const char *label, Uint32 *_flags, Uint32 mask) { SDL_Rect area; copy_rect(&area, _area); area.y += 1; int hit = check_mouse_hit(e, _area, focus, p); Uint32 flags = *_flags; if (checkbox(domain, e, &area, mused.slider_bevel, &mused.smallfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_TICK, label, &flags, mask)) { } else if (hit) { // so that the gap between the box and label works too flags ^= mask; } if (*_flags != flags) { switch (focus) { case EDITINSTRUMENT: snapshot(S_T_INSTRUMENT); break; case EDITFX: snapshot(S_T_FX); break; } *_flags = flags; } if (is_selected_param(focus, p)) { SDL_Rect r; copy_rect(&r, &area); adjust_rect(&r, -2); r.h -= 2; r.w -= 2; set_cursor(&r); } } int generic_button(const SDL_Event *e, const SDL_Rect *area, int focus, int param, const char *_label, void (*action)(void*,void*,void*), void *p1, void *p2, void *p3) { if (is_selected_param(focus, param)) { SDL_Rect r; copy_rect(&r, area); adjust_rect(&r, -2); r.h -= 2; r.w -= 2; set_cursor(&r); } return button_text_event(domain, e, area, mused.slider_bevel, &mused.smallfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, _label, action, p1, p2, p3); } void songinfo1_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); area.w = my_min(320, area.w); adjust_rect(&area, 2); SDL_Rect r; copy_rect(&r, &area); r.w = 100-8; if (area.w > r.w) { r.w = area.w / (int)(area.w / r.w) - 5; } else { r.w = area.w; } r.h = 10; console_set_clip(mused.console, &area); int d; d = generic_field(event, &r, EDITSONGINFO, SI_LENGTH, "LEN", "%04X", MAKEPTR(mused.song.song_length), 4); songinfo_add_param(d); update_rect(&area, &r); d = generic_field(event, &r, EDITSONGINFO, SI_LOOP, "LOOP","%04X", MAKEPTR(mused.song.loop_point), 4); songinfo_add_param(d); update_rect(&area, &r); d = generic_field(event, &r, EDITSONGINFO, SI_STEP, "STEP","%04X", MAKEPTR(mused.sequenceview_steps), 4); songinfo_add_param(d); update_rect(&area, &r); } void songinfo2_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); area.w = my_min(320, area.w); adjust_rect(&area, 2); SDL_Rect r; copy_rect(&r, &area); r.w = 100-8; if (area.w > r.w) { r.w = area.w / (int)(area.w / r.w) - 5; } else { r.w = area.w; } r.h = 10; console_set_clip(mused.console, &area); char speedtext[10]; int d, tmp = r.w; r.w -= 26; d = generic_field(event, &r, EDITSONGINFO, SI_SPEED1, "SPD","%01X", MAKEPTR(mused.song.song_speed), 1); songinfo_add_param(d); r.x += r.w; r.w = 26; d = generic_field(event, &r, EDITSONGINFO, SI_SPEED2, "","%01X", MAKEPTR(mused.song.song_speed2), 1); songinfo_add_param(d); update_rect(&area, &r); r.w = tmp; d = generic_field(event, &r, EDITSONGINFO, SI_RATE, "RATE","%4d", MAKEPTR(mused.song.song_rate), 4); songinfo_add_param(d); update_rect(&area, &r); sprintf(speedtext, "%d/%d", mused.time_signature >> 8, mused.time_signature & 0xff); d = generic_field(event, &r, EDITSONGINFO, SI_TIME, "TIME","%4s", speedtext, 4); songinfo_add_param(d); update_rect(&area, &r); } void songinfo3_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); area.w = my_min(320, area.w); adjust_rect(&area, 2); SDL_Rect r; copy_rect(&r, &area); r.w = 100-8; if (area.w > r.w) { r.w = area.w / (int)(area.w / r.w) - 5; } else { r.w = area.w; } r.h = 10; console_set_clip(mused.console, &area); int d; d = generic_field(event, &r, EDITSONGINFO, SI_OCTAVE, "OCTAVE","%02X", MAKEPTR(mused.octave), 2); songinfo_add_param(d); update_rect(&area, &r); d = generic_field(event, &r, EDITSONGINFO, SI_CHANNELS, "CHANLS","%02X", MAKEPTR(mused.song.num_channels), 2); songinfo_add_param(d); update_rect(&area, &r); } void playstop_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); area.w = my_min(PLAYSTOP_INFO_W * 2, area.w); adjust_rect(&area, 2); area.x++; area.w -= 2; SDL_Rect r; copy_rect(&r, &area); r.w = area.w; r.h = 10; console_set_clip(mused.console, &area); SDL_Rect button; copy_rect(&button, &r); button.w = my_max(button.w / 2, PLAYSTOP_INFO_W/2 - 4); button_text_event(domain, event, &button, mused.slider_bevel, &mused.buttonfont, (mused.flags & SONG_PLAYING) ? BEV_BUTTON_ACTIVE : BEV_BUTTON, BEV_BUTTON_ACTIVE, "PLAY", play, NULL, NULL, NULL); button.x -= ELEMENT_MARGIN; update_rect(&area, &button); button_text_event(domain, event, &button, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "STOP", stop, NULL, NULL, NULL); r.y = button.y + button.h; int d; if (mused.mus.cyd->flags & CYD_CLIPPING) d = generic_field(event, &r, EDITSONGINFO, SI_MASTERVOL, "\2VOL","%02X", MAKEPTR(mused.song.master_volume), 2); else d = generic_field(event, &r, EDITSONGINFO, SI_MASTERVOL, "\1VOL","%02X", MAKEPTR(mused.song.master_volume), 2); songinfo_add_param(d); update_rect(&area, &r); } void info_line(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); area.w -= N_VIEWS * dest->h; console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 3); console_set_clip(mused.console, &area); console_set_color(mused.console, colors[COLOR_STATUSBAR_TEXT]); console_clear(mused.console); char text[200]=""; if (mused.info_message[0] != '\0') strncpy(text, mused.info_message, sizeof text); else { switch (mused.focus) { case EDITPROG: { Uint16 inst = mused.song.instrument[mused.current_instrument].program[mused.current_program_step]; get_command_desc(text, sizeof(text), inst); } break; case EDITWAVETABLE: { static const char * param_desc[] = { "Wavetable item", "Item name", "Sample rate", "Base note", "Base note finetune", "Interpolate", "Enable looping", "Loop begin", "Ping-pong looping", "Loop end", "Number of oscillators", "Oscillator type", "Frequency multiplier", "Phase shift", "Phase exponent", "Absolute", "Negative", "Wave length", "Randomize & generate", "Generate", "Randomize", "Toolbox" }; strcpy(text, param_desc[mused.wavetable_param]); } break; case EDITINSTRUMENT: { static const char * param_desc[] = { "Select instrument", "Edit instrument name", "Base note", "Finetune", "Lock to base note", "Drum", "Sync oscillator on keydown", "Reverse vibrato bit", "Set PW on keydown", "Set cutoff on keydown", "Slide speed", "Pulse wave", "Pulse width", "Saw wave", "Triangle wave", "Noise", "Metallic noise", "LFSR enable", "LFSR type", "Quarter frequency", "Wavetable", "Wavetable entry", "Override volume envelope for wavetable", "Lock wave to base note", "Volume", "Relative volume commands", "Envelope attack", "Envelope decay", "Envelope sustain", "Envelope release", "Buzz", "Buzz semi", "Buzz fine", "Buzz shape", "Sync channel", "Sync master channel", "Ring modulation", "Ring modulation source", "Enable filter", "Filter type", "Filter cutoff frequency", "Filter resonance", "Send signal to FX chain", "FX bus", "Vibrato speed", "Vibrato depth", "Vibrato shape", "Vibrato delay", "Pulse width modulation speed", "Pulse width modulation depth", "Pulse width modulation shape", "Program period", "Don't restart program on keydown", "Enable multi oscillator", "FM enable", "FM modulation", "FM feedback", "FM carrier multiplier", "FM modulator multiplier", "FM attack", "FM decay", "FM sustain", "FM release", "FM env start", "FM use wavetable", "FM wavetable entry" }; if (mused.selected_param == P_FXBUS) snprintf(text, sizeof(text) - 1, "%s (%s)", param_desc[mused.selected_param], mused.song.fx[mused.song.instrument[mused.current_instrument].fx_bus].name); else if (mused.selected_param == P_WAVE_ENTRY) snprintf(text, sizeof(text) - 1, "%s (%s)", param_desc[mused.selected_param], mused.song.wavetable_names[mused.song.instrument[mused.current_instrument].wavetable_entry]); else if (mused.selected_param == P_FM_WAVE_ENTRY) snprintf(text, sizeof(text) - 1, "%s (%s)", param_desc[mused.selected_param], mused.song.wavetable_names[mused.song.instrument[mused.current_instrument].fm_wave]); else if (mused.selected_param == P_VOLUME) snprintf(text, sizeof(text) - 1, "%s (%+.1f dB)", param_desc[mused.selected_param], percent_to_dB((float)mused.song.instrument[mused.current_instrument].volume / MAX_VOLUME)); else if (mused.selected_param == P_ATTACK) snprintf(text, sizeof(text) - 1, "%s (%.1f ms)", param_desc[mused.selected_param], envelope_length(mused.song.instrument[mused.current_instrument].adsr.a)); else if (mused.selected_param == P_DECAY) snprintf(text, sizeof(text) - 1, "%s (%.1f ms)", param_desc[mused.selected_param], envelope_length(mused.song.instrument[mused.current_instrument].adsr.d)); else if (mused.selected_param == P_RELEASE) snprintf(text, sizeof(text) - 1, "%s (%.1f ms)", param_desc[mused.selected_param], envelope_length(mused.song.instrument[mused.current_instrument].adsr.r)); else if (mused.selected_param == P_FM_ATTACK) snprintf(text, sizeof(text) - 1, "%s (%.1f ms)", param_desc[mused.selected_param], envelope_length(mused.song.instrument[mused.current_instrument].fm_adsr.a)); else if (mused.selected_param == P_FM_DECAY) snprintf(text, sizeof(text) - 1, "%s (%.1f ms)", param_desc[mused.selected_param], envelope_length(mused.song.instrument[mused.current_instrument].fm_adsr.d)); else if (mused.selected_param == P_FM_RELEASE) snprintf(text, sizeof(text) - 1, "%s (%.1f ms)", param_desc[mused.selected_param], envelope_length(mused.song.instrument[mused.current_instrument].fm_adsr.r)); else strcpy(text, param_desc[mused.selected_param]); } break; case EDITFX: { static const char * param_desc[] = { "Enable multiplex", "Multiplex period", "Pitch inaccuracy", "FX bus", "FX bus name", "Enable bitcrusher", "Drop bits", "Downsample", "Dither", "Crush gain", "Enable stereo chorus", "Min. delay", "Max. delay", "Phase separation", "Modulation frequency", "Enable reverb", "Room size", "Reverb volume", "Decay", "Tap enabled", "Selected tap", "Tap delay", "Tap gain", "Tap panning", }; strcpy(text, param_desc[mused.edit_reverb_param]); } break; case EDITPATTERN: if (get_current_pattern()) { if (mused.current_patternx >= PED_COMMAND1) { Uint16 inst = mused.song.pattern[current_pattern()].step[current_patternstep()].command; if (inst != 0) get_command_desc(text, sizeof(text), inst); else strcpy(text, "Command"); } else if (mused.current_patternx == PED_VOLUME1 || mused.current_patternx == PED_VOLUME2) { Uint16 vol = mused.song.pattern[current_pattern()].step[current_patternstep()].volume; if (vol != MUS_NOTE_NO_VOLUME && vol > MAX_VOLUME) { switch (vol & 0xf0) { case MUS_NOTE_VOLUME_FADE_UP: strcpy(text, "Fade volume up"); break; case MUS_NOTE_VOLUME_FADE_DN: strcpy(text, "Fade volume down"); break; case MUS_NOTE_VOLUME_PAN_LEFT: strcpy(text, "Pan left"); break; case MUS_NOTE_VOLUME_PAN_RIGHT: strcpy(text, "Pan right"); break; case MUS_NOTE_VOLUME_SET_PAN: strcpy(text, "Set panning"); break; } } else if (vol == MUS_NOTE_NO_VOLUME) strcpy(text, "Volume"); else sprintf(text, "Volume (%+.1f dB)", percent_to_dB((float)vol / MAX_VOLUME)); } else { static const char *pattern_txt[] = { "Note", "Instrument", "Instrument", "", "", "Legato", "Slide", "Vibrato" }; strcpy(text, pattern_txt[mused.current_patternx]); } } break; } } console_write(mused.console,text); SDL_Rect button = { dest->x + area.w + 6, dest->y, dest->h, dest->h }; for (int i = 0 ; i < N_VIEWS ; ++i) { button_event(domain, event, &button, mused.slider_bevel, (mused.mode != i) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, (mused.mode != i) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, DECAL_MODE_PATTERN + i + (mused.mode == i ? DECAL_MODE_PATTERN_SELECTED - DECAL_MODE_PATTERN : 0), (mused.mode != i) ? change_mode_action : NULL, (mused.mode != i) ? MAKEPTR(i) : 0, 0, 0); button.x += button.w; } } static void write_command(const SDL_Event *event, const char *text, int cmd_idx, int cur_idx) { int i = 0; for (const char *c = text ; *c ; ++c, ++i) { const SDL_Rect *r; check_event(event, r = console_write_args(mused.console, "%c", *c), select_program_step, MAKEPTR(cmd_idx), MAKEPTR(i), 0); if (mused.focus == EDITPROG && mused.editpos == i && cmd_idx == cur_idx) { SDL_Rect cur; copy_rect(&cur, r); adjust_rect(&cur, -2); set_cursor(&cur); } } } void program_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area, clip; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 2); copy_rect(&clip, &area); adjust_rect(&area, 1); area.w = 1000; console_set_clip(mused.console, &area); MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; //separator("----program-----"); int start = mused.program_position; int pos = 0, prev_pos = -1; int selection_begin = -1, selection_end = -1; for (int i = 0 ; i < start ; ++i) { prev_pos = pos; if (!(inst->program[i] & 0x8000) || (inst->program[i] & 0xf000) == 0xf000) ++pos; } gfx_domain_set_clip(domain, &clip); for (int i = start, s = 0, y = 0 ; i < MUS_PROG_LEN && y < area.h; ++i, ++s, y += mused.console->font.h) { SDL_Rect row = { area.x - 1, area.y + y - 1, area.w + 2, mused.console->font.h + 1}; if (mused.current_program_step == i && mused.focus == EDITPROG) { bevel(domain,&row, mused.slider_bevel, BEV_SELECTED_PATTERN_ROW); console_set_color(mused.console, colors[COLOR_PROGRAM_SELECTED]); } else console_set_color(mused.console,pos & 1 ? colors[COLOR_PROGRAM_ODD] : colors[COLOR_PROGRAM_EVEN]); if (i <= mused.selection.start) { selection_begin = row.y; } if (i < mused.selection.end) { selection_end = row.y + row.h + 1; } char box[6], cur = ' '; for (int c = 0 ; c < CYD_MAX_CHANNELS ; ++c) if (mused.channel[c].instrument == inst && (mused.cyd.channel[c].flags & CYD_CHN_ENABLE_GATE) && (mused.channel[c].flags & MUS_CHN_PROGRAM_RUNNING) && mused.channel[c].program_tick == i) cur = ''; if (inst->program[i] == MUS_FX_NOP) { strcpy(box, "...."); } else { sprintf(box, "%04X", ((inst->program[i] & 0xf000) != 0xf000) ? (inst->program[i] & 0x7fff) : inst->program[i]); } if (pos == prev_pos) { check_event(event, console_write_args(mused.console, "%02X%c ", i, cur), select_program_step, MAKEPTR(i), 0, 0); write_command(event, box, i, mused.current_program_step); check_event(event, console_write_args(mused.console, "%c ", (!(inst->program[i] & 0x8000) || (inst->program[i] & 0xf000) == 0xf000) ? '' : '|'), select_program_step, MAKEPTR(i), 0, 0); } else { check_event(event, console_write_args(mused.console, "%02X%c%02X ", i, cur, pos), select_program_step, MAKEPTR(i), 0, 0); write_command(event, box, i, mused.current_program_step); check_event(event, console_write_args(mused.console, "%c ", ((inst->program[i] & 0x8000) && (inst->program[i] & 0xf000) != 0xf000) ? '`' : ' '), select_program_step, MAKEPTR(i), 0, 0); } if (!is_valid_command(inst->program[i])) console_write_args(mused.console, "???"); else if ((inst->program[i] & 0x7f00) == MUS_FX_ARPEGGIO || (inst->program[i] & 0x7f00) == MUS_FX_ARPEGGIO_ABS) { if ((inst->program[i] & 0xff) != 0xf0 && (inst->program[i] & 0xff) != 0xf1) console_write_args(mused.console, "%s", notename(((inst->program[i] & 0x7f00) == MUS_FX_ARPEGGIO_ABS ? 0 : inst->base_note) + (inst->program[i] & 0xff))); else console_write_args(mused.console, "EXT%x", inst->program[i] & 0x0f); } else if (inst->program[i] != MUS_FX_NOP) { const InstructionDesc *d = get_instruction_desc(inst->program[i]); if (d) console_write(mused.console, d->shortname ? d->shortname : d->name); } console_write_args(mused.console, "\n"); if (row.y + row.h < area.y + area.h) slider_set_params(&mused.program_slider_param, 0, MUS_PROG_LEN - 1, start, i, &mused.program_position, 1, SLIDER_VERTICAL, mused.slider_bevel); prev_pos = pos; if (!(inst->program[i] & 0x8000) || (inst->program[i] & 0xf000) == 0xf000) ++pos; } if (mused.focus == EDITPROG && mused.selection.start != mused.selection.end && !(mused.selection.start > mused.program_slider_param.visible_last || mused.selection.end <= mused.program_slider_param.visible_first)) { if (selection_begin == -1) selection_begin = area.y - 8; if (selection_end == -1) selection_end = area.y + area.h + 8; if (selection_begin > selection_end) swap(selection_begin, selection_end); SDL_Rect selection = { area.x, selection_begin - 1, area.w, selection_end - selection_begin + 1 }; adjust_rect(&selection, -3); bevel(domain,&selection, mused.slider_bevel, BEV_SELECTION); } gfx_domain_set_clip(domain, NULL); if (mused.focus == EDITPROG) check_mouse_wheel_event(event, dest, &mused.program_slider_param); } static void inst_flags(const SDL_Event *e, const SDL_Rect *_area, int p, const char *label, Uint32 *flags, Uint32 mask) { generic_flags(e, _area, EDITINSTRUMENT, p, label, flags, mask); } static void inst_text(const SDL_Event *e, const SDL_Rect *area, int p, const char *_label, const char *format, void *value, int width) { //check_event(e, area, select_instrument_param, (void*)p, 0, 0); int d = generic_field(e, area, EDITINSTRUMENT, p, _label, format, value, width); if (d) { if (p >= 0) mused.selected_param = p; if (p != P_INSTRUMENT) snapshot_cascade(S_T_INSTRUMENT, mused.current_instrument, p); if (d < 0) instrument_add_param(-1); else if (d >0) instrument_add_param(1); } /*if (p == mused.selected_param && mused.focus == EDITINSTRUMENT) { SDL_Rect r; copy_rect(&r, area); adjust_rect(&r, -1); bevel(domain,&r, mused.slider_bevel, BEV_CURSOR); }*/ } void inst_field(const SDL_Event *e, const SDL_Rect *area, int p, int length, char *text) { console_set_color(mused.console,colors[COLOR_MAIN_TEXT]); console_set_clip(mused.console, area); console_clear(mused.console); bevelex(domain,area, mused.slider_bevel, BEV_FIELD, BEV_F_STRETCH_ALL); SDL_Rect field; copy_rect(&field, area); adjust_rect(&field, 1); console_set_clip(mused.console, &field); int got_pos = 0; if (mused.edit_buffer == text && mused.focus == EDITBUFFER && mused.selected_param == p) { int i = my_max(0, mused.editpos - field.w / mused.console->font.w + 1), c = 0; for ( ; text[i] && c < my_min(length, field.w / mused.console->font.w) ; ++i, ++c) { const SDL_Rect *r = console_write_args(mused.console, "%c", mused.editpos == i ? '' : text[i]); if (check_event(e, r, NULL, NULL, NULL, NULL)) { mused.editpos = i; got_pos = 1; } } if (mused.editpos == i && c <= length) console_write(mused.console, ""); } else { char temp[1000]; strncpy(temp, text, my_min(sizeof(temp), length)); temp[my_max(0, my_min(sizeof(temp), field.w / mused.console->font.w))] = '\0'; console_write_args(mused.console, "%s", temp); } int c = 1; if (!got_pos && (c = check_event(e, &field, select_instrument_param, MAKEPTR(p), 0, 0))) { if (mused.focus == EDITBUFFER && mused.edit_buffer == text) mused.editpos = strlen(text); else set_edit_buffer(text, length); if (text == mused.song.title) snapshot(S_T_SONGINFO); else if (text == mused.song.instrument[mused.current_instrument].name) snapshot(S_T_INSTRUMENT); else if (text == mused.song.wavetable_names[mused.selected_wavetable]) snapshot(S_T_WAVE_NAME); } if (!c && mused.focus == EDITBUFFER && e->type == SDL_MOUSEBUTTONDOWN) change_mode(mused.prev_mode); } void instrument_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect farea, larea, tarea; copy_rect(&farea,dest); copy_rect(&larea,dest); copy_rect(&tarea,dest); farea.w = 2 * mused.console->font.w + 2 + 16; if (!param) { larea.w = 0; } else { larea.w = 32; label("INST", &larea); } tarea.w = dest->w - farea.w - larea.w; farea.x = larea.w + dest->x; tarea.x = farea.x + farea.w; inst_text(event, &farea, P_INSTRUMENT, "", "%02X", MAKEPTR(mused.current_instrument), 2); inst_field(event, &tarea, P_NAME, sizeof(mused.song.instrument[mused.current_instrument].name), mused.song.instrument[mused.current_instrument].name); if (is_selected_param(EDITINSTRUMENT, P_NAME) || (mused.selected_param == P_NAME && mused.mode == EDITINSTRUMENT && (mused.edit_buffer == mused.song.instrument[mused.current_instrument].name && mused.focus == EDITBUFFER))) { SDL_Rect r; copy_rect(&r, &tarea); adjust_rect(&r, -2); set_cursor(&r); } } void instrument_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; SDL_Rect r, frame; copy_rect(&frame, dest); bevelex(domain,&frame, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&frame, 4); copy_rect(&r, &frame); r.w = r.w / 2 - 2; r.h = 10; r.y += r.h + 1; { SDL_Rect note; copy_rect(¬e, &frame); note.w = frame.w / 2 + 2; note.h = 10; inst_text(event, ¬e, P_BASENOTE, "BASE", "%s", notename(inst->base_note), 3); note.x += note.w + 2; note.w = frame.w / 3; inst_text(event, ¬e, P_FINETUNE, "", "%+4d", MAKEPTR(inst->finetune), 4); note.x += note.w + 2; note.w = frame.w - note.x; inst_flags(event, ¬e, P_LOCKNOTE, "L", &inst->flags, MUS_INST_LOCK_NOTE); inst_flags(event, &r, P_DRUM, "DRUM", &inst->flags, MUS_INST_DRUM); update_rect(&frame, &r); inst_flags(event, &r, P_KEYSYNC, "KSYNC", &inst->cydflags, CYD_CHN_ENABLE_KEY_SYNC); update_rect(&frame, &r); inst_flags(event, &r, P_INVVIB, "VIB", &inst->flags, MUS_INST_INVERT_VIBRATO_BIT); update_rect(&frame, &r); inst_flags(event, &r, P_SETPW, "SET PW", &inst->flags, MUS_INST_SET_PW); update_rect(&frame, &r); inst_flags(event, &r, P_SETCUTOFF, "SET CUT", &inst->flags, MUS_INST_SET_CUTOFF); update_rect(&frame, &r); inst_text(event, &r, P_SLIDESPEED, "SLIDE", "%02X", MAKEPTR(inst->slide_speed), 2); update_rect(&frame, &r); } { int tmp = r.w; r.w = frame.w / 3 - 2 - 12; my_separator(&frame, &r); inst_flags(event, &r, P_PULSE, "PUL", &inst->cydflags, CYD_CHN_ENABLE_PULSE); update_rect(&frame, &r); r.w = frame.w / 2 - 2 - 25; inst_text(event, &r, P_PW, "", "%03X", MAKEPTR(inst->pw), 3); update_rect(&frame, &r); r.w = frame.w / 3 - 8; inst_flags(event, &r, P_SAW, "SAW", &inst->cydflags, CYD_CHN_ENABLE_SAW); update_rect(&frame, &r); r.w = frame.w / 3 - 8; inst_flags(event, &r, P_TRIANGLE, "TRI", &inst->cydflags, CYD_CHN_ENABLE_TRIANGLE); update_rect(&frame, &r); inst_flags(event, &r, P_NOISE, "NOI", &inst->cydflags, CYD_CHN_ENABLE_NOISE); update_rect(&frame, &r); r.w = frame.w / 3; inst_flags(event, &r, P_METAL, "METAL", &inst->cydflags, CYD_CHN_ENABLE_METAL); update_rect(&frame, &r); inst_flags(event, &r, P_LFSR, "POKEY", &inst->cydflags, CYD_CHN_ENABLE_LFSR); update_rect(&frame, &r); r.w = frame.w / 3 - 16; inst_text(event, &r, P_LFSRTYPE, "", "%X", MAKEPTR(inst->lfsr_type), 1); update_rect(&frame, &r); r.w = frame.w / 3 - 2; inst_flags(event, &r, P_1_4TH, "1/4TH", &inst->flags, MUS_INST_QUARTER_FREQ); update_rect(&frame, &r); r.w = tmp; } { my_separator(&frame, &r); int tmp = r.w; r.w = 42; inst_flags(event, &r, P_WAVE, "WAVE", &inst->cydflags, CYD_CHN_ENABLE_WAVE); r.x += 44; r.w = 32; inst_text(event, &r, P_WAVE_ENTRY, "", "%02X", MAKEPTR(inst->wavetable_entry), 2); update_rect(&frame, &r); r.w = 42; inst_flags(event, &r, P_WAVE_OVERRIDE_ENV, "OENV", &inst->cydflags, CYD_CHN_WAVE_OVERRIDE_ENV); r.x += r.w; r.w = 20; inst_flags(event, &r, P_WAVE_LOCK_NOTE, "L", &inst->flags, MUS_INST_WAVE_LOCK_NOTE); update_rect(&frame, &r); r.w = tmp; } my_separator(&frame, &r); inst_text(event, &r, P_VOLUME, "VOL", "%02X", MAKEPTR(inst->volume), 2); update_rect(&frame, &r); inst_flags(event, &r, P_RELVOL, "RELATIVE", &inst->flags, MUS_INST_RELATIVE_VOLUME); update_rect(&frame, &r); inst_text(event, &r, P_ATTACK, "ATK", "%02X", MAKEPTR(inst->adsr.a), 2); update_rect(&frame, &r); inst_text(event, &r, P_DECAY, "DEC", "%02X", MAKEPTR(inst->adsr.d), 2); update_rect(&frame, &r); inst_text(event, &r, P_SUSTAIN, "SUS", "%02X", MAKEPTR(inst->adsr.s), 2); update_rect(&frame, &r); inst_text(event, &r, P_RELEASE, "REL", "%02X", MAKEPTR(inst->adsr.r), 2); update_rect(&frame, &r); { my_separator(&frame, &r); int tmp = r.w; r.w = frame.w / 3 + 8; inst_flags(event, &r, P_BUZZ, "BUZZ", &inst->flags, MUS_INST_YM_BUZZ); r.x += r.w + 2; r.w = frame.w - r.x + 4; inst_text(event, &r, P_BUZZ_SEMI, "DETUNE", "%+3d", MAKEPTR((inst->buzz_offset + 0x80) >> 8), 3); update_rect(&frame, &r); r.w = frame.w / 2 - 8; inst_text(event, &r, P_BUZZ_SHAPE, "SHAPE", "%c", MAKEPTR(inst->ym_env_shape + 0xf0), 1); r.x += r.w + 2; r.w = frame.w - r.x + 4; inst_text(event, &r, P_BUZZ_FINE, "FINE", "%+4d", MAKEPTR((Sint8)(inst->buzz_offset & 0xff)), 4); update_rect(&frame, &r); r.w = tmp; } my_separator(&frame, &r); inst_flags(event, &r, P_SYNC, "SYNC", &inst->cydflags, CYD_CHN_ENABLE_SYNC); update_rect(&frame, &r); inst_text(event, &r, P_SYNCSRC, "SRC", "%02X", MAKEPTR(inst->sync_source), 2); update_rect(&frame, &r); inst_flags(event, &r, P_RINGMOD, "RING MOD", &inst->cydflags, CYD_CHN_ENABLE_RING_MODULATION); update_rect(&frame, &r); inst_text(event, &r, P_RINGMODSRC, "SRC", "%02X", MAKEPTR(inst->ring_mod), 2); update_rect(&frame, &r); static const char *flttype[] = { "LP", "HP", "BP" }; my_separator(&frame, &r); inst_flags(event, &r, P_FILTER, "FILTER", &inst->cydflags, CYD_CHN_ENABLE_FILTER); update_rect(&frame, &r); inst_text(event, &r, P_FLTTYPE, "TYPE", "%s", (char*)flttype[inst->flttype], 2); update_rect(&frame, &r); inst_text(event, &r, P_CUTOFF, "CUT", "%03X", MAKEPTR(inst->cutoff), 3); update_rect(&frame, &r); inst_text(event, &r, P_RESONANCE, "RES", "%1X", MAKEPTR(inst->resonance), 1); update_rect(&frame, &r); } void instrument_view2(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { MusInstrument *inst = &mused.song.instrument[mused.current_instrument]; SDL_Rect r, frame; copy_rect(&frame, dest); bevelex(domain,&frame, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&frame, 4); copy_rect(&r, &frame); r.w = r.w / 2 - 2; r.h = 10; inst_flags(event, &r, P_FX, "FX", &inst->cydflags, CYD_CHN_ENABLE_FX); update_rect(&frame, &r); inst_text(event, &r, P_FXBUS, "FXBUS", "%02X", MAKEPTR(inst->fx_bus), 2); update_rect(&frame, &r); inst_text(event, &r, P_VIBSPEED, "VIB.S", "%02X", MAKEPTR(inst->vibrato_speed), 2); update_rect(&frame, &r); inst_text(event, &r, P_VIBDEPTH, "VIB.D", "%02X", MAKEPTR(inst->vibrato_depth), 2); update_rect(&frame, &r); inst_text(event, &r, P_VIBSHAPE, "VIB.SH", "%c", MAKEPTR(inst->vib_shape + 0xf4), 1); update_rect(&frame, &r); inst_text(event, &r, P_VIBDELAY, "V.DEL", "%02X", MAKEPTR(inst->vib_delay), 2); update_rect(&frame, &r); inst_text(event, &r, P_PWMSPEED, "PWM.S", "%02X", MAKEPTR(inst->pwm_speed), 2); update_rect(&frame, &r); inst_text(event, &r, P_PWMDEPTH, "PWM.D", "%02X", MAKEPTR(inst->pwm_depth), 2); update_rect(&frame, &r); inst_text(event, &r, P_PWMSHAPE, "PWM.SH", "%c", MAKEPTR(inst->pwm_shape + 0xf4), 1); update_rect(&frame, &r); inst_text(event, &r, P_PROGPERIOD, "P.PRD", "%02X", MAKEPTR(inst->prog_period), 2); update_rect(&frame, &r); inst_flags(event, &r, P_NORESTART, "NO RESTART", &inst->flags, MUS_INST_NO_PROG_RESTART); update_rect(&frame, &r); inst_flags(event, &r, P_MULTIOSC, "MULTIOSC", &inst->flags, MUS_INST_MULTIOSC); update_rect(&frame, &r); my_separator(&frame, &r); inst_flags(event, &r, P_FM_ENABLE, "FM", &inst->cydflags, CYD_CHN_ENABLE_FM); update_rect(&frame, &r); inst_text(event, &r, P_FM_MODULATION, "VOL", "%02X", MAKEPTR(inst->fm_modulation), 2); update_rect(&frame, &r); inst_text(event, &r, P_FM_FEEDBACK, "FEEDBACK", "%01X", MAKEPTR(inst->fm_feedback), 1); update_rect(&frame, &r); int tmp = r.w; r.w -= 27; inst_text(event, &r, P_FM_HARMONIC_CARRIER, "MUL", "%01X", MAKEPTR(inst->fm_harmonic >> 4), 1); r.x += r.w + 11; r.w = 16; inst_text(event, &r, P_FM_HARMONIC_MODULATOR, "", "%01X", MAKEPTR(inst->fm_harmonic & 15), 1); update_rect(&frame, &r); r.w = tmp; inst_text(event, &r, P_FM_ATTACK, "ATK", "%02X", MAKEPTR(inst->fm_adsr.a), 2); update_rect(&frame, &r); inst_text(event, &r, P_FM_DECAY, "DEC", "%02X", MAKEPTR(inst->fm_adsr.d), 2); update_rect(&frame, &r); inst_text(event, &r, P_FM_SUSTAIN, "SUS", "%02X", MAKEPTR(inst->fm_adsr.s), 2); update_rect(&frame, &r); inst_text(event, &r, P_FM_RELEASE, "REL", "%02X", MAKEPTR(inst->fm_adsr.r), 2); update_rect(&frame, &r); inst_text(event, &r, P_FM_ENV_START, "E.START", "%02X", MAKEPTR(inst->fm_attack_start), 2); update_rect(&frame, &r); tmp = r.w; r.w = 42; inst_flags(event, &r, P_FM_WAVE, "WAVE", &inst->fm_flags, CYD_FM_ENABLE_WAVE); r.x += 44; r.w = 32; inst_text(event, &r, P_FM_WAVE_ENTRY, "", "%02X", MAKEPTR(inst->fm_wave), 2); update_rect(&frame, &r); } void instrument_list(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 3); console_set_clip(mused.console, &area); int y = area.y; //separator("----instruments----"); int start = mused.instrument_list_position; /*if (start > NUM_INSTRUMENTS - rows ) start = NUM_INSTRUMENTS - rows; if (start < 0 ) start = 0;*/ for (int i = start ; i < NUM_INSTRUMENTS && y < area.h + area.y ; ++i, y += mused.console->font.h) { SDL_Rect row = { area.x - 1, y - 1, area.w + 2, mused.console->font.h + 1}; if (i == mused.current_instrument) { bevel(domain,&row, mused.slider_bevel, BEV_SELECTED_PATTERN_ROW); console_set_color(mused.console, colors[COLOR_INSTRUMENT_SELECTED]); } else { console_set_color(mused.console, colors[COLOR_INSTRUMENT_NORMAL]); } char temp[sizeof(mused.song.instrument[i].name) + 1]; strcpy(temp, mused.song.instrument[i].name); temp[my_min(sizeof(mused.song.instrument[i].name), my_max(0, area.w / mused.console->font.w - 3))] = '\0'; console_write_args(mused.console, "%02X %-16s\n", i, temp); check_event(event, &row, select_instrument, MAKEPTR(i), 0, 0); slider_set_params(&mused.instrument_list_slider_param, 0, NUM_INSTRUMENTS - 1, start, i, &mused.instrument_list_position, 1, SLIDER_VERTICAL, mused.slider_bevel); } if (mused.focus == EDITINSTRUMENT) check_mouse_wheel_event(event, dest, &mused.instrument_list_slider_param); } static void fx_text(const SDL_Event *e, const SDL_Rect *area, int p, const char *_label, const char *format, void *value, int width) { //check_event(e, area, select_instrument_param, (void*)p, 0, 0); int d = generic_field(e, area, EDITFX, p, _label, format, value, width); if (d) { if (p >= 0) mused.selected_param = p; if (p != R_FX_BUS) snapshot_cascade(S_T_FX, mused.fx_bus, p); if (d < 0) mused.fx_bus = my_max(0, mused.fx_bus - 1); else if (d >0) mused.fx_bus = my_min(CYD_MAX_FX_CHANNELS -1, mused.fx_bus + 1); } /*if (p == mused.selected_param && mused.focus == EDITINSTRUMENT) { SDL_Rect r; copy_rect(&r, area); adjust_rect(&r, -1); bevel(domain,&r, mused.slider_bevel, BEV_CURSOR); }*/ } void fx_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect farea, larea, tarea; copy_rect(&farea,dest); copy_rect(&larea,dest); copy_rect(&tarea,dest); farea.w = 2 * mused.console->font.w + 2 + 16; larea.w = 16; label("FX", &larea); tarea.w = dest->w - farea.w - larea.w - 1; farea.x = larea.w + dest->x; tarea.x = farea.x + farea.w; fx_text(event, &farea, R_FX_BUS, "FX", "%02X", MAKEPTR(mused.fx_bus), 2); inst_field(event, &tarea, R_FX_BUS_NAME, sizeof(mused.song.fx[mused.fx_bus].name), mused.song.fx[mused.fx_bus].name); if (is_selected_param(EDITFX, R_FX_BUS_NAME) || (mused.mode == EDITFX && (mused.edit_buffer == mused.song.fx[mused.fx_bus].name && mused.focus == EDITBUFFER))) { SDL_Rect r; copy_rect(&r, &tarea); adjust_rect(&r, -2); set_cursor(&r); } } void fx_global_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&area, 2); console_set_clip(mused.console, &area); SDL_Rect r; copy_rect(&r, &area); r.x += 2; r.h = 10; r.w = 96; generic_flags(event, &r, EDITFX, R_MULTIPLEX, "MULTIPLEX", &mused.song.flags, MUS_ENABLE_MULTIPLEX); update_rect(&area, &r); int d; r.x = 100; r.w = 80; if ((d = generic_field(event, &r, EDITFX, R_MULTIPLEX_PERIOD, "PERIOD", "%2X", MAKEPTR(mused.song.multiplex_period), 2))) { mused.edit_reverb_param = R_MULTIPLEX_PERIOD; fx_add_param(d); } update_rect(&area, &r); r.x += 8; r.w = 120; if ((d = generic_field(event, &r, EDITFX, R_PITCH_INACCURACY, "INACCURACY", "%2d", MAKEPTR(mused.song.pitch_inaccuracy), 2))) { mused.edit_reverb_param = R_PITCH_INACCURACY; fx_add_param(d); } } void fx_reverb_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain, &area, mused.slider_bevel, BEV_THIN_FRAME, BEV_F_STRETCH_ALL); adjust_rect(&area, 4); console_set_clip(mused.console, &area); int c = 0; int row_ms = (1000 / mused.song.song_rate) * mused.song.song_speed; int row_ms2 = (1000 / mused.song.song_rate) * mused.song.song_speed2; for (int ms = 0 ; ms < CYDRVB_SIZE ; c++) { SDL_Rect r = { area.x + ms * area.w / CYDRVB_SIZE, area.y, 1, area.h}; if (ms > 0) { Uint32 color = timesig(c, colors[COLOR_PATTERN_BAR], colors[COLOR_PATTERN_BEAT], colors[COLOR_PATTERN_NORMAL]); gfx_rect(dest_surface, &r, color); } if (timesig(c, 1, 1, 0)) { SDL_Rect text = { r.x + 2, r.y + r.h - mused.smallfont.h, 16, mused.smallfont.h}; font_write_args(&mused.smallfont, domain, &text, "%d", c); } if (c & 1) ms += row_ms2; else ms += row_ms; } c = 0; if (mused.fx_axis == 0) { for (int db = 0 ; db < -CYDRVB_LOW_LIMIT ; db += 100, c++) { Uint32 color = colors[COLOR_PATTERN_BAR]; if (c & 1) color = colors[COLOR_PATTERN_BEAT]; SDL_Rect r = { area.x, area.y + db * area.h / -CYDRVB_LOW_LIMIT, area.w, 1}; if (!(c & 1)) { SDL_Rect text = { r.x + r.w - 40, r.y + 2, 40, 8}; font_write_args(&mused.smallfont, domain, &text, "%3d dB", -db / 10); } if (db != 0) gfx_rect(dest_surface, &r, color); } } else { for (int pan = CYD_PAN_LEFT ; pan < CYD_PAN_RIGHT ; pan += CYD_PAN_CENTER / 2, c++) { Uint32 color = colors[COLOR_PATTERN_BAR]; if (c & 1) color = colors[COLOR_PATTERN_BEAT]; SDL_Rect r = { area.x, area.y + pan * area.h / CYD_PAN_RIGHT, area.w, 1}; if (pan != 0) gfx_rect(dest_surface, &r, color); } { SDL_Rect text = { area.x + area.w - 6, area.y + 4, 8, 8}; font_write(&mused.smallfont, domain, &text, "L"); } { SDL_Rect text = { area.x + area.w - 6, area.y + area.h - 16, 8, 8}; font_write(&mused.smallfont, domain, &text, "R"); } } for (int i = 0 ; i < CYDRVB_TAPS ; ++i) { int h; if (mused.fx_axis == 0) h = mused.song.fx[mused.fx_bus].rvb.tap[i].gain * area.h / CYDRVB_LOW_LIMIT; else h = mused.song.fx[mused.fx_bus].rvb.tap[i].panning * area.h / CYD_PAN_RIGHT; SDL_Rect r = { area.x + mused.song.fx[mused.fx_bus].rvb.tap[i].delay * area.w / CYDRVB_SIZE - mused.smallfont.w / 2, area.y + h - mused.smallfont.h / 2, mused.smallfont.w, mused.smallfont.h}; if (mused.song.fx[mused.fx_bus].rvb.tap[i].flags & 1) font_write(&mused.smallfont, dest_surface, &r, "\2"); else font_write(&mused.smallfont, dest_surface, &r, "\1"); if (i == mused.fx_tap) { SDL_Rect sel; copy_rect(&sel, &r); adjust_rect(&sel, -4); bevelex(domain, &sel, mused.slider_bevel, BEV_CURSOR, BEV_F_STRETCH_ALL); } if (event->type == SDL_MOUSEBUTTONDOWN) { if (check_event(event, &r, NULL, 0, 0, 0)) { mused.fx_tap = i; if (SDL_GetModState() & KMOD_SHIFT) { mused.song.fx[mused.fx_bus].rvb.tap[i].flags ^= 1; } } } } int mx, my; if (mused.mode == EDITFX && (SDL_GetMouseState(&mx, &my) & SDL_BUTTON(1))) { mx /= mused.pixel_scale; my /= mused.pixel_scale; if (mx >= area.x && mx < area.x + area.w && my > area.y && my < area.y + area.h) { if (mused.fx_room_prev_x != -1) { snapshot_cascade(S_T_FX, mused.fx_bus, mused.fx_tap); mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].delay += (mx - mused.fx_room_prev_x) * CYDRVB_SIZE / area.w; if (mused.fx_axis == 0) { mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain += (my - mused.fx_room_prev_y) * CYDRVB_LOW_LIMIT / area.h; if (mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain > 0) mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain = 0; else if (mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain < CYDRVB_LOW_LIMIT) mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain = CYDRVB_LOW_LIMIT; } else { mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning += (my - mused.fx_room_prev_y) * CYD_PAN_RIGHT / area.h; if (mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning < CYD_PAN_LEFT) mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning = CYD_PAN_LEFT; if (mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning > CYD_PAN_RIGHT) mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning = CYD_PAN_RIGHT; } } mused.fx_room_prev_x = mx; mused.fx_room_prev_y = my; } } else { mused.fx_room_prev_x = -1; mused.fx_room_prev_y = -1; } } void fx_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&area, 4); console_set_clip(mused.console, &area); SDL_Rect r; copy_rect(&r, &area); int d; r.h = 10; r.w = 48; generic_flags(event, &r, EDITFX, R_CRUSH, "CRUSH", &mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_CRUSH); update_rect(&area, &r); r.x = 56; r.w = 56; if ((d = generic_field(event, &r, EDITFX, R_CRUSHBITS, "BITS", "%01X", MAKEPTR(mused.song.fx[mused.fx_bus].crush.bit_drop), 1))) { fx_add_param(d); } update_rect(&area, &r); r.w = 64; if ((d = generic_field(event, &r, EDITFX, R_CRUSHDOWNSAMPLE, "DSMP", "%02d", MAKEPTR(mused.song.fx[mused.fx_bus].crushex.downsample), 2))) { fx_add_param(d); } update_rect(&area, &r); generic_flags(event, &r, EDITFX, R_CRUSHDITHER, "DITHER", &mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_CRUSH_DITHER); update_rect(&area, &r); r.w = 56; if ((d = generic_field(event, &r, EDITFX, R_CRUSHGAIN, "VOL", "%02X", MAKEPTR(mused.song.fx[mused.fx_bus].crushex.gain), 2))) { fx_add_param(d); } update_rect(&area, &r); my_separator(&area, &r); r.w = 60; generic_flags(event, &r, EDITFX, R_CHORUS, "STEREO", &mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_CHORUS); update_rect(&area, &r); { // hacky-hack, we need different addresses for the different fields // because the address of the string is used as an ad-hoc identifier for // the fields... char temp1[10], temp2[10], temp3[10]; sprintf(temp1, "%4.1f ms", (float)mused.song.fx[mused.fx_bus].chr.min_delay / 10); r.x = 100; r.w = 104; if ((d = generic_field(event, &r, EDITFX, R_MINDELAY, "MIN", temp1, NULL, 7))) { fx_add_param(d); } update_rect(&area, &r); sprintf(temp2, "%4.1f ms", (float)mused.song.fx[mused.fx_bus].chr.max_delay / 10); if ((d = generic_field(event, &r, EDITFX, R_MAXDELAY, "MAX", temp2, NULL, 7))) { fx_add_param(d); } r.x = 100; r.y += r.h; if ((d = generic_field(event, &r, EDITFX, R_SEPARATION, "PHASE", "%02X", MAKEPTR(mused.song.fx[mused.fx_bus].chr.sep), 2))) { fx_add_param(d); } update_rect(&area, &r); if (mused.song.fx[mused.fx_bus].chr.rate != 0) sprintf(temp3, "%5.2f Hz", (((float)(mused.song.fx[mused.fx_bus].chr.rate - 1) + 10) / 40)); else strcpy(temp3, "OFF"); if ((d = generic_field(event, &r, EDITFX, R_RATE, "MOD", temp3, NULL, 8))) { fx_add_param(d); } update_rect(&area, &r); } my_separator(&area, &r); generic_flags(event, &r, EDITFX, R_ENABLE, "REVERB", &mused.song.fx[mused.fx_bus].flags, CYDFX_ENABLE_REVERB); update_rect(&area, &r); r.w = 80; r.x = 4; r.y += r.h; { r.x = 130; r.y -= r.h; int tmp = r.w; r.w = 60 + 32; if ((d = generic_field(event, &r, EDITFX, R_ROOMSIZE, "ROOMSIZE", "%02X", MAKEPTR(mused.fx_room_size), 2))) { fx_add_param(d); } update_rect(&area, &r); r.w = 320 - 8 - r.x; if ((d = generic_field(event, &r, EDITFX, R_ROOMVOL, "VOLUME", "%02X", MAKEPTR(mused.fx_room_vol), 2))) { fx_add_param(d); } r.x = 130; r.y += r.h; r.w = 60+32; if ((d = generic_field(event, &r, EDITFX, R_ROOMDECAY, "DECAY", "%d", MAKEPTR(mused.fx_room_dec), 1))) { fx_add_param(d); } update_rect(&area, &r); r.w = 41; generic_flags(event, &r, EDITFX, R_SNAPTICKS, "SNAP", (Uint32*)&mused.fx_room_ticks, 1); update_rect(&area, &r); if (button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "SET", NULL, NULL, NULL, NULL) & 1) { set_room_size(mused.fx_bus, mused.fx_room_size, mused.fx_room_vol, mused.fx_room_dec); } update_rect(&area, &r); r.w = tmp; } { my_separator(&area, &r); char value[20]; int d; r.w = 32; r.h = 10; Uint32 _flags = mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].flags; generic_flags(event, &r, EDITFX, R_TAPENABLE, "TAP", &_flags, 1); mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].flags = _flags; update_rect(&area, &r); r.w = 32; if ((d = generic_field(event, &r, EDITFX, R_TAP, "", "%02d", MAKEPTR(mused.fx_tap), 2))) { fx_add_param(d); } update_rect(&area, &r); r.w = 80; if (mused.flags & SHOW_DELAY_IN_TICKS) { char tmp[10]; float ticks = (float)mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].delay / (1000 / (float)mused.song.song_rate); snprintf(tmp, sizeof(tmp), "%5.2f", ticks); d = generic_field(event, &r, EDITFX, R_DELAY, "", "%s t", tmp, 7); } else { d = generic_field(event, &r, EDITFX, R_DELAY, "", "%4d ms", MAKEPTR(mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].delay), 7); } if (d) { fx_add_param(d); } update_rect(&area, &r); r.w = 80; if (mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain <= CYDRVB_LOW_LIMIT) strcpy(value, "- INF"); else sprintf(value, "%+5.1f", (double)mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].gain * 0.1); if ((d = generic_field(event, &r, EDITFX, R_GAIN, "", "%s dB", value, 8))) { fx_add_param(d); } r.x += r.w + 4; r.w = 32; int panning = (int)mused.song.fx[mused.fx_bus].rvb.tap[mused.fx_tap].panning - CYD_PAN_CENTER; char tmp[10]; if (panning != 0) snprintf(tmp, sizeof(tmp), "%c%X", panning < 0 ? '\xf9' : '\xfa', panning == 63 ? 8 : ((abs((int)panning) >> 3) & 0xf)); else strcpy(tmp, "\xfa\xf9"); if ((d = generic_field(event, &r, EDITFX, R_PANNING, "", "%s", tmp, 2))) { fx_add_param(d); } r.x += r.w + 4; r.w = 32; if (button_text_event(domain, event, &r, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, mused.fx_axis == 0 ? "GAIN" : "PAN", NULL, NULL, NULL, NULL) & 1) { mused.fx_axis ^= 1; } r.y += r.h + 4; r.h = area.h - r.y + area.y; r.w = area.w; r.x = area.x; fx_reverb_view(dest_surface, &r, event, param); } mirror_flags(); } void instrument_disk_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect area; copy_rect(&area, dest); console_set_clip(mused.console, &area); console_clear(mused.console); bevelex(domain,&area, mused.slider_bevel, BEV_BACKGROUND, BEV_F_STRETCH_ALL); adjust_rect(&area, 2); SDL_Rect button = { area.x + 2, area.y, area.w / 2 - 4, area.h }; int open = button_text_event(domain, event, &button, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "LOAD", NULL, MAKEPTR(1), NULL, NULL); update_rect(&area, &button); int save = button_text_event(domain, event, &button, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "SAVE", NULL, MAKEPTR(2), NULL, NULL); update_rect(&area, &button); if (open & 1) open_data(param, MAKEPTR(OD_A_OPEN), 0); else if (save & 1) open_data(param, MAKEPTR(OD_A_SAVE), 0); } void song_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect larea, farea; copy_rect(&larea, dest); copy_rect(&farea, dest); larea.w = 32; farea.w -= larea.w; farea.x += larea.w; label("SONG", &larea); inst_field(event, &farea, 0, MUS_SONG_TITLE_LEN, mused.song.title); } void bevel_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { bevelex(domain,dest, mused.slider_bevel, CASTPTR(int,param), BEV_F_STRETCH_ALL); } void sequence_spectrum_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { if (mused.flags & SHOW_LOGO) { if (mused.logo != NULL) { SDL_Rect a; copy_rect(&a, dest); a.w += SCROLLBAR; gfx_rect(dest_surface, &a, colors[COLOR_BACKGROUND]); SDL_Rect d, s = {0,0,a.w,a.h}; gfx_domain_set_clip(domain, &a); copy_rect(&d, &a); d.x = d.w / 2 - mused.logo->surface->w / 2 + d.x; d.w = mused.logo->surface->w; s.w = mused.logo->surface->w; my_BlitSurface(mused.logo, &s, dest_surface, &d); gfx_domain_set_clip(domain, NULL); if (check_event(event, &a, NULL, NULL, NULL, NULL)) mused.flags &= ~SHOW_LOGO; } else { mused.flags &= ~SHOW_LOGO; } } else if (mused.flags & SHOW_ANALYZER) { SDL_Rect a; copy_rect(&a, dest); a.w += SCROLLBAR; gfx_domain_set_clip(dest_surface, &a); check_event(event, &a, toggle_visualizer, NULL, NULL, NULL); switch (mused.current_visualizer) { default: case VIS_SPECTRUM: spectrum_analyzer_view(dest_surface, &a, event, param); break; case VIS_CATOMETER: catometer_view(dest_surface, &a, event, param); break; } gfx_domain_set_clip(domain, NULL); } else { sequence_view2(dest_surface, dest, event, param); } } void toolbar_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param) { SDL_Rect button; copy_rect(&button, dest); button.w = dest->w - 3 * (dest->h + 2); button_text_event(domain, event, &button, mused.slider_bevel, &mused.buttonfont, BEV_BUTTON, BEV_BUTTON_ACTIVE, "MENU", open_menu_action, 0, 0, 0); button.x += button.w; button.w = button.h + 2; if (button_event(domain, event, &button, mused.slider_bevel, !(mused.flags & SHOW_ANALYZER) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, !(mused.flags & SHOW_ANALYZER) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, DECAL_TOOLBAR_VISUALIZATIONS, flip_bit_action, &mused.flags, MAKEPTR(SHOW_ANALYZER), 0)) mused.cursor.w = mused.cursor_target.w = 0; button.x += button.w; if (button_event(domain, event, &button, mused.slider_bevel, !(mused.flags & FULLSCREEN) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, !(mused.flags & FULLSCREEN) ? BEV_BUTTON : BEV_BUTTON_ACTIVE, DECAL_TOOLBAR_FULLSCREEN, NULL, 0, 0, 0)) { toggle_fullscreen(0,0,0); return; // dest_surface is now invalid } button.x += button.w; button_event(domain, event, &button, mused.slider_bevel, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_TOOLBAR_QUIT, quit_action, 0, 0, 0); button.x += button.w; } klystrack-0.20171212/klystrack/src/wave_action.h0000644000000000000000000000226413214501362020065 0ustar rootroot#ifndef __WAVE_ACTION_H #define __WAVE_ACTION_H void wavetable_drop_lowest_bit(void *unused1, void *unused2, void *unused3); void wavetable_halve_samplerate(void *unused1, void *unused2, void *unused3); void wavetable_normalize(void *vol, void *unused2, void *unused3); void wavetable_cut_tail(void *unused1, void *unused2, void *unused3); void wavetable_cut_head(void *unused1, void *unused2, void *unused3); void wavetable_chord(void *transpose, void *unused2, void *unused3); void wavetable_create_one_cycle(void *unused1, void *unused2, void *unused3); void wavetable_randomize_and_create_one_cycle(void *unused1, void *unused2, void *unused3); void wavegen_randomize(void *unused1, void *unused2, void *unused3); void wavegen_preset(void *_preset, void *_settings, void *unused3); void wavetable_draw(float x, float y, float w); void wavetable_amp(void *amp, void *unused2, void *unused3); void wavetable_distort(void *amp, void *unused2, void *unused3); void wavetable_remove_dc(void *unused1, void *unused2, void *unused3); void wavetable_filter(void *filter_type, void *unused2, void *unused3); void wavetable_find_zero(void *unused1, void *unused2, void *unused3); #endif klystrack-0.20171212/klystrack/src/view.h0000644000000000000000000001141013214501362016531 0ustar rootroot#ifndef VIEW_H #define VIEW_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (GfxDomain *dest_surface, 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. */ #include "gui/view.h" #define PLAYSTOP_INFO_W 78 #define SCROLLBAR 10 #define uppersig (Uint32)(mused.time_signature >> 8) #define lowersig (Uint32)(mused.time_signature & 0xff) #define compoundbeats (uppersig / 3) #define compounddivider (lowersig) #define simpletime(i, bar, beat, normal) ((((i) % (lowersig * uppersig) == 0) ? (bar) : ((i) % (lowersig) == 0) ? (beat) : (normal))) #define compoundtime(i, bar, beat, normal) (((i) % (compoundbeats * 16 * 3 / compounddivider) == 0) ? (bar) : ((i) % (16 * 3 / compounddivider) == 0 ? (beat) : (normal))) #define timesig(i, bar, beat, normal) (((uppersig != 3) && (uppersig % 3) == 0) ? compoundtime(i, bar, beat, normal) : simpletime(i, bar, beat, normal)) #define swap(a,b) { a ^= b; b ^= a; a ^= b; } void my_draw_view(const View* views, const SDL_Event *_event, GfxDomain *domain); int generic_field(const SDL_Event *e, const SDL_Rect *area, int focus, int param, const char *_label, const char *format, void *value, int width); void generic_flags(const SDL_Event *e, const SDL_Rect *_area, int focus, int p, const char *label, Uint32 *flags, Uint32 mask); int generic_button(const SDL_Event *e, const SDL_Rect *area, int focus, int param, const char *_label, void (*action)(void*,void*,void*), void *p1, void *p2, void *p3); char * notename(int note); void my_separator(const SDL_Rect *parent, SDL_Rect *rect); void set_cursor(const SDL_Rect *location); bool is_selected_param(int focus, int p); float percent_to_dB(float percent); /* "Controls" */ void song_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void instrument_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void instrument_disk_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void program_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void info_line(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void sequence_spectrum_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void pattern_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void songinfo1_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void songinfo2_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void songinfo3_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void playstop_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void instrument_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void instrument_view2(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void instrument_list(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void fx_name_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void fx_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void bevel_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void toolbar_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void fx_global_view(GfxDomain *dest_surface, const SDL_Rect *dest, const SDL_Event *event, void *param); void label(const char *_label, const SDL_Rect *area); void inst_field(const SDL_Event *e, const SDL_Rect *area, int p, int length, char *text); #endif klystrack-0.20171212/klystrack/src/mybevdefs.h0000644000000000000000000000374613214501362017560 0ustar rootroot#ifndef MYBEVDEFS_H #define MYBEVDEFS_H /* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "gui/bevdefs.h" enum { BEV_SELECTED_PATTERN_ROW = BEV_SELECTED_ROW, BEV_SEQUENCE_PLAY_POS = BEV_USER, BEV_BACKGROUND, BEV_SELECTED_SEQUENCE_ROW, BEV_SEQUENCE_BORDER, BEV_SEQUENCE_LOOP, BEV_THIN_FRAME, BEV_SELECTION, BEV_EDIT_CURSOR, BEV_PATTERN, BEV_PATTERN_CURRENT }; enum { DECAL_AUDIO_ENABLED = DECAL_USER, DECAL_AUDIO_DISABLED, DECAL_MODE_PATTERN, DECAL_MODE_SEQUENCE, DECAL_MODE_CLASSIC, DECAL_MODE_INSTRUMENT, DECAL_MODE_FX, DECAL_MODE_WAVETABLE, DECAL_MODE_PATTERN_SELECTED, DECAL_MODE_SEQUENCE_SELECTED, DECAL_MODE_CLASSIC_SELECTED, DECAL_MODE_INSTRUMENT_SELECTED, DECAL_MODE_FX_SELECTED, DECAL_MODE_WAVETABLE_SELECTED, DECAL_TOOLBAR_VISUALIZATIONS, DECAL_TOOLBAR_FULLSCREEN, DECAL_TOOLBAR_QUIT, DECAL_COMPACT, DECAL_COMPACT_SELETED, DECAL_FOCUS, DECAL_FOCUS_SELETED }; #endif klystrack-0.20171212/klystrack/src/key.c0000644000000000000000000001571613214501362016357 0ustar rootroot/* Copyright (c) 2009-2011 Tero Lindeman (kometbomb) 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. */ #include "key.h" #include "gui/menu.h" #include #include #include #include "action.h" #include "mused.h" #include "keytab.h" #include #include "theme.h" extern Mused mused; #define MAX_KEYMAPS 64 #define MAX_KEYTRANS 500 Menu keymapmenu[MAX_KEYMAPS + 1]; extern const Menu prefsmenu[]; static KeyTran keytrans[MAX_KEYTRANS]; void translate_key_event(SDL_KeyboardEvent *e) { const int allowed = KMOD_SHIFT|KMOD_CTRL|KMOD_ALT; for (int i = 0 ; i < MAX_KEYTRANS && !(keytrans[i].from_key == 0 && keytrans[i].from_mod == 0 && keytrans[i].from_scancode == 0) ; ++i) { if ((keytrans[i].focus == mused.focus || keytrans[i].focus == -1) && ((keytrans[i].type == KEYSYM && e->keysym.sym == keytrans[i].from_key) || (keytrans[i].type == SCANCODE && e->keysym.scancode == keytrans[i].from_scancode)) && ((e->keysym.mod & allowed) == keytrans[i].from_mod)) { e->keysym.sym = keytrans[i].to_key; e->keysym.mod = keytrans[i].to_mod; break; } } } void enum_keymaps() { memset(keymapmenu, 0, sizeof(keymapmenu)); // TODO: remove copypastecode and write enum_dir() function that takes a handler int maps = 0; keymapmenu[maps].parent = prefsmenu; keymapmenu[maps].text = strdup("Default"); keymapmenu[maps].action = load_keymap_action; keymapmenu[maps].p1 = (void*)keymapmenu[maps].text; ++maps; char path[1000]; snprintf(path, sizeof(path) - 1, "%s/key", query_resource_directory()); DIR *dir = opendir(path); debug("Enumerating keymaps at %s", path); if (!dir) { warning("Could not enumerate keymaps at %s", path); return; } struct dirent *de = NULL; while ((de = readdir(dir)) != NULL) { char fullpath[1000]; snprintf(fullpath, sizeof(fullpath) - 1, "%s/key/%s", query_resource_directory(), de->d_name); struct stat attribute; if (stat(fullpath, &attribute) != -1 && !(attribute.st_mode & S_IFDIR)) { if (maps >= MAX_KEYMAPS) { warning("Maximum keymaps exceeded"); break; } keymapmenu[maps].parent = prefsmenu; keymapmenu[maps].text = strdup(de->d_name); keymapmenu[maps].action = load_keymap_action; keymapmenu[maps].p1 = (void*)keymapmenu[maps].text; ++maps; } } debug("Got %d keymaps", maps); closedir(dir); } void update_keymap_menu() { for (int i = 0 ; keymapmenu[i].text ; ++i) { if (strcmp(mused.keymapname, (char*)keymapmenu[i].p1) == 0) { keymapmenu[i].flags |= MENU_BULLET; } else keymapmenu[i].flags &= ~MENU_BULLET; } } int parse_key(const char *keys, int *key, int *mod, int *scancode) { *mod = 0; *key = 0; if (scancode) *scancode = 0; char *temp = strdup(keys); int done = 0; char *tok = strtok(temp, " \t"); do { if (!tok) break; int found = 0; for (int i = 0 ; keydefs[i].name ; ++i) { if (strcasecmp(tok, keydefs[i].name) == 0) { if (*key != 0) { warning("More than one key (%s, was %d) specified", tok, *key); done = 1; } *key = keydefs[i].key; found = 1; break; } } for (int i = 0 ; moddefs[i].name ; ++i) { if (strcasecmp(tok, moddefs[i].name) == 0) { *mod |= moddefs[i].key; found = 1; break; } } if (scancode) { int _scancode = 0; if (sscanf(tok, "S_%x", &_scancode) == 1) { debug("Found scancode %x", _scancode); *scancode = _scancode; found = 1; } } if (!found && strlen(tok) > 0) { warning("Unknown token %s", tok); break; } tok = strtok(NULL, " \t"); } while (!done); free(temp); if (*key == 0) { warning("No keys specified"); *mod = 0; } return (*key != 0 || (scancode == NULL || *scancode != 0)); } int parse_keys(const char *from, const char *to, KeyTran *tran) { if (!parse_key(from, &tran->from_key, &tran->from_mod, &tran->from_scancode)) return 0; if (!parse_key(to, &tran->to_key, &tran->to_mod, NULL)) return 0; if (tran->from_scancode) tran->type = SCANCODE; else tran->type = KEYSYM; return 1; } void load_keymap(const char *name) { memset(keytrans, 0, sizeof(keytrans)); char tmpname[1000]; strncpy(tmpname, name, sizeof(tmpname)); if (strcmp(name, "Default") == 0) { strncpy(mused.keymapname, tmpname, sizeof(mused.themename)); update_keymap_menu(); return; } char fullpath[1000]; snprintf(fullpath, sizeof(fullpath) - 1, "%s/key/%s", query_resource_directory(), tmpname); strncpy(mused.keymapname, tmpname, sizeof(mused.themename)); update_keymap_menu(); debug("Loading keymap '%s'", fullpath); FILE *f = fopen(fullpath, "rt"); int trans = 0; if (f) { int lnr = 1; int focus = -1; do { char line[100], from[100], to[100]; if (trans >= MAX_KEYTRANS) { warning("Max keytrans exceeded\n"); break; } if (!fgets(line, sizeof(line) - 1, f)) break; if (line[0] == '#') continue; else if (sscanf(line, "%*[[]%64[^]]%*[]]", from) == 1) { if (strcasecmp(from, "global") == 0) { focus = -1; } else if (strcasecmp(from, "pattern") == 0) { focus = EDITPATTERN; } else if (strcasecmp(from, "sequence") == 0) { focus = EDITSEQUENCE; } else if (strcasecmp(from, "instrument") == 0) { focus = EDITINSTRUMENT; } else warning("Unknown GUI focus \"%s\" on line %d", from, lnr); } else if (sscanf(line, "%99[^=]=%99[^\r\n]", from, to) == 2 && parse_keys(from, to, &keytrans[trans])) { keytrans[trans].focus = focus; ++trans; } else { warning("Keymap line %d is malformed", lnr); } ++lnr; } while (1); fclose(f); } else { debug("Keymap loading failed"); } debug("Got %d keytrans", trans); } klystrack-0.20171212/klystrack/src/config.c0000644000000000000000000001473513214501362017034 0ustar rootroot/* Copyright (c) 2009-2010 Tero Lindeman (kometbomb) 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. */ #include "config.h" #include "mused.h" #include "gui/toolutil.h" #include "gui/filebox.h" #include "action.h" #include "gfx/gfx.h" #include extern Mused mused; extern GfxDomain *domain; enum { C_END, C_BOOL, C_STR, C_INT }; static const struct { int type; const char *name; void *param; int mask; } confitem[] = { { C_BOOL, "fullscreen", &mused.flags, FULLSCREEN }, { C_INT, "pixel_size", &mused.pixel_scale }, { C_INT, "window_width", &mused.window_w }, { C_INT, "window_height", &mused.window_h }, { C_INT, "mix_rate", &mused.mix_rate }, { C_INT, "mix_buffer", &mused.mix_buffer }, { C_BOOL, "compact", &mused.flags, COMPACT_VIEW }, { C_BOOL, "track_focus", &mused.flags, EXPAND_ONLY_CURRENT_TRACK }, { C_STR, "theme", mused.themename, sizeof(mused.themename) - 1 }, { C_STR, "keymap", mused.keymapname, sizeof(mused.keymapname) - 1 }, { C_BOOL, "multichannel_instrument_edit", &mused.flags, MULTICHANNEL_PREVIEW }, { C_BOOL, "show_position_offset", &mused.flags, SHOW_PATTERN_POS_OFFSET }, { C_BOOL, "follow_play_position", &mused.flags, FOLLOW_PLAY_POSITION }, { C_BOOL, "toggle_edit_on_stop", &mused.flags, TOGGLE_EDIT_ON_STOP }, { C_BOOL, "stop_edit_on_play", &mused.flags, STOP_EDIT_ON_PLAY }, { C_BOOL, "multikey_jamming", &mused.flags, MULTIKEY_JAMMING }, { C_BOOL, "animate_cursor", &mused.flags, ANIMATE_CURSOR }, { C_BOOL, "hide_zeros", &mused.flags, HIDE_ZEROS }, { C_BOOL, "protracker_delete", &mused.flags, DELETE_EMPTIES }, { C_INT, "visible_columns", &mused.visible_columns }, { C_BOOL, "show_decimals", &mused.flags, SHOW_DECIMALS }, { C_BOOL, "show_reverb_ticks", &mused.flags, SHOW_DELAY_IN_TICKS }, { C_INT, "pattern_length", &mused.default_pattern_length }, { C_INT, "analyzer", &mused.current_visualizer }, #ifdef MIDI { C_INT, "midi_device", &mused.midi_device }, { C_INT, "midi_channel", &mused.midi_channel }, #endif { C_BOOL, "lock_pattern_length", &mused.flags, LOCK_SEQUENCE_STEP_AND_PATTERN_LENGTH }, { C_BOOL, "edit_sequence_digits", &mused.flags, EDIT_SEQUENCE_DIGITS }, { C_BOOL, "disable_nostalgy", &mused.flags, DISABLE_NOSTALGY }, { C_BOOL, "disable_vu_meters", &mused.flags, DISABLE_VU_METERS }, { C_BOOL, "maximized", &mused.flags, WINDOW_MAXIMIZED }, { C_INT, "oversample", &mused.oversample }, { C_BOOL, "disable_render_to_texture", &mused.flags, DISABLE_RENDER_TO_TEXTURE }, { C_BOOL, "disable_backups", &mused.flags, DISABLE_BACKUPS }, { C_BOOL, "start_with_template", &mused.flags, START_WITH_TEMPLATE }, { C_BOOL, "use_system_cursor", &mused.flags, USE_SYSTEM_CURSOR }, { C_END } }; void apply_config() { change_fullscreen(0, 0, 0); change_render_to_texture(0, 0, 0); change_pixel_scale(CASTTOPTR(void,mused.pixel_scale), 0, 0); load_theme_action(mused.themename, 0, 0); load_keymap_action(mused.keymapname, 0, 0); change_oversample(CASTTOPTR(void,mused.oversample), 0, 0); } void load_config(const char *path, bool apply) { char *e = expand_tilde(path); FILE *f = fopen(e ? e : path, "rt"); if (e) free(e); if (f) { while (!feof(f)) { char line[500], name[500]; if (!fgets(line, sizeof(line), f)) break; if (sscanf(line, "%400[^ =]", name) == 1) { int i; for (i = 0; confitem[i].type != C_END ; ++i) { if (strcmp(confitem[i].name, name) == 0) { switch (confitem[i].type) { case C_BOOL: { char value[10]; if (sscanf(line, "%400[^ =]%*[= ]%9[^\n\r]", name, value) == 2) { if (strcmp(value, "yes") == 0) { *(int*)confitem[i].param |= confitem[i].mask; } else { *(int*)confitem[i].param &= ~confitem[i].mask; } } } break; case C_INT: { int value; if (sscanf(line, "%400[^ =]%*[= ]%d", name, &value) == 2) { *(int*)confitem[i].param = value; } } break; case C_STR: { char value[100]; if (sscanf(line, "%400[^ =]%*[= ]%99[^\n\r]", name, value) == 2) { strncpy((char*)confitem[i].param, value, confitem[i].mask); } } break; default: debug("Unhandled configtype %d", confitem[i].type); exit(2); break; } } } } } fclose(f); } if (apply) apply_config(); e = expand_tilde("~/.klystrackfavorites"); if (e) { filebox_init(e); free(e); } } void save_config(const char *path) { char *e = expand_tilde(path); FILE *f = fopen(e ? e : path, "wt"); if (e) free(e); if (f) { for (int i = 0; confitem[i].type != C_END ; ++i) { switch (confitem[i].type) { case C_BOOL: fprintf(f, "%s = %s\n", confitem[i].name, *(int*)confitem[i].param & confitem[i].mask ? "yes" : "no"); break; case C_STR: fprintf(f, "%s = %s\n", confitem[i].name, (char*)confitem[i].param); break; case C_INT: fprintf(f, "%s = %d\n", confitem[i].name, *(int*)confitem[i].param); break; default: debug("Unhandled configtype %d", confitem[i].type); exit(2); break; } } fclose(f); } else { warning("Could not write config (%s)", path); } e = expand_tilde("~/.klystrackfavorites"); if (e) { filebox_quit(e); free(e); } } klystrack-0.20171212/klystrack/windres/0000755000000000000000000000000013214501362016275 5ustar rootrootklystrack-0.20171212/klystrack/windres/resource.h0000644000000000000000000000015413214501362020275 0ustar rootroot#ifndef IDC_STATIC #define IDC_STATIC (-1) #endif #define IDI_MAINICON 101 klystrack-0.20171212/klystrack/windres/resource.rc0000644000000000000000000000042213214501362020450 0ustar rootroot// Generated by ResEdit 1.4.13 // Copyright (C) 2006-2010 // http://www.resedit.net #include #include #include #include "resource.h" // // Icon resources // IDI_MAINICON ICON "..\\icon\\256x256.ico" klystrack-0.20171212/klystrack/player/0000755000000000000000000000000013214501362016116 5ustar rootrootklystrack-0.20171212/klystrack/player/player.c0000644000000000000000000000340413214501362017557 0ustar rootroot/* Example klystrack command line replayer. Use as you like. Usage: player.exe */ /* SDL stuff */ #include "SDL.h" /* klystron stuff */ #include "snd/cyd.h" #include "snd/music.h" #include #undef main int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } MusSong song; CydEngine cyd; MusEngine mus; memset(&song, 0, sizeof(song)); /* To be sure, let's init enough channels */ cyd_init(&cyd, 44100, MUS_MAX_CHANNELS); if (!mus_load_song(argv[1], &song, cyd.wavetable_entries)) { fprintf(stderr, "Could not open %s\n", argv[1]); cyd_deinit(&cyd); return 2; } SDL_Init(SDL_INIT_AUDIO); /* Notify the music engine about Cyd */ mus_init_engine(&mus, &cyd); /* Add Cyd in SDL_Mixer audio output queue */ cyd_register(&cyd, 2000); /* Start updating the music engine at the rate set in the song */ cyd_set_callback(&cyd, mus_advance_tick, &mus, song.song_rate); /* Start playing from position 0 */ mus_set_song(&mus, &song, 0); printf("Playing %s...\n\nPress Ctrl-C to exit.\n\n", song.title); int done = 0; while (!done) { SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_QUIT: case SDL_KEYDOWN: done = 1; break; } } int song_position; mus_poll_status(&mus, &song_position, NULL, NULL, NULL, NULL, NULL, NULL); printf("Position: %4d/%d\r", song_position, song.song_length); SDL_Delay(5); } printf("\nQuit.\n"); cyd_unregister(&cyd); cyd_deinit(&cyd); cyd_unregister(&cyd); cyd_deinit(&cyd); mus_free_song(&song); SDL_Quit(); return 0; } klystrack-0.20171212/klystrack/player/Makefile0000644000000000000000000000055413214501362017562 0ustar rootrootifdef COMSPEC SDL := -lSDL2main -lSDL2 -I /mingw/include/SDL2 LIBS := -lmingw32 -lengine_snd else SDL := `sdl-config --libs` LIBS := -lengine_snd endif player.exe: player.c gcc -DUSESDLMUTEXES -DSTEREOOUTPUT -DENABLEAUDIODUMP -DNOSDL_MIXER -DDEBUG -o player.exe player.c -g -Wall $(LIBS) $(SDL) -I ../../klystron/src -L ../../klystron/bin.debug klystrack-0.20171212/klystrack/themes/0000755000000000000000000000000013214501362016107 5ustar rootrootklystrack-0.20171212/klystrack/themes/Classic/0000755000000000000000000000000013214501362017470 5ustar rootrootklystrack-0.20171212/klystrack/themes/Classic/colors.txt0000644000000000000000000000132613214501362021534 0ustar rootrootbackground = 0x0 main_text = 0xffffff small_text = 0xffffff statusbar_text = main_text sequence_counter = 0x000000 sequence_normal = 0x000000 pattern_selected = 0xffffff pattern_bar = 0xffffff pattern_beat = 0xc0c0ff pattern_normal = 0xd0a0d0 pattern_disabled = 0x808080 pattern_instrument = 0xd0a0d0 pattern_instrument_bar = 0xffffff pattern_instrument_beat = 0xffffff program_selected = 0xffffff program_even = 0xe0d0d0 program_odd = 0xb0a0b0 instrument_selected = 0xffffff instrument_normal = 0xc0c0c0 menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff catometer_eyes = 0xa04f9b klystrack-0.20171212/klystrack/themes/Classic/font/0000755000000000000000000000000013214501362020436 5ustar rootrootklystrack-0.20171212/klystrack/themes/Classic/font/font.png0000644000000000000000000000155413214501362022117 0ustar rootrootPNG  IHDR@=gAMA a cHRMz&u0`:pQ<PLTE2bKGD- pHYsodtIME 30<NIDATH?kA#6*8\M!)\.)1. \]㫮Pe\,kʤTƅCCåH"bYgvO_*훷s;N|9}<ot'ȸJ}du"Ɩ(fg^Yd"S❃J]00i#pes3&|QU,Eq% m"HGW O._\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Classic/font/res.txt0000644000000000000000000000000313214501362021761 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Classic/font7x6/0000755000000000000000000000000013214501362021003 5ustar rootrootklystrack-0.20171212/klystrack/themes/Classic/font7x6/font.png0000644000000000000000000000127213214501362022461 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Classic/font7x6/charmap.txt0000644000000000000000000000006213214501362023155 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Classic/font7x6/res.txt0000644000000000000000000000000313214501362022326 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Classic/vu.png0000644000000000000000000000050413214501362020627 0ustar rootrootPNG  IHDR @hgAMA a cHRMz&u0`:pQ<PLTE߂Uӊ(abKGDhQ pHYsodtIME 30<IDAT8c`Q@ t%40 mqٳ%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Classic/bevel.png0000644000000000000000000000256713214501362021305 0ustar rootrootPNG  IHDR 9gAMA a cHRMz&u0`:pQ<EPLTELLL\\\TTTTlllTTTfbKGD- pHYsodtIME 30<IDATx횋z09Ruu!dD#ٌ!WN~dIH9hbHDŷ,l?/vH0;!}^d$#?wD=)$T!/Є'HܠpmؼTܜM} '?h ?| %U ecsns1)@h- ϩCkUX 4Aച]"` i? 5.@f*;ZM`ri JKtuHrkxY'\.]:f)> D&p@S\d- C){!IF{?n<6 6̯ &Ā5IW_Q{Ed6Pvwꅰ?eEs@`ҬJ&ͪC7qSϭ2sP6֫*a \6͸6zG_w%m8v7^<` quq9KWEQͫ`ULp<tk}x]RߥIN8Xh)ǤPwMq}vO|)I0{ӥ5{nvT5{nCi  O.)cd܊k+_ҷз;=Wv۟TSZ逩(G O}tՋ Y! ˰nt]/{"J珑y:k@/F1Gk;V;= `vPzh<ظ`M8!@5r;"n!0&v@s6VW|@ğ!6#Л?߄ HWh@ sTaW#W] ֆv#Up{[M4!ȟ#n~\Yu09 )FЭ:g?;X2ø`k'6D(Z~'jc\U,'89Pl$=^L6&S YLUcWc %tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/0000755000000000000000000000000013214501362020003 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Camo/tiny/0000755000000000000000000000000013214501362020766 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Camo/tiny/font.png0000644000000000000000000000054713214501362022450 0ustar rootrootPNG  IHDR -cq^gAMA a cHRMz&u0`:pQ<PLTEXbKGDHtIME 30<CIDATc,,#db%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/tiny/charmap.txt0000644000000000000000000000002213214501362023134 0ustar rootroot0123456789abcdef+-klystrack-0.20171212/klystrack/themes/Rust_Camo/tiny/res.txt0000644000000000000000000000000313214501362022311 0ustar rootroot4 6klystrack-0.20171212/klystrack/themes/Rust_Camo/colors.txt0000644000000000000000000000207113214501362022045 0ustar rootrootbackground = 0x000011 main_text = 0xffffff small_text = 0xffffff button_text = 0xffffff text_shadow = 0x0 statusbar_text = main_text sequence_counter = 0xffffff sequence_normal = 0x0 pattern_normal = 0x2699ff pattern_beat = 0x2699ff pattern_bar = 0xffffff pattern_selected = 0x0 pattern_disabled = 0x333333 pattern_instrument = 0x2699ff pattern_instrument_beat = 0x2699ff pattern_instrument_bar = 0x2699ff pattern_volume = 0x2699ff pattern_volume_beat = 0x2699ff pattern_volume_bar = 0x2699ff pattern_ctrl = 0x2699ff pattern_ctrl_beat = 0x2699ff pattern_ctrl_bar = 0x2699ff pattern_command = 0x2699ff pattern_command_beat = 0x2699ff pattern_command_bar = 0x2699ff pattern_empty_data = 0x80000000 program_selected = 0xffffff program_even = 0x2699ff program_odd = 0x2699ff instrument_selected = 0xffffff instrument_normal = 0x2699ff menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff wavetable_sample = 0x2699ff wavetable_background = 0x0b2b48 progress_bar = 0xffffff klystrack-0.20171212/klystrack/themes/Rust_Camo/analyzor.png0000644000000000000000000000206413214501362022352 0ustar rootrootPNG  IHDR QgAMA a cHRMz'dv9~:bKGD pHYs  d_tIME 30<#IDAThݚ@Mr(DEK-/x^J*JDAh( #IfgglvBXYo<|/ q[,>|:.t[Yمy6qHG0{]׾@k(!Y{SEb^VGFm%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/font/0000755000000000000000000000000013214501362020751 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Camo/font/font.png0000644000000000000000000000151113214501362022423 0ustar rootrootPNG  IHDR@=gAMA a cHRMz&u0`:pQ<PLTE2bKGD-tIME 30<%IDATH풡nAGQ5XE'pU8UV'2iQ0DAQ᱒Hs Y Qj*uVE%#SZ 1;I#P !(igH!q"SAWoMH(@Z =JJd&#($Gd%vH(#Ԫ ע1eg/agA@Uu_*xzd1&1XUg)Ue-KLd@ b6|r0qjɽJ8]3TjP+e:TUTt1|'pOt7oyMȘ&zX͘{{s"-cYggߌN>r,X}Tf+G; h4*aڵ w*䦼J4+6PY{΋+aM/EA4WsG^_cPn]>Mq9_aJ fPTY]x4`^U[h/ {]obY;S򹎔%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/font/charmap.txt0000644000000000000000000000023313214501362023123 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Rust_Camo/font/res.txt0000644000000000000000000000000313214501362022274 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Rust_Camo/font7x6/0000755000000000000000000000000013214501362021316 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Camo/font7x6/font.png0000644000000000000000000000127213214501362022774 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/font7x6/charmap.txt0000644000000000000000000000006213214501362023470 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Rust_Camo/font7x6/res.txt0000644000000000000000000000000313214501362022641 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Rust_Camo/vu.png0000644000000000000000000000230213214501362021140 0ustar rootrootPNG  IHDR @{ugAMA a cHRMz&u0`:pQ<bKGD pHYs  d_tIME 30<IDAThޭYA0 N\^ K^nLZ#F5,u$q4" Uh?.C{z=v؛r~iM0bQ;p N >dޛ2^or-u2 , -z W7:oy?`Հ.-Y L& Y €4V="_ONh_4J(WWY$P@8 7{ .Bnh2 ,M@3'؋ʧ0 3Y [| V FE 2V%%Y [ wͨW@s. <<~_O$ vAowtK8/Pjq!u,XIdX$$-1:`]0e155inB+Q i ,X iLWw5CoĪ7b@xٸd15O`˿(m\VUXzU\7 ,n@ 󶥁\l,Hctྼ[Dq=m{݊/ϊifΫ Ӄ5v8cM7ƝjkQO@jR[ 0'V `Հʗ@xE QLƀ['tV/]Dn现 v#-7pblR]к b `"gg 6r%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/bevel.png0000644000000000000000000000240613214501362021610 0ustar rootrootPNG  IHDR 9gAMA a cHRMz'dv9~:NPLTEhhaV8?&&&IQFa&222IF?:):_/s^@hLOmGMMM+)+cG bKGD a pHYsodtIME 30<IDATx횋 )nlkܶ4s@ oN(;"BtgWCB;^Hl%T~o9OP%goJpuފ;/R@siKiҽDs1-0tM);[^ Dx+l`2ϟOmP g ZP<}S+ r}k] V1jK _ Vn60KA*g@6'p铐؍Z!z#zn(.,aFʼny2v 'Y64esa:kO,U<O9O&x1+Py6*PUU S>~fQ6vɠ4n=Q6Ah Xzt7_A|4,vn8K{ j [ tWﱺk#chhkτM_avxp DH@Ho9_h#Us2454g& 8{_35, 5`*~%/'vȫo- ׯ +tٔ>d \)9 'q|HT 9lƛ̞X`6lia~@ J8h8ABq noos.v ePb1^؜<1` JR0LH=-I-0}XW._ډ`>߭?)׹F>7"EP2 sv/^c68ywEoFO2BlȜ+u?th1Z%nTGITU*PUU[V")?^%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Camo/catometer.png0000644000000000000000000000512113214501362022473 0ustar rootrootPNG  IHDRP,gAMA a cHRMz&u0`:pQ<!PLTE<6KdLbItgpYOvgbKGD ٥tIME 30< IDAThIsF)B<`3Ѝ5I9M Lnc Q5^/X(57?E_ Wj_bn3#?t_bG4p78yu]#A&_G0A(Q.\.xN|ēMNviJCQI%I!MRM74' }s"8)RH>sx@="39n֡)#9Rs$](iBHyӔ+yEeY+RuOf V_9NW1l""QCMGF(!1۪/n In uK?3\A&y!,\Df鐡ilCNrW*#̍DzA:%Ud`>9E7qŤʆзMI҄Upoxڣ CzfkWwFz Yɚ6*{rjp?.ށ''ĺ,i 8mL=ݼQ$Yyqr wyKz6[$LLbw 2>>)9l(" ~c#0 3|pмu)4%qbi}3[*r&IO(qnGԸ UFIe+޲Z+~ȃYeG4fa[0gUP`g8ۆ'!<4Mk. ͈ҷwX<.@7:hxR˪+b<"^B-9GΦsg0'jP<-/a+^&:~x t'k!v }\q77qEڛbr89Rc9 ۛ1Ơٍh ]~zjyƝby| ;.ք|pޕ{8#]p0Kٝ͒0YǻO SKwBw [Lp{>o2oDJex@a;39N R 0qvIR#ODl;%]{ &8ז c7$~ā"+af ʄz I@ 1-{iy/;ʫn\ޥeo8Ň66m}ٵ+6ʫqb5IN(En5cf[ RmQ G+&O]Ǣ)w*{ a-./Tc FHPޫͼ_Q1ikc9fT'U􇖘ZX&2X&3wzM፝Omj#i3gNFLa ̏/!PN-uW:|$pOӴ3h.)\$bθm»^Ԗdsͼ#SApQ~ br+J^JdYߺ8GO o#ҟ.&˖L=oX33O-.hKBz|տ,WSf+ILR}~i1(s:6LvuϘ]DemyT{!Pm'[ދ<Ϫf GH_ t?jyw-LAۏ-oaL4"ylYHP l{9x8, JV\?k<X^[x/kb2=!`9wyn4ahJm+]V^[xrN~w%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Default/0000755000000000000000000000000013214501362017473 5ustar rootrootklystrack-0.20171212/klystrack/themes/Default/tiny/0000755000000000000000000000000013214501362020456 5ustar rootrootklystrack-0.20171212/klystrack/themes/Default/tiny/font.png0000644000000000000000000000054713214501362022140 0ustar rootrootPNG  IHDR -cq^gAMA a cHRMz&u0`:pQ<PLTEXbKGDHtIME 7CIDATc,,#db%tEXtdate:create2017-05-26T14:04:23-07:00ʙ%tEXtdate:modify2017-05-26T14:04:23-07:00@ttEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Default/tiny/charmap.txt0000644000000000000000000000002213214501362022624 0ustar rootroot0123456789abcdef+-klystrack-0.20171212/klystrack/themes/Default/tiny/res.txt0000644000000000000000000000000313214501362022001 0ustar rootroot4 6klystrack-0.20171212/klystrack/themes/Default/colors.txt0000644000000000000000000000222513214501362021536 0ustar rootrootbackground = 0x0 main_text = 0xffffff small_text = 0xffffff button_text = 0xffffff statusbar_text = main_text sequence_counter = 0xffffff sequence_normal = 0x000000 pattern_normal = 0xa0c9d0 pattern_beat = 0x619fac pattern_bar = 0xffffff pattern_selected = 0xffffff pattern_disabled = 0x808080 pattern_instrument = 0x00c8e8 pattern_instrument_beat = 0x009fba pattern_instrument_bar = 0xffffff pattern_volume = 0xa0c9d0 pattern_volume_beat = 0x619fac pattern_volume_bar = 0xffffff pattern_ctrl = 0xa0c9d0 pattern_ctrl_beat = 0x619fac pattern_ctrl_bar = 0xffffff pattern_command = 0x00c8e8 pattern_command_beat = 0x009fba pattern_command_bar = 0xffffff pattern_empty_data = 0x80000000 pattern_seq_number = 0xffffff program_selected = 0xffffff program_even = 0xd0d0e0 program_odd = 0xb0a0b0 instrument_selected = 0xffffff instrument_normal = 0xc0c0c0 menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff wavetable_sample = 0xffffff wavetable_background = 0x0 progress_bar = 0xffffff catometer_eyes = 0xa04f9b klystrack-0.20171212/klystrack/themes/Default/analyzor.png0000644000000000000000000000206113214501362022037 0ustar rootrootPNG  IHDR QgAMA a cHRMz&u0`:pQ<bKGD pHYs  d_tIME"v7% IDAThݚnA h)hx"*Zx^!@ xJ=-%@Q{vvcOyo}7$=ng7f:u-o`<L8$`#lw6nD Fр+|no>T݊JCcð<DY1V g؞|L"Rp]0 D!i;9@Wo0#@$s>ޫ^DC8V@@j,BnGm6~0էIxٚr u V8Nus0RB*iCzܯ7HA|4Q t-: =s6X MӴ!5oH^ɹî$EA?2-o"df*0P)HiC"{@dgG *G#S%a{ Cj;}>}t!kX'B-/1pe%^IMfZKƭ"*2:"kX@hd1r:ƨ9}vV <¾aX_  מ**KiCr|fhELҠ v0^,V4SH5# \q;9v BHΪ`E_@$OC^T/L1wF ϊ0+z; -~X\6޿s}4 bmu7^$?FG-%tEXtdate:create2017-05-26T14:07:34-07:00(}%tEXtdate:modify2017-05-26T14:07:34-07:00YgIENDB`klystrack-0.20171212/klystrack/themes/Default/font/0000755000000000000000000000000013214501362020441 5ustar rootrootklystrack-0.20171212/klystrack/themes/Default/font/font.png0000644000000000000000000000171513214501362022121 0ustar rootrootPNG  IHDR@gAMA a cHRMz&u0`:pQ< PLTE)bKGDf |d pHYsodtIME%S5IDATXT[0 _0@8Eh? Sc=8&#IÚiͽ֥2V]=˧4 s-&q:0bs}/ <7Sngz#ȘN .eA XcyF ]|~+io鐱! %f5"SGgc2+τFb *fp"6=<{5#؆6hMjڙ #;1RTS_cj2"Ay3>Kۊy J59v9&2Drֳ.N T;>k:eC=1SHY`XlKȌ\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Default/font/res.txt0000644000000000000000000000000313214501362021764 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Default/font7x6/0000755000000000000000000000000013214501362021006 5ustar rootrootklystrack-0.20171212/klystrack/themes/Default/font7x6/font.png0000644000000000000000000000127213214501362022464 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 7IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T14:04:23-07:00ʙ%tEXtdate:modify2017-05-26T14:04:23-07:00@tIENDB`klystrack-0.20171212/klystrack/themes/Default/font7x6/charmap.txt0000644000000000000000000000006213214501362023160 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Default/font7x6/res.txt0000644000000000000000000000000313214501362022331 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Default/vu.png0000644000000000000000000000230213214501362020630 0ustar rootrootPNG  IHDR @{ugAMA a cHRMz&u0`:pQ<bKGD pHYs  d_tIME"v7%IDAThޭYA0 N\^ K^nLZ#F5,u$q4" Uh?.C{z=v؛r~iM0bQ;p N >dޛ2^or-u2 , -z W7:oy?`Հ.-Y L& Y €4V="_ONh_4J(WWY$P@8 7{ .Bnh2 ,M@3'؋ʧ0 3Y [| V FE 2V%%Y [ wͨW@s. <<~_O$ vAowtK8/Pjq!u,XIdX$$-1:`]0e155inB+Q i ,X iLWw5CoĪ7b@xٸd15O`˿(m\VUXzU\7 ,n@ 󶥁\l,Hctྼ[Dq=m{݊/ϊifΫ Ӄ5v8cM7ƝjkQO@jR[ 0'V `Հʗ@xE QLƀ['tV/]Dn现 v#-7pblR]к b `"gg 6r%tEXtdate:create2017-05-26T14:07:34-07:00(}%tEXtdate:modify2017-05-26T14:07:34-07:00YgIENDB`klystrack-0.20171212/klystrack/themes/Default/bevel.png0000644000000000000000000000257113214501362021303 0ustar rootrootPNG  IHDR 9gAMA a cHRMz&u0`:pQ<NPLTE~]O\X'dpseulJJJ1&&b/_?99bKGD- pHYsodtIME"v7%IDATx훍v0A2R.e%dHmgrt dŢRJjK"V/h/Eܾr WT5wQ||.ʬ:~r$~r,֠(:s⋫kkvPr Zlhèz!9qJ$0kp;vצ*TTfPP :@u@0+ `V:`9<-@}_9 $.pÞQ#(b rOt"P߮F`hݲ0~0Vvh0 `@X! &08{ȍ"$P c@^gX"oΎ x1eh&ZXsa䀕,.=po(3w+IЇ{`9=u)> `,H?:x )&C'Ĝ'#4n@2Kp(Ĉ O;4k8cTwR^vgSdT$X Hxu08 sz AㅯqfEȔh3ɀa'r{$ `oa܅X=l!Rbqݙ'PU *~%4gu%tEXtdate:create2017-05-26T14:07:34-07:00(}%tEXtdate:modify2017-05-26T14:07:34-07:00YgIENDB`klystrack-0.20171212/klystrack/themes/Default/logo.png0000644000000000000000000000570613214501362021151 0ustar rootrootPNG  IHDRTJwdgAMA a cHRMz'dv9~:'PLTE$+++5>3MMMnaa}u7bKGD Qc pHYs  tIME"v7% IDATh=sljoH]4x:_'tI:[ pئ!v>[C-;@_.g|5$_&nxFd?o,j۽۽m2}'kȇmN'vckNapx~g 8 }73?:\a]4sw+Dh6-z{ωG섏Dm*Cm\I0ߘX,׻fm}3Vle cMvr4{m@pw/{CC^'4RQ c}|Е䲞E8LUzszvwޗR_$YؐbH}(h;>Ǜ=,% ;r/%d$K?톼oFh&$:jTG(!Ϲm{qc5kDC)ItAQ!2voWdJ>|.o9ۋs! S QgDNs$]Is3nKNEJ? )| uJBb7\I g&YBkl!Z;_:Ќ }RJw5۪bb>r?RW!Và=M2Nx #Y#gxJҔkr5JMCfbtȼ?,Gz2 &}^H6 :&=@4Roȱ!_Ds&FX@Cq0g uOtG)E,:/DyAb9ً^b}0CzrX㺮K&}** ݵde;˗ɼFCC=z? m\u]չR; 'qМdr Rm4#M{Ȍq >cp萨c@9YydtoI r^ {;]dˑp@~7,S=]]\Lj2{YvNM(VdX%Ϡ[i2׌N1tR|W S $rM\d4s^AN2m"^2ī)ir@ s&o9q4FqAE[WOޘҾ1f"d4sNS-x{z:"j& &E]IEMmT`I/c4vkAV!qQ@QED˗=VtCQD&4sɎ&s.#eNʮsMdBB24Rh~vlW#4r3Xf{NJ<' Xde^H4v91<*ͭ +sY ?*v*v_9f TV/Q0;NƇl^ϙMh|QMd$grJ7_Ǒ9 Wa d}y)敪D٬5ɜJ7kU0Uqء>G]kM݌>eD6먦6HSt5'ɭ6 ƕFZ) cW@ l#ƻ^4ѩsaemwLɝ+B4cۊ_&*͍6k)u.ۧ&v`eD&t{s]#5c:c.}ᦕ2O\m-f/;_mtü3u-y m̢޸9)F/-d>bHMOdG(΃m6i.%{o6_f۽۽۽ݲ?{+%tEXtdate:create2017-05-26T14:07:34-07:00(}%tEXtdate:modify2017-05-26T14:07:34-07:00YgIENDB`klystrack-0.20171212/klystrack/themes/Default/catometer.png0000644000000000000000000000512413214501362022166 0ustar rootrootPNG  IHDRP,gAMA a cHRMz&u0`:pQ<$PLTE<6KdLbItgpYO MbKGD tIME"v7% IDAThIsF)B<`3Ѝ5I9M Lnc Q5^/X(57?E_ Wj_bn3#?t_bG4p78yu]#A&_G0A(Q.\.xN|ēMNviJCQI%I!MRM74' }s"8)RH>sx@="39n֡)#9Rs$](iBHyӔ+yEeY+RuOf V_9NW1l""QCMGF(!1۪/n In uK?3\A&y!,\Df鐡ilCNrW*#̍DzA:%Ud`>9E7qŤʆзMI҄Upoxڣ CzfkWwFz Yɚ6*{rjp?.ށ''ĺ,i 8mL=ݼQ$Yyqr wyKz6[$LLbw 2>>)9l(" ~c#0 3|pмu)4%qbi}3[*r&IO(qnGԸ UFIe+޲Z+~ȃYeG4fa[0gUP`g8ۆ'!<4Mk. ͈ҷwX<.@7:hxR˪+b<"^B-9GΦsg0'jP<-/a+^&:~x t'k!v }\q77qEڛbr89Rc9 ۛ1Ơٍh ]~zjyƝby| ;.ք|pޕ{8#]p0Kٝ͒0YǻO SKwBw [Lp{>o2oDJex@a;39N R 0qvIR#ODl;%]{ &8ז c7$~ā"+af ʄz I@ 1-{iy/;ʫn\ޥeo8Ň66m}ٵ+6ʫqb5IN(En5cf[ RmQ G+&O]Ǣ)w*{ a-./Tc FHPޫͼ_Q1ikc9fT'U􇖘ZX&2X&3wzM፝Omj#i3gNFLa ̏/!PN-uW:|$pOӴ3h.)\$bθm»^Ԗdsͼ#SApQ~ br+J^JdYߺ8GO o#ҟ.&˖L=oX33O-.hKBz|տ,WSf+ILR}~i1(s:6LvuϘ]DemyT{!Pm'[ދ<Ϫf GH_ t?jyw-LAۏ-oaL4"ylYHP l{9x8, JV\?k<X^[x/kb2=!`9wyn4ahJm+]V^[xrN~w%tEXtdate:create2017-05-26T14:07:34-07:00(}%tEXtdate:modify2017-05-26T14:07:34-07:00YgtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Default/cursor.png0000644000000000000000000000054513214501362021522 0ustar rootrootPNG  IHDRbgAMA a cHRMz&u0`:pQ< PLTE#Kb$bKGD LtIME"v7%;IDATc` eP BKD bX% "ZF:"P5+ʆP`(bm%tEXtdate:create2017-05-26T14:07:34-07:00(}%tEXtdate:modify2017-05-26T14:07:34-07:00YgtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Default/icon.png0000644000000000000000000010744613214501362021145 0ustar rootrootPNG  IHDR\rfIDAT{̧gZu<{=x}X'  T)DJ6R5)m?J(QUREH!D P ivaw8;<}Uƞ~g|/I{;O]|j2gk$?D,w`;8lӆXf\9 W  #`} -8>H,3~oO6Dޞ7 p m 15$bcDmgi 9i &G! &MA7<@ Xk~ nrkN 9iHIc,$prjliDMCJZ4;톸SBKN#jRG-W܂FDyDI-bA[%Ԑi 4y«gnBoQ{=BN-&N'HqH-ϱ+_[/&l|J=aBsjH 9"j WN8+b| ׄ֎ٷu$ V9~WL@3BÞ" E̓"@nDv瀟-ҳ~Za p!NGD+h̀=NՈ8 PyK(1A=%$G&p A^(^T 9"V 5" jPB!4 XuCkf|;ɌZv~ڑM\pܕyIVM=-a_|ȂYǝnDmi48cBm5VIܨ!Qb ׉1&9 1 l_ qDi$m 8u]qt Ns'?IOxeƅ#rȷάY?}L(sÃH]Xn&7 x JΨp o2lGTW,- 8;Bo3ADUJQuf֟=w݈1>9CBb4>Fӿib瘾ˈ8Fd;_;WΜdi`Xt+9$E_}"MgB-jz,=m6ϸAdSQqA#l-I =el-!;)j0^ D2sofh,9(\NqQpg|/𡧘͞8wJhzWt@:N_9p&*KaAҜymUo}/\:Ҡ9s`]*\:æ#׆rDTV*qU g)D硯PӀ^~۬y'N 9k\8hq au8:]תsPlؼoCވ̧˔k,!;=yGy In +6-XSqBQra1̐ʁ\P*!!ܔQ$\Q=E\% 8WSCC (wn(EcA+(s BglV wedc'D ƂA+m(h( BӮ!3]NĬO:4y:@9x6܍Z 1C$u "V9 ;d xV,U01 Ksê!Q80 iB{{& \@`AyIl̇$/pcbfVFvZMsbtMe@f 99F!N"1UH3"&H7cls8U#"E'rjYx{<5-t_97p* W:Q/}8刖ْV5̏y*l:=͕cU^xA 2>|dkoo=^YmG#OAV3bl$~w4re#u!ۜ1m;7y_qLJABv8 W9 :DM@b!ŎB"UW .D@Bl4g,+׋ b\pQĝ(xBB_RA:JF͐*Hξ7 w%]C(!@: *  WBȵ5{. ʹFp8'@) &nZ'XV5UP( T *9{,q'ܼț\k`sLCрHQ A#{dŪaՐjXu)jJ5rs P3Lqi"`K@.qDB_Fr SzC3/Fh4 J@"CXP-BH8b\/!ܜțy桇pj)rG?8}Y7@S&-yPԐ@(UAhX`7$x,g@Xyoڱ+bpy;m2~zJ`t[=[Cg7Qh~|5̄&r81_Ỷl+;Ujh8s'(1V+q)lM>+>\%9jvq@9A/Km(VMr3bc&}eo3|ܮu##aiYġ8{s)οx2VzQq*n: (+ 06k!iF\Օ F[fys+JS\Zy] 4ϔ?<#;(%6/R灝zJ{Iʴrara3gVӌ瘕3I]RB:I Ip3"oFJ3bXk15#HZg8(wF F]e0)1ԮU^հ.8ˀ.D9ł{H5Rn;MrK[*l ܷ\2ܝ6 :JtqDNfEBJ{.8R!1/@uDnn~׀w@xw99 1MvD& *94]_,:]/'l.g&F "`]bLI<#8ڽ@=t/n=T# ֜[$.nı8*0V"Y9Q+ BSB-{;@3^!j#I݊܄P3}r'1Z#(/>ImhgynL;X:tL-NN(iV'ufZ"hʡ{Σjس>YyULԑu2#y7- $Iݼ]yq+5,_Ft"[Uc%AIO}؀qƆ3S˼%G\%n88&uC~>Ƌ_qV7J-I݊܄P ]*S  iđ{ύqx^PsK5YQÝ]Ahm^Oxw9% 57N;74 Vscfp0SQqD,`}`FP#J@1ޛ$FK'yܰ b`͍֜m`B=+I*,+܌4aDY\ψܜk HFE=BȨUֲ88d "lofD +F1!b6gR0)m "ƭ1@t}7'̂Ba8j/ 0ZҤ`AaeDsa҃K)K#@P2. *9\%0w 'j`Z7DW pzP:\ mqibf2;Q*k/;"8}` Kyfy^PkV8ʬH<`,x=h˾7B]hAb0j׸; g!apsckwn[AW9 $҆@V(Qvk&P YP+YpZP/:Q!,Cy($rI9k@˔ 8B&{g25Awūq܅YA& M XAQ+ܘL&L7TvX:^eH5ޜ 5 Lw fĚAJOW* Rr[ fX?Mf: uXa/*]\`HrPdmYY*7gPa)v檾rUXE)tiJ= K@1셭 D[O}wx^iq@;O6ϟ4];FkNӈCWNs?!I+w.=ɂX&>^22X!KԜ,9g|Wilg߾ѵ9:<@_3y>:5e'5BSkh5^|c!8n'~lQC8ƭ̹KngA"1#.BB(BW#bN1e` 0PDL5!/WݗPDc)J@X5CZ O\Va``V pzy¬x2%g'xJ3L) @0ɂ٠DK"HܸU5qsĂF&u3@pID! J&z,TݰsB"1% ")0 ul,sSD im^7eG:!sK#Eܡ@Ee?n%,,;;rcIR3P"-SP!ԈQ"1pNr pc;^4٤! ^81 B-)7( `7rwk zk/,F8 "bLg;bN)6+ !2\FU]?`gѵ ķ tI|@:vl݀ nhy@]G̜ba5q&eN+ևpt9Ngn@\KD(b ✅ ܴ-qq`͜A7'uJl'ľ(ӮaZAE8jX:f,GKχp܁J,m]j6qMXPnFKAXHԳX$O,ՙ qӨ*fN1S9mI<!]ˉ-^|mrI<4Yz 673 l RPiuB|gk;Q*ʴjTdor JjWqҳ"\> ]5MW fXzD97rRܨ4O΍-ֆB;o9k%bL1ԙUN&'VG3>|YF _|^yxX: c}Bh.T_&e>澱Ҿ%B2N(9€/vH q.p'ōKlw %c Ӗ$Dfݘׯs˯ɱqKW )?x4=*KD# .BoqRIy h56C8^8!J;) "k̍LjXJ褤 L Ŝ~Rh-aҠ]ycS;$/A]Fv!+P 3p9;bG3Qͮ͟p}2nt w# K̝w";0 ~A M96dE(.Q\2Y%hPE8"r%ogy=\r8^;;]>֌<{(ձGמO3L-_ya;~sh䢘 O^",*CQ⁦"<ڔ?x%\*k/(kL,? _]{gZQJ cȈ7xN}b:f)YA)-_ZgG'Y % BHA$5: ^Q:dED1E`zF͸CP-,`M悹QLQs)f)fB((4>0ЪC z 1Gr0@jd\zenra.wj ~ꊊaXp>^½&|&bw#" N.+baCG,H04PqDI@ $|bZsǝswܝ[b8#8)΂#,8‚; bܹᓋ< %c)^^X4 D3q gA&gnpEN+M D>o]DT"|*kCg:YC#u\3@2rt'BaZ~{l?D: CaCwזzWg?Éisǁ…g`{)!R3&Jg88 :LAI;Ӟ1 h |&YX'.rS LfG8.ӈb|pp}5d^`2}(%cDHB"baE3I1f2 bO" /"s`/=܎podRiң8-?atX@Yq7TQUa 4 *}+Dž[@5 ^P?8t@F\5DU`X8 {}߻yve OEvvsDGQĖ]A ]Yr7X%&mŬxxQT'YaGZк%`6E4q裉 "F2!BPRU8 eiQQ]UHSwx,(qnNg NNCaΝHu q+} %Vt-se4Te:3GB:D\mINW)t<,♵1.a=P1^g0kŇ[b!"f&F;I` Pq6ֿk N;O ILH4< T'FX(yK%R T U,9kKLB(S7^ FxsρD.g[(ĆE9?뼷c@Ospw@CN[GId?Lb ]DnDnAn;w%"q()fvaWԂ, I 0L S˜])$ 8^TH0}:#U=!\-T ;xoLpR(.<(ZgRJqETc8n\ ΣB(h(,h pŧV/ˊָL$Ambr>ƴ5xP$8]3d:^n`8]y谧mWx 2JQh!}[fq'⫧~Ȯs jo |:1f.1WI!4󠉀7\0 <bX3@H(*b8PGY3lI} ܁>B R5cXu&ȳ)% Ġ\;hkM;|3Lf[4s4n<*"{u谨D͸ wRŞlQ{>oi9jkv::)$C6ݹ? k3> "BT%:ytVN׷'U7SnN[zz*%=-~0kq$O ]S pT#JH.J(( b9c0>J\߹è/-;Sz+;>)gƘ*(KnPЗ.nn[sa ¤pN't1-]iiGId"O^dmEBoM\QQX}eZG)!qd< -=cl>I(= —i'Xqb{fP8} DX8rb?4JsG|OD//out8ǎLr!c+\'Yz'ҔP+ yD(xr2a5"F+R!|sK#p枮sb%vkO|7{A;v^ gp̍^&ŊMB}*$opQRMjg$Nʰݡ8y ~ur~΂3x%TuST1,Q_Ռ~po˃D(nQCpRAKĹ2+RR.ӶYː $SLהCQ٘JRؚtL&nF`k2jń&-(0᠆i;fQta(c8]}҈-mbq iz %P2.¡G_ Ei1ꅦHAd"w %+L+h)XPbR7ADXX޹İBU;4`!7%憃P+4UjZУY1M)B9yj=+Hy&PAKo;pAlxwy}sg\". á5ܹ87ccM>֘Fy\iK"j'jϧBnde\):Ͽ %;. .ڵ7bz8XT픜,Xw 8!7XXio3\AKRus,x49z RljD)$͜z ['ĖY;'erIڳWD5܅  BCU蹸}w6N3-vo%rIvc^{6mbcz<ל9O\dn( xs8ٔ6+ՄRjK`Cˁ8i|ZK-~GSjAps. Z C?H;2:tRC[ Ղ 8Tge waDac B2z058UqW ApF!{@1 qabuS#F 3+9s?:t܎D DM8 8M8?mY(e6i:} t%""`%E@X&9i휘q`:} uĝ*L#WJDRcK)F;̕&W Nk`bC =U-8UlP1a]P)T,PŎ抽fEq.4FhsEo@W*z8VwAp>-B =BZꐩB 8 d/"',QRp;-4 SK&߾W(_S:OO1-i~z-oY ϾMGph;nGS+,C2FlF 9CɅ7is3iZ!ǧ8 <(nF"W@Ĕ+^3Gϋ Y`?1TjA]q)fbBTC 8:P%8{8*uE0 b#g>m"ZP *JPE .A07Z<ungnVKX"N<ٜLb&j T%PJ7 OPfa(%&$&pı[b[%^nsuᷕsZm~مhR+ ܔ(89bZ1*f/F)Ju(bXP+ZlM&TjJU*po1SN8ww(@ybJBNCP ( : BUH5DqUvs1c7w\p̔UCYRQ B!";n  Utt 5BqCug[s@@L(☵ܫ(H)cV'@4TD NF`8w$8߱D#(^.# iW'Q(@n&zN*A݂8I+Q*1JMTU'CJZ݉B÷9GօA x8828ߤ^ɿS7Xgp#PR""Kp~jDuhJUGrY۸Ɖ/s8h0DDfp["(W/r'5qsX&f $VFM/4ёiHL+i+@pL&!,C5厙MntZ#̽&l,T*BW ¼TS·Z#0FG"(mՊ ((΁BŰ{ T'׈X$q;R5[5b\ J  IC  17 ֑ZLkaP 0Ij@+H; D qg+rCU6a%Q״$JBAB8V#*"?pϨ@{Dm^Q-0 `.}u wtXZۢVxmDR=|k z#M*9 \qnnm`>DC8:^]8VŗBAPg f .ͯqvr~|2x'ƇBu#[BPEbS@)B6qad9hq{'"UnJA M!R5PK⠙)"웊--rKrZ߮[A3VlfXxlnp4>p܇tʘ̅N)HTH20Dn!ڀ>7t]TRC |ӅKcL ;hĦeDZDDw1.RK11׌ Üa"@PC * s]@Rg1 ʂA ):ͽ qa9>׸acm_f"$ ȓ:´̈́![~ L1S#mtu!J4 W&K4$>WvdHsfһuγS뜅Z"(shB\#Ol^FJиLp/"%~qàQ~'fŝҰs[O]oy饌l1\X!ej;]gZ~ˉS]+kf:!eGqF\`I-= 0 tTYo9٫&j|?2j`V3_c- [fpneyyTS'qp@ǭr#w@n0@p"VG8 [C\ wqpY7% 0@or^EnA̜ʽqDQ1vD7je/qv.%40qD~w]]q; UE#m p Ao{ySs(oQ'uʑΝp#BxwqSB(F[8$]5:|<ɼ&CZ"Ϝ#s~̏?$+-eAf[y;%uWCf9cV"EarvfA!ٟ56&yr{זiKyEB<I8|!TwHVzΨqBd:t .6%n'HƬ&D*oK+#R& oWn 1999*6U]P1~)q)k)]Mk#0 ,D6+g^]A9v%J5;Mm y#Ƭ5 ݈83E]Pu4ގBpJ^{mՄ#EަMsD+rA`.uE9rO% ("V_l0+Rؐ>mgpJ7_""s#=ʼДl 87ء֎_-WO. g]q^xL XKdD wȑ",#C ʰFi F0҆ha$1Є EpGw]ױנ?b4X KxhxymYJGPUr@ar'v1a>o3ܡQݸ , ycc/Qs_ʝ͈?+ yl}e ـO{jXʉ6"G{L&~a~~pȕ+Wkvy 5dk^I]-|Op^U‡Or*RbHD5Vz-qXj G躎^{~"s3uz{$2"sTtYAuuTwpFA09gmRj.UDA^VQE:.)C((t5k@9qvrCP1qwnq%+{;%faD¤"s/T0E(FgW7Wp@p(jqDAQeʴN x9Mr3+uG1€ 7'7rq 8m쇹62Ņ#o\#k)^0v8:Z !Ou !(W^d2C _cM+HXݹƫ^B ϯ^vRqIQ0|7y X>̕ {@8\1}|WynUFa |q+zs*K}|/g.a>o'v-R)~0b[v>s@0z1@a%mAtA=am14 8A 9*QPq#o%RP:.7)]fm~hdD%1s !b Pi >tBJ@BL-s; Սbl(GH!2bLb*PQ$;UM1&w%[@rCRj ṔhPS YkôeܨfJԀ=^~gf˯ŗ> M |ٚoQƕgXzvDVTGqn]Xǟg?#]ҕ=J$Paf(B[/q{TG>{>A { B+ CܾcvUx|"BD0v)Y`Z"F<2D xwwgY3BW;fuB?p7G%!p+V+A :'ILnέΌ:51Z ܎"s䰩d@RQ84MQ>]g F`Pk^o@?iRYVb0@8Lf@#i%THhFl^FD@ JbXxeeTBԄj  Q$ 1w@8r܅vsZ*)]a2TμtE1]iɨj܊-r( u,-Y)+0 ԦM WVr0eaT&XX*!88  fcn\͙׺f8r[hao 5T̍;o묀;١:.ܱ&T!fL7"UBcKG5j  `n֡5@t܃RN0 4Y?=|,A {zfsgZ{+π@uaam)”wӈLI+s&\xm 'O3*Aiyi} %h}Yvƛ,4^a+MPFfZ3d>O>΅=ggai{ fF{Wln,==9q;"98M {J6=q&)O^y]?i`/qW 2mG@ӳ|O Uņᰲ'?5n=̌yÉC> `l"t\{uʕT^Zg2 [md*E N5+Yi!%8C‹z\?=)^:0XYZ/|EvՇɵR%C'F,SDž}$ tܖsU "KC%j#Gdx 4$8(2uG(^2[MyPDlt]߯Fck\zF!y ZT8f), L' ]NLR(h;{8V),w\ x3lt\ihaЏ hEnHpi@B8 hT)x sW1s3BQ?.Z­xu*#uPݘ9 )6t3HYY)J́ *ǖqugɕ+WO6.jC:|Cюt"Ih 0f VBoj&U._su^@/D\R˃3v˵e5!J pD j:6,6Q"`lVSBJ3%`9gZSD#&n'DҊ!,Ŏ*~͍] nN+fhbXQ [uNpD%Qqqz W MT\?]*1͐#>~w:J~cȏɄ\"˃'>8^V=$83'V?sQ'tO>ԂqvKkX01sH (JG姟@F!);%Ƽz Ν_C ZދQG]#%g-/l}z >^N(G{ s[Ml|St5Ur֪ "O#WEՉbV#>F$E^ʹ;$ fRsr4^_uθv|x~u4Tg)lo$C@q6#e$֔ݮL'D ,q]" ++xqn q'5qթSC`bbt5._"HRt^Y>=b[ $Q qDB9&z [HLJhC^~yWib=yZOcd'w1X{!BL tJmQ+UǝwߍW/caF/d-A Qd03WOK Dx9 1& _qpNuc{4`0`ΛQtFn Da7%Ƒa`x"yc** .keaywrMCx6Q(BeZ]ҷ+ӫ\z("RG++z_O_'qmkN;9c?18~f'?7᳛`+#WՆ2=;~K|Svyh})Ύϝ{_+>rotR8Ꮋ%j,yϓF+E'>ā{6\OMӕ31 Q+:+,eu?r8 A7놽c 6t`l| Xv$5)Aq vró'.0 Ge#l q ZGh?=8Λ^8a8wg.Jbc! :!fj;EuNZm߇GGC%f q[lYֿHjXykMpk\'څkAL5) @7mMbB-(weq3[]Fqp8\ǖO܍*mf"{$5z҄B2I!JC AlpfcryzN7A.P#V#V̄A:'O"> Wm 1 Qa^m1r+A!)u\4p3b8GecApu3QQ&isDv)ah@¥)ԾpuƳC#RpA`':q wQJUPMhĵ *V\r|}g[^Y3H}9Ns΍\:rPQ̍2 ޠ5s*ʝPyMqܙ:3ѹ=~얄f\{q<*ljǓm˿$'h)թEkjKό8YX^_7>͜mȿAQ=8;s{%]ɒ-llJh NN'!@ۿȤ LtmJ& 3!-Ltbpc,-c[ow{}^Ylb/}"5d})#b_4K}Y%s)x[X-0I, +t%q)E5|O0"h4*#g/c6ɴFF4*khj (k%S|ivh9u\;s{f-m:u#Ձw,y|y1Tf^FDIӔcK9kJV-WZkҧh-ĸ9.`y嗥4-I2ik_k_Ϫ6ˀ_f/B&y ǎ5; Dϋ6\ .ff|sbSy 2rY{s3T"TJ4nb h60lr.zU|{Mf28B9!,# u,gUަ<ط+Ic ̡oSljlqhqk9R0!i[lRgpE- KpC#ւ /~ @bP(ϻ]3ZH &2ҭ=S Vcr";~pPyKa-&QlÀHaMD10K-KCJwWX/0t%I(|A(*8k'%i0b1Zvt"c*X"%.69F@ILLˉE+fs,͡.KMKzuuԱ&Ԋmڝ (C׀ P*ZF0U!w5 |FT\ LJ,"Ě p4 & ȱl܃G7*i(:H%sv4^ƊIxc&im?bi*&$ Vaaq!l=\#7 .xƒؔ^ebzT##"﷈UHG+W9m sx e:בd"A#$ǀJ.!YZ9 NQ*ZF6M,ٚKx5XQzUNb='J ͷmIMGXXe"(gKI|7Oj>w+RWGȒ`kt3״6{9a1U~?3pjYڤ7?1 S k2 P ([)MlhΖi>&7Dֵf]w.yҤ5Xq܋Z0 3;:d'u\dr6Qi;R.+Jov&MWY|I!S[8:{5hd _Nۨ*"6)*==*)i*$*X  Gb@A{bqYĂEb&  vĮg'UD[TYN(WC:-AjҐl༅659gBjrjETA"\*S:I@b"T瓊 *FDjO߷`UQs|,bDe3a Ueu-i4t R@< Ae|F|q PH,`hIA"*[$XO B=DLrABXIX<$ ء+DC?];rv3ēf>Lhg2qxF~ #~ l&IjE?s2Wc27<9ٹu%_X57}?/Q ¶ZG-#7]¥%Xy!K}A5k`݅sJ P.Ȉ"A8 "VD!(*p!)BA rbXsX7/xc!BX`DA"TAՠjQUW=ehA5ee뚺5| [འ*N, F#Q#"'*(HDƞbTF.b-$eR. "'ptF3QUTUEQNPS^;`'o]dh,6j-pBE4y[3S;m\I:\H}33~ EDi "(ݗ6ő;&ZpL LjH1$)e( ܶm+2~h_٤E,c/({5ԓ5zdd& cWұ &5h-rT)&oa7ujf=\n)y;{`%:z5U/ nb 'ޡQB2H,#w{j=OB}le5"ˆ2b4*ofH&5\'<EOX{Ah`e+l%RUj`,dIJQ+Ak>0Jj&Zo\OFB , P@b c؊(B"A#r}-GoYYq+^ڞav4+Y !VA\`2I>M8IY0Z+#O_3+slӂW_*8[5]_!5`s;ݷ}7c+0" c?$;Xi 6mc ˾1ӄ$`&w -,NB^C+pqSgv{;Yr,PU5/qA2v[XLi&C[DVԆWbwtm1) 0v*A1xOۊ |ʮc \KN9Qal-9iXcYVTut Z3bc %V5'H[FlfPeJ2[>< Insu;D{΂⇋شM uYQ =P|I'3NtCZ.%1 &)vh#ʰ( @#A3 baPjlE($4G+o4~5܆MCV:$ofl9J34f!iǵ,%&#FNq#%yzG{DH +./Dץ_ 4& "  1i $ĕ c,Gz, j21"I9ݬu[oRƞ2o%@}I֭[Ǡ̘^dJdD4D{OE:-Y_ßUIxk~<ɩWL%2J[{IʧNp>A釬zć?s{jཛྷey*jo w{DrIM,.qఉE<%sLBj|(Jkѣ^QBPD%PLj"PyC:֜.Or${8+D&g;OD >B CE겢8J|@ 4*`8b1(`ADX%"RU*|\Z"aX, U% XDTWTr6`0#@$>*QG]uEe*:8'Ht CRĠ J J 1X$bňaUH+DU!Z2PZ(XD '$Y%XZ*|ֺKp&wx3%.KHkm|D5 oa8bK90IE8}MBBF1|뾇X8D%4?GdՖ-鶷0hH纹GImW 7m|mBa߷a>b988Lꆄ`!n5\4b01c #G:XNfCvQ>Ob"W_͖mKFʺA]|i)qvbl|<[ˇ=6%0"i4h3t{Kyu{ V!iJ=@w ZB;= 9]pP%2g0yylPΠ |#ீ׺qF\V.;%K<c}rX%Iv="O,Kq1*mۆ37+@Y9]~=u(c:7jHkvNvso7~xcc/kg^˪m[`ۋ9[ʳc8i'sp }/]\ ..e~glȑ#Gvi 4M. qqTq z\|$`f*j`r@ɡGG}AASMIENDB`klystrack-0.20171212/klystrack/themes/Golden_Brown/0000755000000000000000000000000013214501362020466 5ustar rootrootklystrack-0.20171212/klystrack/themes/Golden_Brown/colors.txt0000644000000000000000000000216613214501362022535 0ustar rootrootbackground = 0x0 main_text = 0xe1d622 small_text = 0xe1d622 button_text = 0xc3ba24 statusbar_text = main_text sequence_counter = 0x000000 sequence_normal = 0x3c2f26 pattern_normal = 0x668ca6 pattern_beat = 0xa0b2c6 pattern_bar = 0xd9def1 pattern_selected = 0xffffff pattern_disabled = 0x333333 pattern_instrument = 0x668ca6 pattern_instrument_beat = 0xa0b2c6 pattern_instrument_bar = 0xd9def1 pattern_volume = 0x68934e pattern_volume_beat = 0xa4c187 pattern_volume_bar = 0xe3f1d9 pattern_ctrl = 0x937b4e pattern_ctrl_beat = 0xc1ae87 pattern_ctrl_bar = 0xf1e8d9 pattern_command = 0x1791a6 pattern_command_beat = 0x00c8e8 pattern_command_bar = 0x97eefc pattern_empty_data = 0x80000000 program_selected = 0xfff4cc program_even = 0x668ca6 program_odd = 0xa0b2c6 instrument_selected = 0xfff4cc instrument_normal = 0x1791a6 menu = 0xc1ae87 menu_selected = 0xe1d622 menu_header = 0x97eefc menu_header_selected = 0xd9def1 menu_shortcut = 0xc1ae87 menu_shortcut_selected = 0xe1d622 wavetable_sample = 0xffffff wavetable_background = 0x0 progress_bar = 0x291f17 catometer_eyes = 0xa04f9b klystrack-0.20171212/klystrack/themes/Golden_Brown/analyzor.png0000644000000000000000000000223613214501362023036 0ustar rootrootPNG  IHDR QTgAMA a cHRMz&u0`:pQ<PLTE6 6 #"#"$"'!, 7 11 87 >8 FN9 V^9 g9 p: y:" :$ :& :( :, :/ :1:3:4:6966646 26 06 /6 -6 -6 ,5 )4 '3 %2 $2 "1 !0 ~z/ v/ q m!j". g#- -.d#c#d#c$d$c#`$]%-Y&V',R'R'P(+M)J)H*+E*+B,A+A,>,?,*;-=-o]bKGDeh pHYs  d_tIME 30<IDATHǍsAGTbF4ر]P$ AD  ݑ1,~vݹ}fYK&^̋ "a}yvm{Db/إ=?JVćlOq7X`b 6*ؤج`m +v(ةإ`b} +(88ంaG$pI sLYH&d*l+N( Fl⤂S ΨYC F\PnpQ%eW\U\SAH Ҋ n(7N0wSW@PGHXOϔ"\AFBKQVN{cqٱl6k7d 7n39|TW|RPON -0<'Ȯ:3,f qXVr!3TQ:~}ͪYR,Ytydwx#ͺW" R!COϯK?Kquxw;( A%4pdơ|~vj-$U.h0Ԯ~Uy-{Yb WT-dpTJ= 2mu 4ZX@rL/TglDQ|&+OB؉nOOdo/zy z5]㓍bL &'H[)A^aK)mtIn&>y,jI~}q(` t|kAe`ǭdmX7+b} j2yф K `nŹ6Aq&,+t8xu_$5SvXy.Ve:Y4$UTJiaGۤmd0=V:=cXZKk^qW\qW mں%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Golden_Brown/font/charmap.txt0000644000000000000000000000023313214501362023606 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Golden_Brown/font/res.txt0000644000000000000000000000000313214501362022757 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Golden_Brown/font7x6/0000755000000000000000000000000013214501362022001 5ustar rootrootklystrack-0.20171212/klystrack/themes/Golden_Brown/font7x6/font.png0000644000000000000000000000130513214501362023454 0ustar rootrootPNG  IHDRӚ1gAMA a cHRMz&u0`:pQ<PLTEz!@bKGDhQ pHYs  d_tIME 30<IDAT8Tq0 #U4@nJ 5#예8caf~a2>w3QANg pg|(azL(QcCC!+B <RHB;M0"UӼ}|^`KK:1xG?h"C8PG؇}ln t n*o*S(M8 rgA!\>L|SڐdHA XI-yƻ_'|+{d 7Ȼϑ~ļ>zJ<*N| (ZT5o;Ed@T,Q3q!5«V2- p72B>8c Hw!aIt$G}6+zOs6%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Golden_Brown/font7x6/charmap.txt0000644000000000000000000000006213214501362024153 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Golden_Brown/font7x6/res.txt0000644000000000000000000000000313214501362023324 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Golden_Brown/vu.png0000644000000000000000000000356013214501362021632 0ustar rootrootPNG  IHDR @LPgAMA a cHRMz&u0`:pQ<PLTE#"$"#!#"#!(!"". - . '5,,==3EFE::OAXHGcPmnmXxx` h g g o u v }       yrsnmjheeab_[}~}}\XzyUuvVRr q Pm!n!Mi"j"i!Je#f#Gb$b#E^$^$EBB[%[%[&@?W&X&=>T';Q(Q(Q'R(R'9N(N(997K)L)5I)H)H*I*3F*D*1~D+C+0} A,B,A+B+/}.} ?,?+?,,}!=,nbKGDmJ pHYs  d_tIME 30<gIDATHeyXq""XIJI"#JR MaCQ9umKYC Gi+I:-{|{RRMYyXI4n IEEYYTURU`IRWS@Cc2! hNEi)VKs diӴ̘Ih,B %4g6TzWJ@_||P-; XflbbB3Li `jjfnfnn_sSS,ҥXY-#de53tram \(ۯ!doZGG및NNGۀf.8yB[m;!WWwN/]^o=zχd2?~ <xf :r :t`6}<  4Iz rϜp ?>Bu!*K\EG(@bR5쥤$$''%p=5-=##FfzzfzFuPxfPx+K%-nA{桋6'|X\ *(B$hТ+PRRZ-)S)+gxTTTV@TU־BUU @]A Oo56]Smm';::>joSLE&wvw zb׏|߃CÃCCC!Chd: Smd%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Golden_Brown/bevel.png0000644000000000000000000000254113214501362022273 0ustar rootrootPNG  IHDR 9gAMA a cHRMz&u0`:pQ<NPLTE1&YI?|CgQ6]PfZ x#aF@('7 HXEnpl=bF\hUG- x<pj&G^W3Ev\ xW xW xW^_ *`vC\ߊ)FZ@|w`din*ƞObb@#k6no׀woXzYY*/Vc|QuMEcԽby޹7(H5.74P~0Rxc$8b6\I6mӔuP>&/3Z#l>Rm_h`>ǶA1e<adsrHmKS7nK[+(@? hLsAqd%gsRJNKoѥ 0[??a 1~ R'eDTX >!p?@w ;/+[}EUB59lCѿ h G4sO۷wN|`9 8Zc ;͕_嶀Zé 9Ň8(bsO䟐LB_7 P+%=U.94(3&'5` F %dS14V0K1_ Qs0U@3p\ D;pg~c=/ä?=vbMqMa=ա h↝(G\o^MÿT@nһ4w#3qEqE_] Iw%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/0000755000000000000000000000000013214501362021671 5ustar rootrootklystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/tiny/0000755000000000000000000000000013214501362022654 5ustar rootrootklystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/tiny/font.png0000644000000000000000000000054713214501362024336 0ustar rootrootPNG  IHDR -cq^gAMA a cHRMz&u0`:pQ<PLTEXbKGDHtIME 30<CIDATc,,#db%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/tiny/charmap.txt0000644000000000000000000000002213214501362025022 0ustar rootroot0123456789abcdef+-klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/tiny/res.txt0000644000000000000000000000000313214501362024177 0ustar rootroot4 6klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/colors.txt0000644000000000000000000000205313214501362023733 0ustar rootrootbackground = 0x000011 main_text = 0x0 small_text = 0xffffff button_text = 0xffffff text_shadow = 0x0 sequence_counter = 0xffffff sequence_normal = 0x0 pattern_normal = 0x3047ff pattern_beat = 0x3047ff pattern_bar = 0x3047ff pattern_selected = 0x0 pattern_disabled = 0x333333 statusbar_text = pattern_normal pattern_instrument = 0x3047ff pattern_instrument_beat = 0x3047ff pattern_instrument_bar = 0x3047ff pattern_volume = 0x3047ff pattern_volume_beat = 0x3047ff pattern_volume_bar = 0x3047ff pattern_ctrl = 0x3047ff pattern_ctrl_beat = 0x3047ff pattern_ctrl_bar = 0x3047ff pattern_command = 0x3047ff pattern_command_beat = 0x3047ff pattern_command_bar = 0x3047ff pattern_empty_data = 0xff000000 program_selected = 0x0 program_even = 0x3047ff program_odd = 0x3047ff instrument_selected = 0x0 instrument_normal = 0x3047ff menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff wavetable_sample = 0xfff000 wavetable_background = 0x0 progress_bar = 0xffffff klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/analyzor.png0000644000000000000000000000167013214501362024242 0ustar rootrootPNG  IHDR Qz8RwT[vG:1!+L>(&NY ezDK !'Į)wnjyRrC(Ipg/=G0DGrp-%} 舆Hkc(1x,jZ jD4r/YPz_{m(lf`@=C U|TVnn^)e0ow:G15 +UL슘6g C•^._0-1xHZzxT#9 2xZKM޾~m9|71[lϫJ\,Q]UKXߎtpN^:ԡ/,P%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/font/charmap.txt0000644000000000000000000000023313214501362025011 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f5\f6\f7\f8\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/font/res.txt0000644000000000000000000000000313214501362024162 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/font7x6/0000755000000000000000000000000013214501362023204 5ustar rootrootklystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/font7x6/font.png0000644000000000000000000000127213214501362024662 0ustar rootrootPNG  IHDR\]gAMA a cHRMz'dv9~: PLTEbKGD- pHYs  tIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/font7x6/charmap.txt0000644000000000000000000000006213214501362025356 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/font7x6/res.txt0000644000000000000000000000000313214501362024527 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Ultimate_Proctamed/vu.png0000644000000000000000000000215413214501362023033 0ustar rootrootPNG  IHDR @gAMA a cHRMz'dv9~:bKGD pHYs  tIME 30<[IDATXåKr0D_˛$TJ9m| T,NĀDQRQ5(ػ]'/^?=?󃯦gB_|4 `$ 7,G V2B<`1L' V`9*jd #3>1XBREQU,c \!"h,big^Y#c"i-~<ͶͪhqRθRa4ŠP{!;5=Gn PC@!Ԑ W'DH`aIHOx@0jh+rrMUXi6\Q*i-'j!O2pWm-/LvjYFmSzAl%s,H(HtQX!dǎr`u^nxX'30u#cP:t, `H/40@343h g@@π)w?w|?A(j'l-ru pwhױLLjX C5h6nI] Zdgk|/yŽ/[l;\ؙxY=?^19.״en6sIqu9 -%.7{&+nrdompFsk# zpcu#5imًeթOy{ g zT6ʖ{z`DICE3`^OX"k` yrGtg:SV{8 WDdlI@z@T i8>"{{8^T9/85/.ODo 7sC?REBwf@G( gKQl@6A2`t a HX̀ׯwCDRH`fOkl6\34. )׮I8V 4͉eT @3D.H! k'B4hkH  >#.͆`u dV3`ƈ723֛(|f?)௫Gw̕N`DKPw>2ʺykZxx6^j<'>I欦LLLjcԜ'%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Blacklyst/0000755000000000000000000000000013214501362020037 5ustar rootrootklystrack-0.20171212/klystrack/themes/Blacklyst/colors.txt0000644000000000000000000000220413214501362022077 0ustar rootrootbackground = 0x0 main_text = 0xffffff small_text = 0xffffff button_text = 0xffffff text_shadow = 0x0 statusbar_text = main_text sequence_counter = 0x820b05 sequence_normal = 0x3eb6a3 pattern_normal = 0x3eb6a3 pattern_beat = 0x00f4cd pattern_bar = 0xffffff pattern_selected = 0x0 pattern_disabled = 0x333333 pattern_instrument = 0xecb34b pattern_instrument_beat = 0xecb34b pattern_instrument_bar = 0xecb34b pattern_volume = 0x3eb6a3 pattern_volume_beat = 0x00f4cd pattern_volume_bar = 0x00f4cd pattern_ctrl = 0x3eb6a3 pattern_ctrl_beat = 0x00f4cd pattern_ctrl_bar = 0x00f4cd pattern_command = 0x3eb6a3 pattern_command_beat = 0x00f4cd pattern_command_bar = 0x00f4cd pattern_empty_data = 0xc0000000 program_selected = 0xffffff program_even = 0x3eb6a3 program_odd = 0x2f8a7c instrument_selected = 0xffffff instrument_normal = 0x3eb6a3 menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff wavetable_sample = 0xffffff wavetable_background = 0x0 progress_bar = 0xffffff catometer_eyes = 0xa04f9b klystrack-0.20171212/klystrack/themes/Blacklyst/analyzor.png0000644000000000000000000000206113214501362022403 0ustar rootrootPNG  IHDR QgAMA a cHRMz&u0`:pQ<bKGD pHYs  d_tIME 30< IDAThݚnA h)hx"*Zx^!@ xJ=-%@Q{vvcOyo}7$=ng7f:u-o`<L8$`#lw6nD Fр+|no>T݊JCcð<DY1V g؞|L"Rp]0 D!i;9@Wo0#@$s>ޫ^DC8V@@j,BnGm6~0էIxٚr u V8Nus0RB*iCzܯ7HA|4Q t-: =s6X MӴ!5oH^ɹî$EA?2-o"df*0P)HiC"{@dgG *G#S%a{ Cj;}>}t!kX'B-/1pe%^IMfZKƭ"*2:"kX@hd1r:ƨ9}vV <¾aX_  מ**KiCr|fhELҠ v0^,V4SH5# \q;9v BHΪ`E_@$OC^T/L1wF ϊ0+z; -~X\6޿s}4 bmu7^$?FG-%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Blacklyst/font/0000755000000000000000000000000013214501362021005 5ustar rootrootklystrack-0.20171212/klystrack/themes/Blacklyst/font/font.png0000644000000000000000000000155413214501362022466 0ustar rootrootPNG  IHDR@=gAMA a cHRMz&u0`:pQ<PLTE2bKGD- pHYsodtIME 30<NIDATH?kA#6*8\M!)\.)1. \]㫮Pe\,kʤTƅCCåH"bYgvO_*훷s;N|9}<ot'ȸJ}du"Ɩ(fg^Yd"S❃J]00i#pes3&|QU,Eq% m"HGW O._\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Blacklyst/font/res.txt0000644000000000000000000000000313214501362022330 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Blacklyst/font7x6/0000755000000000000000000000000013214501362021352 5ustar rootrootklystrack-0.20171212/klystrack/themes/Blacklyst/font7x6/font.png0000644000000000000000000000127213214501362023030 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Blacklyst/font7x6/charmap.txt0000644000000000000000000000006213214501362023524 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Blacklyst/font7x6/res.txt0000644000000000000000000000000313214501362022675 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Blacklyst/vu.png0000644000000000000000000000230213214501362021174 0ustar rootrootPNG  IHDR @{ugAMA a cHRMz&u0`:pQ<bKGD pHYs  d_tIME 30<IDAThޭYA0 N\^ K^nLZ#F5,u$q4" Uh?.C{z=v؛r~iM0bQ;p N >dޛ2^or-u2 , -z W7:oy?`Հ.-Y L& Y €4V="_ONh_4J(WWY$P@8 7{ .Bnh2 ,M@3'؋ʧ0 3Y [| V FE 2V%%Y [ wͨW@s. <<~_O$ vAowtK8/Pjq!u,XIdX$$-1:`]0e155inB+Q i ,X iLWw5CoĪ7b@xٸd15O`˿(m\VUXzU\7 ,n@ 󶥁\l,Hctྼ[Dq=m{݊/ϊifΫ Ӄ5v8cM7ƝjkQO@jR[ 0'V `Հʗ@xE QLƀ['tV/]Dn现 v#-7pblR]к b `"gg 6r%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Blacklyst/bevel.png0000644000000000000000000000246413214501362021650 0ustar rootrootPNG  IHDR 9gAMA a cHRMz&u0`:pQ<QPLTEzzzbbb(#,?99KPK1&&O\XE=&odn.#% JJJ7D/ήibKGDhQ pHYsodtIME 30<IDATx pnvnSVI,v>F"<{CGɧB ;_m[G*k>l}]-_~ߛ~ּkaUHY42SԦ o Bn{f$` GC_{׎*˨)a4ycP@(z>H Ĕx 8β_g>",!P؍c 4" 2)%.H3" "ΈD;#"H3" ",!:Pk kG7_ŭ@3[[9v4C8iͧlW'pti; a+o/Kn:7#nKaDJ7-gPX\_v,"&`UǮci). *wPȊ(dE?}ogr_XFtSs UhWחzo\gsBŹKcۍ5Tx6sb9V|vkp&^bm4F4⒬YKFwGCTXw/f`b:goShD( 0)e)mDgnj @򍗌 ?*m.ХA'2|zpJa?\.^;5 Z;m΂{8x"DIF#`OR `4TЀ\(e@C\<uIKspWz8RwT[vG:1!+L>(&NY ezDK !'Į)wnjyRrC(Ipg/=G0DGrp-%} 舆Hkc(1x,jZ jD4r/YPz_{m(lf`@=C U|TVnn^)e0ow:G15 +UL슘6g C•^._0-1xHZzxT#9 2xZKM޾~m9|71[lϫJ\,Q]UKXߎtpN^:ԡ/,P%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/C64/font/charmap.txt0000644000000000000000000000023313214501362021563 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/C64/font/res.txt0000644000000000000000000000000313214501362020734 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/C64/font7x6/0000755000000000000000000000000013214501362017756 5ustar rootrootklystrack-0.20171212/klystrack/themes/C64/font7x6/font.png0000644000000000000000000000127213214501362021434 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/C64/font7x6/charmap.txt0000644000000000000000000000006213214501362022130 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/C64/font7x6/res.txt0000644000000000000000000000000313214501362021301 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/C64/vu.png0000644000000000000000000000051213214501362017601 0ustar rootrootPNG  IHDR @hgAMA a cHRMz&u0`:pQ<PLTE@1xig}0bKGDhQ pHYs  d_tIME 30<#IDAT8c``R26qqq6VRdQQQQbM%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/C64/bevel.png0000644000000000000000000000241613214501362020251 0ustar rootrootPNG  IHDR 9gAMA a cHRMz&u0`:pQ<BPLTExiUI@1?92grJJJT)WBibPPPxxxbKGDf |d pHYsodtIME 30<IDATx횁b  v]m)B%F~cCA88w pBNhS^@C)\?X\A"$R&#*U$9$W_[ 6~S~p 7Ɖ\ fGpfArrA,pc d=#p 8  {DeL @EDY @E?QEQ9hc[ "hZ @E DoxB7!UDUen-F(H.FP ڲƗWz1xo˱*.B[/zzkWe4Ux+atz>h&I=w1.x!dy[NW 3c8!Ʉ_J] `1CObc#J|Gp R /3&o!.Z[B"Ё&F qV=@1B{s#4?YH7揀ȝh՗7.0=3w?<&c<) !c}K30lF(6Or~ 1Y;a;E02 XLL4I"EVm~'uXߒd̯wǡ ]I.N+I\j`;ƒ](r}(&WLd`Rp!Kɹ|Lᒄ=ُ ǥJ`% #OJµ[*U=@&dAx 9r;8 \s7V|º`_J=tZ}@C,$'Br=1 &s4?!NXG/RPu%;'p`+8QXa/QʽFf ҁfD[\'II$V4 !fTgKi̞2S%x3?>qGXrؚ Ҕn? 9!Dq>gڟJ-y`k\1C" oȱ%_Dns&&@Ka4'aj?mс'˧ {6$'Cs|lYuڙ qMTL&qj65d,˖ʖm<&cK&=h4ɍq7MdZr8WhNT6XlYZr@!Ͻݒ=LwLP "k"-f$A&.i l#r5osʧ]EKi\OຜZȾR&!ZEq"b[2w@h1Tˊj6MG_CF:L%ST0NdB0+nJ3w6?#;;I9L{Wd x/s L/C>kYjnМA~H^ j"Is䱽\&3S)fUIͨKd*RPvh &'uܒϪ)-52gZDi[yꬩ[rmqR-k} 0&E6'5Ϙ:U,/[rvaGCߒђ" VsyQitIa"WU>{ۛkjNNV'ICK@oiԈ[ ZA!eȤKoCmdLM hpTs)fVD&5c1f^h;]άkwvΞϥU"AdAd4f[فVs9#S\'V}ΐs5̽r ZB7[؎dM[T醖l4eͽXG Nfњt&4M@!`*H> ^\螳 mfkM#MG&;D3]D`ueՌ̾:EӚ#_eƴ*7_SHPҨ |Uf O:iS[K5ܒf˗gZS|ͩJj2fLeV4s'Cg1 Dn9UH4,G} spG*:3% {Vof8;EUHzQ0dZ:>/%N5\S<͑/- ]i|­ d8'rs8#S\Zr@ sI8V|t58GցL4h=i.~AaO5_ӾJSvI3rٖx4}C\ih/lP-7LS)<o"w@#'J`*^҉ly']C]F󌂕]Ƨ oL]THRoÞhq ]s6dCuVf*+Au^AL M70@e<4m9f}qzb+ ^"a }6OL~I}ѬCdgrJO7^G 0t\~H~e뇴浮ukڐ7kU@3]]7qأh>'{l毬C̼%G=z7ҁќl w \m4%TJahoXA7Ԝ?Vڥ х?ƶ}e$vue&v eӡ`G!77D&tƶuҌ NO\6o{ c|%nAXy`#A~o|eMw;hNnP5x/+j 0:YUf/np%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/0000755000000000000000000000000013214501362017636 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Red/tiny/0000755000000000000000000000000013214501362020621 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Red/tiny/font.png0000644000000000000000000000054713214501362022303 0ustar rootrootPNG  IHDR -cq^gAMA a cHRMz&u0`:pQ<PLTEXbKGDHtIME 30<CIDATc,,#db%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/tiny/charmap.txt0000644000000000000000000000002213214501362022767 0ustar rootroot0123456789abcdef+-klystrack-0.20171212/klystrack/themes/Rust_Red/tiny/res.txt0000644000000000000000000000000313214501362022144 0ustar rootroot4 6klystrack-0.20171212/klystrack/themes/Rust_Red/colors.txt0000644000000000000000000000207113214501362021700 0ustar rootrootbackground = 0x000011 main_text = 0xffffff small_text = 0xffffff button_text = 0xffffff text_shadow = 0x0 statusbar_text = main_text sequence_counter = 0xffffff sequence_normal = 0x0 pattern_normal = 0x2699ff pattern_beat = 0x2699ff pattern_bar = 0xffffff pattern_selected = 0x0 pattern_disabled = 0x333333 pattern_instrument = 0x2699ff pattern_instrument_beat = 0x2699ff pattern_instrument_bar = 0x2699ff pattern_volume = 0x2699ff pattern_volume_beat = 0x2699ff pattern_volume_bar = 0x2699ff pattern_ctrl = 0x2699ff pattern_ctrl_beat = 0x2699ff pattern_ctrl_bar = 0x2699ff pattern_command = 0x2699ff pattern_command_beat = 0x2699ff pattern_command_bar = 0x2699ff pattern_empty_data = 0x80000000 program_selected = 0xffffff program_even = 0x2699ff program_odd = 0x2699ff instrument_selected = 0xffffff instrument_normal = 0x2699ff menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff wavetable_sample = 0x2699ff wavetable_background = 0x0b2b48 progress_bar = 0xffffff klystrack-0.20171212/klystrack/themes/Rust_Red/analyzor.png0000644000000000000000000000206413214501362022205 0ustar rootrootPNG  IHDR QgAMA a cHRMz'dv9~:bKGD pHYs  d_tIME 30<#IDAThݚ@Mr(DEK-/x^J*JDAh( #IfgglvBXYo<|/ q[,>|:.t[Yمy6qHG0{]׾@k(!Y{SEb^VGFm%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/font/0000755000000000000000000000000013214501362020604 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Red/font/font.png0000644000000000000000000000151113214501362022256 0ustar rootrootPNG  IHDR@=gAMA a cHRMz&u0`:pQ<PLTE2bKGD-tIME 30<%IDATH풡nAGQ5XE'pU8UV'2iQ0DAQ᱒Hs Y Qj*uVE%#SZ 1;I#P !(igH!q"SAWoMH(@Z =JJd&#($Gd%vH(#Ԫ ע1eg/agA@Uu_*xzd1&1XUg)Ue-KLd@ b6|r0qjɽJ8]3TjP+e:TUTt1|'pOt7oyMȘ&zX͘{{s"-cYggߌN>r,X}Tf+G; h4*aڵ w*䦼J4+6PY{΋+aM/EA4WsG^_cPn]>Mq9_aJ fPTY]x4`^U[h/ {]obY;S򹎔%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/font/charmap.txt0000644000000000000000000000023313214501362022756 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Rust_Red/font/res.txt0000644000000000000000000000000313214501362022127 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Rust_Red/font7x6/0000755000000000000000000000000013214501362021151 5ustar rootrootklystrack-0.20171212/klystrack/themes/Rust_Red/font7x6/font.png0000644000000000000000000000127213214501362022627 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/font7x6/charmap.txt0000644000000000000000000000006213214501362023323 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Rust_Red/font7x6/res.txt0000644000000000000000000000000313214501362022474 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Rust_Red/vu.png0000644000000000000000000000230213214501362020773 0ustar rootrootPNG  IHDR @{ugAMA a cHRMz&u0`:pQ<bKGD pHYs  d_tIME 30<IDAThޭYA0 N\^ K^nLZ#F5,u$q4" Uh?.C{z=v؛r~iM0bQ;p N >dޛ2^or-u2 , -z W7:oy?`Հ.-Y L& Y €4V="_ONh_4J(WWY$P@8 7{ .Bnh2 ,M@3'؋ʧ0 3Y [| V FE 2V%%Y [ wͨW@s. <<~_O$ vAowtK8/Pjq!u,XIdX$$-1:`]0e155inB+Q i ,X iLWw5CoĪ7b@xٸd15O`˿(m\VUXzU\7 ,n@ 󶥁\l,Hctྼ[Dq=m{݊/ϊifΫ Ӄ5v8cM7ƝjkQO@jR[ 0'V `Հʗ@xE QLƀ['tV/]Dn现 v#-7pblR]к b `"gg 6r%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/bevel.png0000644000000000000000000000232613214501362021444 0ustar rootrootPNG  IHDR 9gAMA a cHRMz'dv9~:EPLTEΪV8?Q#O!!&222e)'!!MMMbXfcGbKGD a pHYsodtIME 30<yIDATx횋0EGc]m]?U IIP:/aLN'!B(.Tw"}&P J?BQ %7Is}O%jKNhT^w\W=dN{;-rK@wMx JD ; lfU `h.0f_|`e}[)`P60#= Y;V%`JXq,^c15?GiC2MMeBuq89$H]5n;eF^>2y x\R `)[#cHk#<6K tUﱺxzhͱ`c#N{p1$*Q1׼JESu .4A3` \RͭȀn>bܧ~ 3z#sp+|9s@؜W0lϫ1@M'm.=_>D- :tDˀS,f-=!4WUA KZ Z2$$?c"Y`1:)4֙l# (s9砕'!9%SgLGӴ2~w-m^VJz6! @SS2MM5~c%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Rust_Red/catometer.png0000644000000000000000000000512113214501362022326 0ustar rootrootPNG  IHDRP,gAMA a cHRMz&u0`:pQ<!PLTE<6KdLbItgpYOvgbKGD ٥tIME 30< IDAThIsF)B<`3Ѝ5I9M Lnc Q5^/X(57?E_ Wj_bn3#?t_bG4p78yu]#A&_G0A(Q.\.xN|ēMNviJCQI%I!MRM74' }s"8)RH>sx@="39n֡)#9Rs$](iBHyӔ+yEeY+RuOf V_9NW1l""QCMGF(!1۪/n In uK?3\A&y!,\Df鐡ilCNrW*#̍DzA:%Ud`>9E7qŤʆзMI҄Upoxڣ CzfkWwFz Yɚ6*{rjp?.ށ''ĺ,i 8mL=ݼQ$Yyqr wyKz6[$LLbw 2>>)9l(" ~c#0 3|pмu)4%qbi}3[*r&IO(qnGԸ UFIe+޲Z+~ȃYeG4fa[0gUP`g8ۆ'!<4Mk. ͈ҷwX<.@7:hxR˪+b<"^B-9GΦsg0'jP<-/a+^&:~x t'k!v }\q77qEڛbr89Rc9 ۛ1Ơٍh ]~zjyƝby| ;.ք|pޕ{8#]p0Kٝ͒0YǻO SKwBw [Lp{>o2oDJex@a;39N R 0qvIR#ODl;%]{ &8ז c7$~ā"+af ʄz I@ 1-{iy/;ʫn\ޥeo8Ň66m}ٵ+6ʫqb5IN(En5cf[ RmQ G+&O]Ǣ)w*{ a-./Tc FHPޫͼ_Q1ikc9fT'U􇖘ZX&2X&3wzM፝Omj#i3gNFLa ̏/!PN-uW:|$pOӴ3h.)\$bθm»^Ԗdsͼ#SApQ~ br+J^JdYߺ8GO o#ҟ.&˖L=oX33O-.hKBz|տ,WSf+ILR}~i1(s:6LvuϘ]DemyT{!Pm'[ދ<Ϫf GH_ t?jyw-LAۏ-oaL4"ylYHP l{9x8, JV\?k<X^[x/kb2=!`9wyn4ahJm+]V^[xrN~w%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WtEXtSoftwareGrafx2SjIENDB`klystrack-0.20171212/klystrack/themes/Gameboy/0000755000000000000000000000000013214501362017472 5ustar rootrootklystrack-0.20171212/klystrack/themes/Gameboy/colors.txt0000644000000000000000000000132613214501362021536 0ustar rootrootbackground = 0x0 main_text = 0xffffff small_text = 0xffffff statusbar_text = main_text sequence_normal = 0xaaaaaa sequence_counter = 0x000000 pattern_normal = 0xaaaaaa pattern_beat = 0xaaaaaa pattern_bar = 0xffffff pattern_selected = 0xffffff pattern_disabled = 0x555555 pattern_instrument = 0xffffff pattern_instrument_beat = 0xffffff pattern_instrument_bar = 0xffffff program_selected = 0xffffff program_even = 0xaaaaaa program_odd = 0xaaaaaa instrument_selected = 0xffffff instrument_normal = 0xaaaaaa menu = 0xffffff menu_selected = 0xffffff menu_header = 0xffffff menu_header_selected = 0xffffff menu_shortcut = 0xffffff menu_shortcut_selected = 0xffffff catometer_eyes = 0xa04f9b klystrack-0.20171212/klystrack/themes/Gameboy/font/0000755000000000000000000000000013214501362020440 5ustar rootrootklystrack-0.20171212/klystrack/themes/Gameboy/font/font.png0000644000000000000000000000157113214501362022120 0ustar rootrootPNG  IHDR@=gAMA a cHRMz&u0`:pQ<PLTE2bKGD- pHYsodtIME 30<[IDATH풱k1! <CF!h0! d LNC77P:O3 >]Zҩ?N}Ӂ\\ ("jU~ 21p"NrS^ 0qYeTK- ۙF)p0#ω8q:$yH\nkByQ )p[f $kBMydG]d4kC4896J!dF hs|M Lh`RҞ$^b. ,m[`Z% "dQHB:A D=c۶G,F/Q޳O 1+|9tI/h'N>ڴA[A!&47w#̂(;A)7bJYy'`  5CoP6T1V?,T1 8>?!-ЁRU% (Ŀ&ko!`TB_&zcڟV͏ =:?O{ՙnp:.Mt_347V[mO P,%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Gameboy/font/charmap.txt0000644000000000000000000000023313214501362022612 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/Gameboy/font/res.txt0000644000000000000000000000000313214501362021763 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/Gameboy/font7x6/0000755000000000000000000000000013214501362021005 5ustar rootrootklystrack-0.20171212/klystrack/themes/Gameboy/font7x6/font.png0000644000000000000000000000127213214501362022463 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Gameboy/font7x6/charmap.txt0000644000000000000000000000006213214501362023157 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/Gameboy/font7x6/res.txt0000644000000000000000000000000313214501362022330 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/Gameboy/vu.png0000644000000000000000000000050413214501362020631 0ustar rootrootPNG  IHDR @hgAMA a cHRMz&u0`:pQ<PLTE߂Uӊ(abKGDhQ pHYsodtIME 30<IDAT8c`Q@ t%40 mqٳ%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/Gameboy/bevel.png0000644000000000000000000000201513214501362021273 0ustar rootrootPNG  IHDR p`gAMA a cHRMz&u0`:pQ<PLTEUUU^bKGDf |d pHYsodtIME 30<IDAThKr0 INu$fGh'>@P>Hbd3!2 dO?Rd2$7ceg:vo$3Pud5@nc$@N(Gp @r-ygvOaw: 5~_n 0jMUg¥{ ػuh P2>|E7Ou|M~8 >˖@/<(n.>n-傶taO> ַB #qpCJ=_²$&*Ah|`]Zҩ?N}Ӂ\\ ("jU~ 21p"NrS^ 0qYeTK- ۙF)p0#ω8q:$yH\nkByQ )p[f $kBMydG]d4kC4896J!dF hs|M Lh`RҞ$^b. ,m[`Z% "dQHB:A D=c۶G,F/Q޳O 1+|9tI/h'N>ڴA[A!&47w#̂(;A)7bJYy'`  5CoP6T1V?,T1 8>?!-ЁRU% (Ŀ&ko!`TB_&zcڟV͏ =:?O{ՙnp:.Mt_347V[mO P,%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/AHX/font/charmap.txt0000644000000000000000000000023313214501362021647 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ.:-abcdefghijklmnopqrstuvwxyz0123456789(),;#_|+?/`~\[]{}"'%!@$=<>\1\2\3\4\5\6\7\8\9\b\f0\f1\f2\f3\f4\f8\f5\f6\f7\f9\fa\fb\fcklystrack-0.20171212/klystrack/themes/AHX/font/res.txt0000644000000000000000000000000313214501362021020 0ustar rootroot8 8klystrack-0.20171212/klystrack/themes/AHX/font7x6/0000755000000000000000000000000013214501362020042 5ustar rootrootklystrack-0.20171212/klystrack/themes/AHX/font7x6/font.png0000644000000000000000000000127213214501362021520 0ustar rootrootPNG  IHDR\]gAMA a cHRMz&u0`:pQ< PLTEbKGD- pHYsodtIME 30<IDAT(͐A0̼jJS؅e0$9LuŬJ}:A)->5S\Fת( 5\ɦtV(}~4tei· f(Z6dߌ).tqtt]RnDt$;}X:\A86%MbCO,uֵ{Ǫ9i0ʬ?Lt˂SM$sCpq=F YKƞ{zHgɪnjܬH9-9qu$oPZgF;+<Z-ly~}!_>y>fkFV vATA S1,VOyą%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/AHX/font7x6/charmap.txt0000644000000000000000000000006213214501362022214 0ustar rootrootABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-#^/\:+\1\2klystrack-0.20171212/klystrack/themes/AHX/font7x6/res.txt0000644000000000000000000000000313214501362021365 0ustar rootroot7 6klystrack-0.20171212/klystrack/themes/AHX/vu.png0000644000000000000000000000046513214501362017674 0ustar rootrootPNG  IHDR @=gAMA a cHRMz&u0`:pQ< PLTEզbKGDf |d pHYs  d_tIME 30<IDAT(c`Q(tzՈz%tEXtdate:create2017-05-26T13:51:48-07:00%tEXtdate:modify2017-05-26T13:51:48-07:00|WIENDB`klystrack-0.20171212/klystrack/themes/AHX/bevel.png0000644000000000000000000000222513214501362020333 0ustar rootrootPNG  IHDR p`gAMA a cHRMz&u0`:pQ<PLTERZcìprbKGDH pHYsodtIME 30<eIDATh]N0 xTuڝ+@J0ھ: ƴ$R8?#De 9#=)QȒx+>ޱz>Ce>Kĥo)<0 7js=Ae?2n'=]u% 7 ;@4 6WƊ^P"s?1hE5X ps`%́7VX ps`%e8p/s)ckv`OqqC.3^z(&y9[,en嬯N`VjX%l>~EP_P?޵wǤGPM\s5F6G36_\ ~fs(, QӝD3=^þ4Y$<d,GQ d1@cP~HIr*Φ8 S?!Mӟ<]kO 8XÛ1]ُZt > %HEADER% ) @FOR /F "tokens=*" %%d IN ('DIR %DIR%\*.* /A:D /B /S') DO @( set string=%%d set string=!string:%CD%\%DIR%=! echo RMDir "$OUTDIR\!string:~1!" >> %HEADER% ) @EndLocal @goto :EOF :Help @echo. @echo Usage: UNFILES FolderName [OutFile] @echo. @goto :EOFklystrack-0.20171212/klystrack/linux/0000755000000000000000000000000013214501362015761 5ustar rootrootklystrack-0.20171212/klystrack/linux/copyright0000644000000000000000000000210313214501362017710 0ustar rootrootCopyright (c) 2009 Tero Lindeman (kometbomb) 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. klystrack-0.20171212/klystrack/linux/control640000644000000000000000000000073613214501362017544 0ustar rootrootSource: klystrack Section: multimedia Priority: optional Maintainer: Tero Lindeman Build-Depends: debhelper (>= 7), libsdl2 (>=2.0), libsdl2-image (>=2.0) Standards-Version: 3.8.0 Homepage: http://code.google.com/p/klystrack/ Package: klystrack Architecture: amd64 Depends: ${shlibs:Depends}, ${misc:Depends} Description: klystrack chiptune tracker klystrack is a chiptune tracker for creating music in an oldschool video game style. klystrack-0.20171212/klystrack/linux/control0000644000000000000000000000073513214501362017371 0ustar rootrootSource: klystrack Section: multimedia Priority: optional Maintainer: Tero Lindeman Build-Depends: debhelper (>= 7), libsdl2 (>=2.0), libsdl2-image (>=2.0) Standards-Version: 3.8.0 Homepage: http://code.google.com/p/klystrack/ Package: klystrack Architecture: i386 Depends: ${shlibs:Depends}, ${misc:Depends} Description: klystrack chiptune tracker klystrack is a chiptune tracker for creating music in an oldschool video game style. klystrack-0.20171212/klystrack/linux/Makefile0000644000000000000000000000076313214501362017427 0ustar rootroot# linux installer makefile TARGET=klystrack RES_PATH = $(DESTDIR)/usr/lib/klystrack install: @mkdir -p $(DESTDIR)/usr/bin @cp -f $(TARGET) $(DESTDIR)/usr/bin/$(TARGET) @mkdir -p $(RES_PATH) @cp -Rf res $(RES_PATH) @cp -Rf key $(RES_PATH) @cp -Rf examples $(RES_PATH) @mkdir -p $(DESTDIR)/usr/share/doc/klystrack @cp LICENSE $(DESTDIR)/usr/share/doc/klystrack @cp SDL.txt $(DESTDIR)/usr/share/doc/klystrack @cp SDL_image.txt $(DESTDIR)/usr/share/doc/klystrack clean: klystrack-0.20171212/klystrack/examples/0000755000000000000000000000000013214501362016440 5ustar rootrootklystrack-0.20171212/klystrack/examples/songs/0000755000000000000000000000000013214501507017572 5ustar rootrootklystrack-0.20171212/klystrack/examples/songs/smp_dingleberries_fix.kt0000644000000000000000000006267113214501362024510 0ustar rootrootcyd!song@3866Psmp_dingleberries(MkIO(@2^j&L.(|^&(tLMN 3"3"3"3" /-=/ n00bstar /=->t4 $- four channels#0"_ - no samplespF)""_"" - (lots of) beer0  0  @ π0 greets to the people over at dbf 5 0you guys can used this track in Bn0 your prods in you want. i've put @ ^ a bunch of little hooks all over2  0the place so you can sync your  @ routines to the music. enjoy!P < `!!`"" <random_zak@hotmail.com 5 0 @!!`"" < 5 0 A _! 2  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  0@0@ @@@!@"'''@'''-+ 7@ 7 7 < 7@ 7 7 < 7@ 7 7 @ '@ ' ' ' '@ ' ' 'M@@@@/@@#@,...@.14 8@ 8 8 ; @    @   B @    @   N@ @ @@@$)+(@((((@(25 (@ ( ( : @    @   A D@ D E G D@ D E GI@JIJ@ @  @  @ @%*@***&@&&&&@&36 &@ & & 9 =@ > = ? =@ > = ? C@ C F H C@ C F HK@LKL@000000000000000000000 00 00@ 0` 00@ 00@ 0000 00 0@ 00 00 00@ 0` 00@ 00@ 0000 00@0000000000000(( (( ((-./(( (( (242+@                      !  "  #  "  !                        !  "  #  &  #  @4    4    7  4    4    ;  :  9  4    2  3  4    4    7  4    4    3  2  /  .  -  +    @0000000000000000000 00 00@ 0` 00@ 00@ 0000 00 0@ 00 00 00@ 0` 00@ 00@ 000@000000000000(( (( ((-./(( (( (242@                      !  "  #  "  !                        !  " @4    4    7  4    4    ;  :  9  4    2  3  4    4    7  4    4    3  2  /  . @  4  4    4  4    4  4    4  4    4  4      4  4    4  4    4  4    4  4    4  4    @0001010000000110100000( 4@+ ;@( 9+ 7& + 44@+ @4- + 23@000000000000000000000<00<00<<<0<00<00<<<@ @0 @00 @000000000000000000000 00 00@ 0` 00@ 00@ 0000 00 0@ 00 00 00@ 0` 00@ 00@ 0000 00@00000000000000000000<00<00<<<0<00<0000@00p00p0000p00w11111( ` 44  `(  4 ` &&  `2  + ` 77  ( ` 44  `(  4 ` --  !`;@C IE =9 @1111111100004  4  @4  2  > (  /  @(  -  @/  .  @+  (  4  @2  (  > &  (  @&  (  7 1-&(@0000000000(( (( ((-./(( (( (@0000- + 23@0000000000000++ ++ ++-./-- -- -./24@  7   7    7   7    7   7    7   7  !  :   ;  #  !  9   9  !  9   9  !  9   9  !  ;   ;    >   4    @0001010000000110100000( + 7 + ;7 ( 9+ 7& + 4- 9 + 9 4- + 23@0001010000000110102 + 7 / ;7 . 9- 7+ & 4- 9 ( 9 4@00000000  7   7    7   7    7   7    7   7  !  :   ;  #  !  9   9  !  9   9      4 / - / - + ( + @00000000000++ ++ ++-./-- -- -2 4 @000000000000000000000 00 00@ 0` 00@ 00@ 0000 00 0@ 00 00 00@ 0` 00@ 00@ 0000 00@011000011000(@4-./(@4&&'@4  4    4  2    (  /    (  -    /  .    +  (  4    2  (    &  (    &  (    +  7    9  @000000004 42 4 4 42 7 @0  7   7    7   7    7   7    7   7  !  :   ;  #  !  9   9  !  9   9      0@0000000000000000000000000000@000000004 42 4 :0; :9 7 @00000000000000 00 00@ 0` 00@ 00@ 0000 00 0@ 0T T@000000000000p000000000000 00 @01100000000(@4-.//.-+(@4  4    4  2    (  /    (  -    /  .    +  ;    9  :    7  9    4  7    2  4    (O@OOO@0000000004 42 4 ; : 9 7 4 @10110110110110111011011011711111((@2(> 4(@+(@-9+/(-@2.> 4/@(4;@C IE =9 @00000000000000000<<<<<<<<<<<<<<<<<@00004  4    4  2    (  /    (  -    /  .    +  (  4    2  (    &  (    &  (  7 1-&(@@1111111111111@> @@@@> @;@C IE =9 @0<@0H @0H@0p00p00p00p00p000p00p00p00p00p00(`44`(4`&&`2+`77(`44`(4`--!`9&`22@0000000000++ ++ ++-./-- -- -@000000000000000000000 00 00@ 0` 00@ 00@ 0000 00 0@ 00 00 00@ 0` 00@ 00@ 0000 00@0p00p00p00p00p000p00p00p00p00p00(`44`((`44`((`44(`44`((`44`((`44@4  4    4  2    4  4    4  2    4  4    4  4  4    4  2    4  4    4  2    4  4    4  @10110110110110111011011011011011((@2(> ((@2(> ((@2((@2(> ((@2(> ((@2@0p00p00p00p00p000p000p000p000p00(`44`((`44`((`44((`((((`((((`((((`((@p4  4    4  2    4  4    4  2    4  4    4  (@/@///////@10110110110110110((@2(> ((@2(> ((@2(////////@00000000000000000000000000000000$000$0000000$000$000$0000000$000@00p00p0000p00p00( ` 44  `(  4 ` &&  `2  + ` 77  ( ` 44  `(  4 ` --  !`9  & ` 22  @101101101101101110110110111111((@2(> 4(@+(@-9@/(-@2.> 4/@;@C IE =9 @00004  4    4  2    (  /    (  -    /  .    +  (  4    2  (    &  (         1-&(@00p00p0000p00( ` 44  `(  4 ` &&  `2  + ` 77  ( ` 44  `(  4 ` -        @00000000000000000000000000$000$0000000$000$000$0000$@000001qq00000pp( 4424(4 (@(44279000090 9 @00000pp00;p000p0p( 4424 40 4+  (  9:000: :90090 007  4  220--0@00000p10;0;000( 4424404(   9;000>;9000744@00000000000000000$000$0000000$000$@111114  4  @4  2  > (  /  @(  -  @/  .  @+  (                 @00p00p00011111( ` 44  `(  4 ` &&  `2  + ` 77  (  ;@C IE =9 @010101000010101011111/ @/ > / @/ 1 1 2 @2 > 2 @1 ;@C IE =9 @000000000000000000+ @ + 4 + + - - / @ / 4 / - - E 9 E @00000000000000000+ @ + 4 + + - - / @ / 4 / - - / / @000000000000000000011111/ ( / / / 4 / / 1 + - 1 2 - 2 - 2 - 1 ;@C IE =9 @00000000000000000+ @ + 4 + + - - / @ / 4 / - - + ( @000000000000000000011111/ ( / / / 4 / / 1 + - 1 2 - 2 - 2 / 1 ;@C IE =9 @00000000000000000+ @ + 4 + + - - / @ / 4 / - - / / @00000000000000000+ @ + 4 + + - - / @ / 4 / - - + ( @000000000000000000000/ ( / / / 4 / / 1 + - 1 2 - 2 - 2 - 1 / / @000000000000000000000/ ( / / / 4 / / 1 + - 1 2 - 2 - 2 / 1 / / @00@0(@0@0@0@0@0@0@0@0@0@0@0@0@0@0klystrack-0.20171212/klystrack/examples/songs/smp_dpintro.kt0000644000000000000000000002277513214501362022504 0ustar rootrootcyd!song@A#)@ 2 smp_dpintro(jvh|sE$-z (@>p(dyDi5 c(@P @D  3"3"3"3" 0Dancing Pixels L by n00bstar "_p`ppp@ 5-four channels   0 -no samplesJ 0-all klystrackm π0 0random_zak@hotmail.com  \0 contact me if  0you need music  0for you project <@` ! < P! 0A tt_O^v0`?! <@@@@,@)%@%%2%@%%% =@ = = 5 9@@ @@@@-@*/&@&&3&@&&8 >@ > > 6 :@  @"@1#@$#$(?7@77' 7@ 7 7 7 ;@@    @    @   @! . @+ 0@@ 4@ 4 4 4 <@00000000000000300000000000000000<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  @0000000000<< << <<<<< << << << << << @880008880808800888< H 0<0 K??0< H << > ?00C A? <>PP2 &>0 J00> 2 > C 77C7C 7 @,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  .  .  .  .  .  .  .  .  /  /  .  /  /  /  /  /  @00000000000000<< << <<<<< << << <<<<<<@88080888088088080880? 0 8? <8? <008 3 <8 3 <>``?``5 > :A 2:A >/@00000000000000300000000000000000<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@0  3  7  3  <  3  7  3  0  <  7  3  <  3  7  3  +  .  2  .  7  .  2  .  +  7  2  .  7  .  2  .  @880808880808< ! 0 3 7 < !0  3 7  < !0 3  7 < ! 0 3 7 : ! + 2 7 : !+  2 7  : !+ 2  7 : ! + 2 7 @,  0  3  0  8   0  3  0  ,  8   3  0  8   0  3  0  .  2  5  2  :   2  5  2  /  :   5  2  :   2  5  2  @8808088808088 ! , 0 3 8 !,  0 3  8 !, 0  3 8 ! , 0 3 : ! . 2 5 : !.  2 5  ; !/ 2  5 ; ! / 2 5 @0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  @,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  .  .  .  .  .  .  .  .  /                @03000003030030030300000303003003<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@03000003030030030300000303003000<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@8800080888880008088< ) 0 3 7 < 0  3 7  < 0 3  7 < 0 3 7 : + 2 7 : +  2 7  : + 2  7 : + 2 7 @0<@000000000000000000000000000000000000000000000000++++++++++++++++@00000000000000000000000000000000,,,,,,,,,,,,,,,,........////////@0< @0  0  0  0 0 0  0  0  0  0  0  0  0 0 0  0  0  0  +  +  +  + + +  +  +  +  +  +  +  + + +  +  +  +  @,  ,  ,  , , ,  ,  ,  ,  ,  ,  ,  , , ,  ,  ,  ,  .  .  .  . . .  .  .  .  /  /  /  / / /  /  /  /  @,  ,  ,  , , ,  ,  ,  ,  ,  ,  ,  , , ,  ,  ,  ,  .  .  .  . . .  .  .  .  /  /  /  / / /        @00 @0000000000000030000000000<<<<<<<<<<<<<<<<<<<<<<<<<<@00@00000000000000000000HFH<?HFH<?JHJ<?JHJOM@00000000000000000000HFH<?HFHFHJKJFCMKJGF@8808088808088 " , 0 3 8 ",  0 3  8 ", 0  3 8 " , 0 3 : " . 2 5 : ".  2 5  ; "/ 2  5 ; " / 2 5 @,                                                                @000< 00@<` @ <` @ <` @ H ` @ < ` @ H ` 7` @ 7` @ 7` @ C ` @ 7 ` @ C ` @8 ` @ 8 ` @ 8 ` @ D ` @ 8 ` @ D ` : ` @ : ` @ F ` @ : ` @ : ` @ F ` @0000000000000000000HFH<?HFHFHJKJFCMKJG@0000032.@00000000232532@0000000000000000000000000000030000000000000<0<00000000000<0<0<<0<@000000000000000000000000< 0000< 0000< ........@888888888888888888H H   H H   H H   H H   H D C ? < <   < <   < < 0                @0                                @03000003030030030300000300000<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@<74@00000000000000000000000000000000,,,,,,,,,,,,,,,,........////////@8 ` @ 8 ` @ 8 ` @ D ` @ 8 ` @ D ` : ` @ : ` @ F ` @ : ` @ : ` @ F ` @03000003030030030;0;0;0;0<<<<<<<<<<<<<<<<<<<<<<<<P <::P :77P 733P 3@00000000000000000,,,,,,,,,,,,,,,,0@000000008 ` @ 8 ` @ 8 ` @ D ` @ 8 ` @ D ` : ` @   <<887733@0000000000000000000000000,,,,,,,,,,,,,,,,........0@8 ` @ 8 ` @ 8 ` @ D ` @ 8 ` @ D ` : ` @ : ` @ F ` @ : ` @    @0000000000000000000HFH<?HFHFHJKJFCMKJG@00000000000000000000000000000000000000000<0<0000000000<<:::@ 77@0000000000000;00;00000< 0000< 0000< ::: :@ :` 7733P 3@<  <  ?  C  <  >  ?  <  >  ?  <  D  >  <  C  D  ?  <  D  F  <  D  F  <  F  C  <  <  F  <  ?  <  @03000000030000000300000000000H0<0HH000H0<0<H<00H0<0HH000<<::883@0000000000000000 000000<H0000<K0000<H< < <: : :8 8 83 3 3@888888888888888888888888H H   H H   H H   H H   H D C ? < <   < <   < <   : :   : : ; ; @0000000000000000< 0000< 0000< 0               @0H@0$@00 @00@03000000030000000300000003000000H0<0HH000H0<0<H<00H0<0HH000H0<0<H<00@00000000000000000000000000<H0000<K0000<H......F@0H @0<klystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/0000755000000000000000000000000013214501362023036 5ustar rootrootklystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/Oscillators_And_Wavetable.kt0000644000000000000000000000661413214501362030457 0ustar rootrootcyd!song@2Oscillators_And_Wavetable0          0Change Oscilators0 ; ; ; 0Different Pitch (wave 08-0A)0 ;;;;;;;; 0Change Wave Item (wave 00-07)@@00@00@00<07+ - BT"խOVXU%RK_Q}tą-%ETuXET$0Qi$у-˖pF_/yaD_/ٲq"B^-m1WK[ B^-m!D[+v"*zL(,<: 6!d =!dk-O@BZB098ET WDE-ST2U8DE-SQ CT,ʲ뿂cXqs"F$ACq2ؐ(< D(B3$*- IۮyH_%%eSD/7!eTe\N dZ^1`` ֪AP2 IPl9YԝL]iaD/Ē*EDz"~a0"C,TT_KKHz:PB\J%YdtK:-I,QX!"IuUZUlB#u±,$JDJl[V۲l@E0 (]2& E e 4 րdP;z$D n-2>3*GgB90>3*GgB9 LTEx&| LTEx&|, 4p+ 4`j 4p+ 4`r20%8s %8s20%8s %8U̪j-U̪*U̪j-U̪*I6sx9I63x1I6sx9I63x19ۄ0(؄0(؄0(؄0(GBrƑq$,$g 5d dd dd dd d6X AbAA 8hE>T! 4dH JA/Hpa`A? |  .-bG]*W(HDn%qPFոV)Pߡzx&ϫ@;^ jUꛫ@-yOdpsyݜ *{vn{[NRw~ofe=pOjpYk5䖅*٭B),b29lC4hh4Lݜ#H='~G;% ̆ݞL v2zB$rms бuH`qsqB,Z,۠>:ҫ5>v cf%S;.7 ^ҵU,%2쯢d@Bw6<+R<>X goe=(^FA8o!@t-(svOཚ$3]-2qY5l@љ̼i۫l-_Y !M~_Xr7hXj|&[VO:(*|8"IF%|1FE".Fa@wl۟'WlFF9DM/k@xkNMq_8kD~K@Sd:~GAFKGaa3&= X3 GۂX3+c*)J1kX{PrJ[iWBhDA fN`SU)i$U MQ~̮}sHeҞ8LiCxyjsIxp<Gß3/m)(%"jeIQJą1)Mr0S:8iLzYti0XńB9C`H16- @r-{!Wyf5/,+a炴vm*V`O -Y]m+bSĊVZ2ek먳uMdmEB)Rrݪ] 1d*nqU9T^Xh{cO\+D|VՒpc{6U+_U8 ~M~z|U֗p ɭ|Sz OnU*RÓNBVբ>95x1]2vr]U EC2 [,DxL!hDmE`2EQ.LF/ &# !b 0341&A1v4ڠX @~-X0sC2^@4^@6^@klystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/Multiplex.kt0000644000000000000000000000060613214501362025363 0ustar rootrootcyd!song@@2 Multiplex0 P 0First Instrument0  /`Second Instrument@00000325@00004769@00007:9<@0000:<;?klystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/Arps.kt0000644000000000000000000000162113214501362024303 0ustar rootrootcyd!song@2Arps0  0Speed 20  0Speed 10  0Speed 60  0Four Notes up/down0  Four Notes always up0   0Fixed Octave Arp@@@00Pp7GH@00Pp7GH@<77X3I<77X3I<77X3I<77X3I@0007.G,+@0GHIH@00000000@0000$0+'klystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/Buzz.kt0000644000000000000000000000063613214501362024335 0ustar rootrootcyd!song@2Buzzp  0Main Instrument@@@00p:q:r:s:t:u:v:w:x:y:z:{:|:}:~::::::::::::::::::::::::::::::::::@@<p::::p::::p::::p::::@klystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/Ringmod.kt0000644000000000000000000005421513214501362025004 0ustar rootrootcyd!song@2RingMod(2^j&L.(2^j&L.(2^j&L.(2^j&L.(2^j&L.(2^j&L.(2^j&L.(2^j&L.0  0Main Instrument0 0Silent Instrument2  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  02  0@@@00@000000000$                0357:<:7@0<@T0000000000000000000000000000000000000000000000000000000000000000klystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/Sync.kt0000644000000000000000000000102413214501362024307 0ustar rootrootcyd!song@2Sync0  0Main Instrument2  0Silent Instrument@@@00@00000000"+.7:@T@0000000000000000$+07<C$+07<Cklystrack-0.20171212/klystrack/examples/songs/n00bstar-examples/FXBus.kt0000644000000000000000000000272713214501362024375 0ustar rootrootcyd!song@ 2FXBus Simple Chorus(@2^j&L. Stereo Doubler (tap0 = 1 to 5ms)(Slapback(< Tempo Delay(jL.Fast Vibrato Chorus @2^j&L. Downsampler(2^j&L. Mangler^&Fake Distortion(2^j&L.0  0To FX00  0To FX10 0To FX20 0To FX30  0To FX40  0To FX50  0To FX60  0To FX7@@@000$@000$@000000000$0$0$0$@0000000$00$0@00000$0$@00000000<:73$0$0@0000TH<0@0000$,$,@000000000000320320875875klystrack-0.20171212/klystrack/examples/instruments/0000755000000000000000000000000013214501362021033 5ustar rootrootklystrack-0.20171212/klystrack/examples/instruments/stabmin.ki0000644000000000000000000000010113214501362023005 0ustar rootrootcyd!inst2B $Minor stabOklystrack-0.20171212/klystrack/examples/instruments/cowbell.ki0000644000000000000000000000007113214501362023005 0ustar rootrootcyd!inst:+Cowbellklystrack-0.20171212/klystrack/examples/instruments/kick.ki0000644000000000000000000000007713214501362022305 0ustar rootrootcyd!inst8Bp4Kickklystrack-0.20171212/klystrack/examples/instruments/lethal_kick.ki0000644000000000000000000000073013214501362023632 0ustar rootrootcyd!inst2  0 lethal kick@0 wZ2>ҨcJB ѐ5،&bZ.JDӿdy^7@aX)##c+zaC(Ao!d:BtOc"fJKki뻶21DjE5P1ܰBvJQ ފ'C%]"o''(u)tkz sQy}Y$M,(ūJD6ADw\, rH/(3jf1k +"^bdRA8K2 4'X7(Bd5D %YEIB AFk CJha1W D`Rx dd$VIi%C"qD&:-HS(<klystrack-0.20171212/klystrack/examples/instruments/bass2.ki0000644000000000000000000000010113214501362022362 0ustar rootrootcyd!inst0 @-b Bv$Bass 2klystrack-0.20171212/klystrack/examples/instruments/bigsnare.ki0000644000000000000000000000010113214501362023142 0ustar rootrootcyd!inst>  :`/Big snareklystrack-0.20171212/klystrack/examples/instruments/bass.ki0000644000000000000000000000010313214501362022302 0ustar rootrootcyd!inst0 X $Bass/bassassbklystrack-0.20171212/klystrack/examples/instruments/clap.ki0000644000000000000000000000011313214501362022272 0ustar rootrootcyd!inst:D   @ Clap?klystrack-0.20171212/klystrack/examples/instruments/ssnare.ki0000644000000000000000000000010513214501362022647 0ustar rootrootcyd!inst >Tt@4 $Simple snareklystrack-0.20171212/klystrack/examples/instruments/snappy.ki0000644000000000000000000000013413214501362022670 0ustar rootrootcyd!inst8@  8 Snappysnareklystrack-0.20171212/klystrack/examples/instruments/dang.ki0000644000000000000000000000011513214501362022266 0ustar rootrootcyd!inst6"7;0Dang0Eklystrack-0.20171212/klystrack/examples/instruments/MontyKick.ki0000644000000000000000000000014013214501362023263 0ustar rootrootcyd!inst0      0 MontyKickklystrack-0.20171212/klystrack/examples/instruments/JDsnare.ki0000644000000000000000000000013113214501362022701 0ustar rootrootcyd!inst :   ,JD Snareklystrack-0.20171212/klystrack/examples/instruments/hardkick.ki0000644000000000000000000000010513214501362023134 0ustar rootrootcyd!inst:C  p 4Hard kickklystrack-0.20171212/klystrack/examples/instruments/lethal_snare.ki0000644000000000000000000000102313214501362024015 0ustar rootrootcyd!inst20  0 lethal snare@40 Cq42 *p! 06QRuS'q;FGK=""%RM%ZtTMKrRNHҒ~SO#"H鄍?N1+PD( M47QN$"tB.5۵M#>K+[@iF"pǏ_(¡zKy~keMDo59D,NL{UQm]岤DK-;NQ$8y+]fx*I%t"]'2IZٴge"OU**v$Wta%KEEu.I.%njW"ItR&o9'ͨj@գx cqG 3IB4ֺRZ,Fvey]9_KZJ/@ !ⱒBA;_QNc+6VͺI3+#[յklystrack-0.20171212/klystrack/examples/instruments/tom.ki0000644000000000000000000000010513214501362022153 0ustar rootrootcyd!inst 6Tt@4 5Tomklystrack-0.20171212/klystrack/examples/instruments/vibbas_flt.ki0000644000000000000000000000014713214501362023475 0ustar rootrootcyd!inst 6  @!-b Bv$Vibbass filterediklystrack-0.20171212/klystrack/examples/instruments/wetkick.ki0000644000000000000000000000013113214501362023014 0ustar rootrootcyd!inst :  "Wet kickklystrack-0.20171212/klystrack/examples/instruments/lead1.ki0000644000000000000000000000010313214501362022340 0ustar rootrootcyd!inst4   !@h0Weird leadklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/0000755000000000000000000000000013214501362025055 5ustar rootrootklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Hihat_3_Open.ki0000644000000000000000000000054313214501362027644 0ustar rootrootcyd!inst8   _ Hihat_3_Open-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bassdrum_06.ki0000644000000000000000000000054613214501362027474 0ustar rootrootcyd!inst8B + Bassdrum_06-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_External_SustainedPWM.kiklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_External_SustainedPWM.k0000644000000000000000000000021013214501362032211 0ustar rootrootcyd!inst0 0Arp_External_SustainedPWM2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_Fixed_Minor.ki0000644000000000000000000000017613214501362030413 0ustar rootrootcyd!inst0 0Arp_Fixed_Minor2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Hihat_1_Closed.ki0000644000000000000000000000054113214501362030150 0ustar rootrootcyd!inst8 _Hihat_1_Closed-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Hihat_2_Open.ki0000644000000000000000000000053713214501362027646 0ustar rootrootcyd!inst8 _ Hihat_2_Open-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/FX_VinylRecord.ki0000644000000000000000000000022313214501362030234 0ustar rootrootcyd!inst|C    @    @?FX_VinylRecord@2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Hihat_1_Open.ki0000644000000000000000000000053713214501362027645 0ustar rootrootcyd!inst8 _ Hihat_1_Open-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Snare_03.ki0000644000000000000000000000054513214501362026760 0ustar rootrootcyd!inst8B0 +Snare_03`-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_FM.ki0000644000000000000000000000057513214501362026663 0ustar rootrootcyd!inst0  0Bass_FM -2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z !$J@klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Pulse.ki0000644000000000000000000000014713214501362027444 0ustar rootrootcyd!inst0 $ Bass_Pulse!$J@klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Clap_01.ki0000644000000000000000000000053613214501362026565 0ustar rootrootcyd!inst:A <Clap_01`-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_DigitalBells.ki0000644000000000000000000000062113214501362030665 0ustar rootrootcyd!inst4  0Lead_DigitalBells-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_VibraSquare.ki0000644000000000000000000000017313214501362030554 0ustar rootrootcyd!inst4  0Lead_VibraSquare 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_OctaveArpBleep.ki0000644000000000000000000000020413214501362031157 0ustar rootrootcyd!inst0  0Lead_OctaveArpBleep2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Instrument_Trombone.ki0000644000000000000000000000020413214501362031413 0ustar rootrootcyd!inst2   0Instrument_Trombone2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Tom_02.ki0000644000000000000000000000053713214501362026447 0ustar rootrootcyd!inst0`  <Tom_02-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Shifting.ki0000644000000000000000000000016013214501362030122 0ustar rootrootcyd!inst0   $ Bass_Shifting !$J@Zklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bassdrum_03.ki0000644000000000000000000000054613214501362027471 0ustar rootrootcyd!inst:p 0 Bassdrum_03-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Snare_05.ki0000644000000000000000000000055113214501362026757 0ustar rootrootcyd!inst8B 0P! +Snare_05-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_PulseToSquare.ki0000644000000000000000000000017513214501362031106 0ustar rootrootcyd!inst4  0Lead_PulseToSquare2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Deep.ki0000644000000000000000000000057713214501362027240 0ustar rootrootcyd!inst0J  $ Bass_Deep-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z !$J@klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Clap_02.ki0000644000000000000000000000054213214501362026563 0ustar rootrootcyd!inst:@  <Clap_02`-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bassdrum_05.ki0000644000000000000000000000054613214501362027473 0ustar rootrootcyd!inst8D0 0 Bassdrum_05-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Pad_ThinDigital.ki0000644000000000000000000000016613214501362030371 0ustar rootrootcyd!inst4  0Pad_ThinDigital 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_External_OscSweep.ki0000644000000000000000000000022613214501362031576 0ustar rootrootcyd!inst0        0Arp_External_OscSweep2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_DoubleSquare.ki0000644000000000000000000000015613214501362030747 0ustar rootrootcyd!inst0B Bass_DoubleSquare!$J@Zklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/FX_PowerUp.ki0000644000000000000000000000017313214501362027401 0ustar rootrootcyd!inst8 $ FX_PowerUp2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Filtered.ki0000644000000000000000000000016013214501362030105 0ustar rootrootcyd!inst0  $ Bass_Filtered!$J@Z././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_External_PhasingSquare.kiklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_External_PhasingSquare.0000644000000000000000000000025113214501362032272 0ustar rootrootcyd!inst0 0Arp_External_PhasingSquare -.iPfXf2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Hihat_2_Closed.ki0000644000000000000000000000054113214501362030151 0ustar rootrootcyd!inst8 _Hihat_2_Closed-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Pad_LongRise.ki0000644000000000000000000000017313214501362027711 0ustar rootrootcyd!inst4 ! 0 Pad_LongRise 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_Fixed_Major.ki0000644000000000000000000000017613214501362030377 0ustar rootrootcyd!inst0 0Arp_Fixed_Major2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Picked.ki0000644000000000000000000000016013214501362027546 0ustar rootrootcyd!inst0""  $ Bass_Picked`!$J@Zklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bassdrum_04.ki0000644000000000000000000000054613214501362027472 0ustar rootrootcyd!inst8Dp 0 Bassdrum_04-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/FX_BreakGlass.ki0000644000000000000000000000017013214501362030013 0ustar rootrootcyd!inst8H  ~H FX_BreakGlass 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Tom_03.ki0000644000000000000000000000053713214501362026450 0ustar rootrootcyd!inst" HTom_03-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Snare_04.ki0000644000000000000000000000054713214501362026763 0ustar rootrootcyd!inst:B 0  +Snare_04`-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_Fixed_Dim.ki0000644000000000000000000000017413214501362030036 0ustar rootrootcyd!inst0 0 Arp_Fixed_Dim2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_Buzz.ki0000644000000000000000000000016013214501362027256 0ustar rootrootcyd!insttB  < Lead_Buzz2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Snare_06.ki0000644000000000000000000000055113214501362026760 0ustar rootrootcyd!inst8L 0P" 0Snare_06-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_Fixed_Aug.ki0000644000000000000000000000017413214501362030041 0ustar rootrootcyd!inst0 0 Arp_Fixed_Aug2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_HPF_SawFifths.ki0000644000000000000000000000017513214501362030725 0ustar rootrootcyd!inst4  ! 0Lead_HPF_SawFifths2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Snare_02.ki0000644000000000000000000000054513214501362026757 0ustar rootrootcyd!inst:B@ 0Snare_02`-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Tom_01.ki0000644000000000000000000000054113214501362026441 0ustar rootrootcyd!inst2@ HTom_01-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_Fixed_Dom7th.ki0000644000000000000000000000020113214501362030456 0ustar rootrootcyd!inst0  0Arp_Fixed_Dom7th2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_Fixed_Sus4.ki0000644000000000000000000000017513214501362030164 0ustar rootrootcyd!inst0 0Arp_Fixed_Sus42s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Hihat_3_Closed.ki0000644000000000000000000000054513214501362030156 0ustar rootrootcyd!inst8   _Hihat_3_Closed-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_FM_Sync.ki0000644000000000000000000000016713214501362027631 0ustar rootrootcyd!inst4  0 Lead_FM_Sync 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Aggro.ki0000644000000000000000000000015313214501362027410 0ustar rootrootcyd!inst0  $ Bass_Aggro!$J@Zklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/FX_DriveBy.ki0000644000000000000000000000016513214501362027345 0ustar rootrootcyd!inst<B0 FX_DriveBy2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Instrument_Trumpet.ki0000644000000000000000000000025413214501362031273 0ustar rootrootcyd!inst0H 0  0Instrument_Trumpet!s`W2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Snare_01.ki0000644000000000000000000000054513214501362026756 0ustar rootrootcyd!inst:@@ $Snare_01`-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Arp_External_Short.ki0000644000000000000000000000025213214501362031144 0ustar rootrootcyd!inst0  0Arp_External_Shorts`W2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bass_Sustained.ki0000644000000000000000000000015713214501362030314 0ustar rootrootcyd!inst0   $Bass_Sustained!$J@Zklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Instrument_Strings.ki0000644000000000000000000000024613214501362031265 0ustar rootrootcyd!inst4  P0Instrument_Stringss`W2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_ShortFMSquare.ki0000644000000000000000000000017113214501362031031 0ustar rootrootcyd!inst0 0Lead_ShortFMSquare 2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Pad_ResonnantSweep.ki0000644000000000000000000000052713214501362031145 0ustar rootrootcyd!inst0 00 0Pad_ResonnantSweepP-K%Ur B~`Z⢪KyetD1!ײX^Y`p`*uRĈʝfGztUeR݁1ArDuҁ|U򩸘܁eRV_U"RruI.{DIҁ*%wX-i}vUhh#ܕlΚx2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_FakeArp.ki0000644000000000000000000000017513214501362027643 0ustar rootrootcyd!inst0   0 Lead_FakeArp2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_FM_Rise.ki0000644000000000000000000000016313214501362027613 0ustar rootrootcyd!inst0   0 Lead_FM_Rise`2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Lead_SquareToPulse.ki0000644000000000000000000000017513214501362031106 0ustar rootrootcyd!inst4  0Lead_SquareToPulse2s`Wklystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bassdrum_02.ki0000644000000000000000000000054413214501362027466 0ustar rootrootcyd!inst8 0 Bassdrum_02-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/n00bstar-instruments/Bassdrum_01.ki0000644000000000000000000000054213214501362027463 0ustar rootrootcyd!inst8 0 Bassdrum_01-2~j 095@2B0'~_dHû*2j~Y3RvOJ<,pRcΌqN`Vc̜qfٖVJK)UUmٖRJKUUm<13lM&3c<13lM&3c/rJ !6mbBpJ !&MlBAE#9sD 39 yaAbqB9,aa z klystrack-0.20171212/klystrack/examples/instruments/katana.ki0000644000000000000000000000012713214501362022617 0ustar rootrootcyd!inst >ELTt@W:YKatanaklystrack-0.20171212/klystrack/examples/instruments/major.ki0000644000000000000000000000010313214501362022462 0ustar rootrootcyd!instp }}}yf.@{~~~{a0@www~~~>D!}}}yf.@{~~~{a0@www~~~c{tqy|irlvq{WQTFFFFFFFFFFFFFFFFFFFFF???!!! """CCCFFFFFFFFFFFFFFFFFFFFF^V[s}lvlvlvlvlv}kt~kt}!5pD}}}yf.@{~~~{a0@www~~~@sp{{{xuv4'+ 0!9)?-0!0!0!0!0!./qkp{{{tn^>G(p;>5D}}}yf.@{~~~{a0@www~~~ @2XM5AE*7I0=Q5D  V8GI0=I0=I0=I0=I0=G-;H-;}~qW^E}H;>5D}}}yf.@{~~~{a0@www~~~L1@!.J'(J'(G#&I#&enRHm};>5D}}}yf.@{~~~{a0@www~~~eh{l}r=kijlhKKsDFsIIsIJxAANBA5D}}}yf.@{~~~{a0@www~~~ !uxxzsqxxx{||9!- ) 8'Cu9qy6ms=vHiBpEl ? /M+= ', '#f`dy};>5D}}}yf.@{~~~{a0@www~~~@8IWCMB$3I0=V8H MxEu|CrvGyHbBfFd?`wEcDcFeFeI7NJ*2I0=V8G H.5D}}}yf.@{~~~{a0@www|}~H>PR=G9)B$3P.@  Ev>rz;nt@vA^9b>`6[u=_<_>a>aB-GB&B$3P.? H.5D}}}yf.@{~~~{a0@www1+;}z}bOYR5D}}}yf.@{~~~{a0@www~0,,0y|y[KS3#>"1K*<# u@q}D{w@tv=rz@eJjJnKdI1>I-8J1>N3C87Mu5D}}}yf.@{~~~{a0@www;::;~~cS\=-G,;S5E+!vCs~G{xCvw@t}t=`GeGiG`I1>I-8J1>N3B; :RxEu@n@.fy};>5D}}}yf.@{~~~{a0@y{y7667fW_;,G.:T7F)!uAr}EzwAuv>s{r|8]CbBfD]I.9J+3K.9N1=5D}}}yf.@{~~~{a0@vvv@>>@~~eT^@"1K0>U7G.&vEs~J{xEuwBs|s}=`GeGiG`I2?I.9J2?N4C5D}}}yf.@{~~~{a0@YorbK#,P8DH55\>[[[\\'G*EMtCqrjJ|75*]9T5@.fy};>5D}}}yf.@{~~~{a0@4QSMtAD(7:$&T,NCCDD B!@U}Gzw5D}}}yf.@{~~~{a0@E^aW{E#I0=A,,X4TNNOOD&BQxEuu5D}}}yf.@{~~~{a0@E`a]P)T7FJ44b;^OOQP:8IueAmO/'-Z6P\(@J:@.fy};>5D}}}yf.@{~~~{a0@wwBR_R]s[i85D}}}yf.@{~~~{a0@|gT]f\4r=E&U#. uFiuFkrAerCeGeCbFdFd@g=i?h1lh\J|P[b7` I0=RI.5D}}}yf.@{~~~{a0@2=;A{jrzdG?&I0=V8G'  {Gw{GyxCtxDtGeCbFdFdFdFdFd=iaT@lxEuOU0SRC,5A+1BC?@.fy};>5D}}}yf.@{~~~{a0@-*4|gL2B,4Q8@ z=sz=vu7pu9p~GeCbFdFdFdFdFd5D}}}yf.@{~~~{a0@TY[ZVJX5D}}}yf.@{~~~{a0@eLjcwwwz{yht*_-a2h}-_J&BVI~{;wmGeCbFdFdFdFdFdGcAf5D}}}yf.@{~~~{a0@{@.fy|wAtxDv~I{vDsM*KPxEuu;qbGeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=`xEuxEuxEu}7iQ0<*ey};>5D}}}yf.@{}b0@z7jv@sxDvJ|vDsF CKv?ss3m^~GeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=xEuxEuxEu}7iU5D}}}yf.@{{s{tx`0@|1KAakgvvvx|xvkwxBuxDv}GzvDs V8UY{PyxFuhGeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=xEuxEuxEu{;lf\^Xt}};>5D}}}yf.@{ak0exDt,`\2@93?}Vyx9oyBrO;8J|yFvwBuxFuGeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=xEuxEuxEu{;lf\_Xt}};>5D}}}yf.@{aj0exCt~,`\2@72>}Vyy9oyBrO;8 J|yFvwBuxFuGeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=xCtxCtxCt{8kfZ^Utx|};>5D}}}yf.@{bi2cwEs~._Z2>'@;F}[}v=rxEuS:9 G{yDvv@txDtGeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=xDtxDtxDt{8kfZ^Vtz|};>5D}}}yf.@{bj2cwEs~._Z2@%@;F}[|v=rxEuR; :I{yEuwAtxEtGeCbFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=򇀇zbsPuUqPrd{vk9>5D}}}yf.@{ttuv]AL;xMZZ\\``````^szwsS}bjhNmOHP=DoCi~F|xEuy=tw]vwxvvvvvvzxykaeeeeeeeeeeeeeeeeeeeeeeeeeecgvHePiQjPiFdFdFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=򌐌񌐌Tvy0f{;lw2QTxpd9>5D}}}yf.@{HGJL[EN>UahO''''''$FPMF^jnSk2f|=xI@?"1G*:C'4>#.j=dJ}xEus7olbTYYYYYYYYYYYYYYYYYYYYYYYYYYV\q|4[?`>`?aFdFdFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=񊊊񊊊}Z|v=rxEut>^[yrg9>5D}}}yf.@{[Z\]\CM=}R^bU;@@@@@@>Ya^Ymx|3dxEuOU0SE,:N3BI0=E-6l?fI|xEuu9qfeY^^^^^^^^^^^^^^^^^^^^^^^^^^\as}<_FdFdFdFdFdFdFdFdFdFdFdFdFdFdFjGUJ*2I0=I0=I0=~~~~Yyu>sxEur>[\{ti8>5D}}}yf.@{MLNOYyu;qr,l`~{~~~~~~~~~|}gX^^^^^^^^^^^^^^^^^^^^^^^^^^\ax~}{w1c=igK'+G&'J'*J'*J'*J'*J'*J'*J'*J'*J'*U03/^^^[rc{7ixEu@laT=iFdFWE{?@5D}}}yf.@{@1RJJLLlurrrrrxbt?cxEuL~m>j#V8HI0=C,5V6M}G{xEuwAtyJwnX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~bt;^Fd?hXZAmxEu}GztCqK0>G.:I0=I0=I0=I0=I0=I0=I0=I0=I0=S7F2 )^^^[p\x+du@"18(O*D{>xuPGRDGzMfbaZdubvscqd/@{Q`ZjWWZZacbfqS_G_GbLX>J&>M*KS.PI(G&%''%$%#+'+-.-,,,,,,H@DiU_`PY\NTiTc_^~~\}a~y||||||||||hZ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~vqs{PTz#;t*?p&Bu77dQ(DM*KO+MJ)G.&,#-$-$-$-$-$-$-$-$-$3!*^^^Ymba?J(,@!\5Zhf^gfe#_ufvsktmh.dxEu-`^0@{@-gcrrrrrss|LuAhxEuQ.-vDs~I{xDvwAt|}vV^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~{Pyv?sxEuQ.-^^^Yyl^b9+E-8;$Y?g|u}mh.dxEu-`],<z7dfuuv{{||OxBj}GzT*)t?p}Czv?tu;q{uxV^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~VD|L~Y..^^^Y{lcmD"4N2BG+.Y=ejgahmh.dxEu-``5C!|-IjI{-+       ^^^^^__Zl}{3cwEtM^5\Vh`Jmh.dxEu|3dl}Y^GX0D4zeszau?bxFxNhC-5d<]~G{vDss;p}]{b]______^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~xEtxDt{Ix{Iw  ' U7FH.<;*"h8qPLLLLLLLEqCivDs~G}_8WA+1H.+0g>aL~I{{?wb^Y\\\\\\]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~wAtw@tzDxzDw' [_xEuMf;c<&2P4CH.r}R{dSYYYYYYYYYXY^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~ks1nv>r{?yp;iC-5C,5D-5D-6P5BR6ER6EC1'ETPRMkCWsDjsDjsDjsDjsDjsDjsDjwEsyEwxEuwEt{FyI|~G{KrBmN4=R6ER6ER6E^^^^^^^^^^^[dz?oxDt~I{vDs:ql^C`V]YbAMMMMM@hV^_]A>@@@@@:Ob^YhzLxv@txEuP%$.-QxEuv?s{PyhY^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Y~nu;qxEu}G{rBmH0;H.nNSGOIa8FFFFF7gJTUR3/009=<1Usniw{Myu?sxEuSGu9qs2mxFv|}}}}}{xiX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^WUVP|uu8pxEu{FztCnU8GU7GV8HV8HE-6@+1B,21'@SNOLqDexEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuI~j>c<),B,2B,2B,2^^^^^^^^^^^\al{l}nk|A*E>7gY5Rj?bb<[\9O|CKIJGuEoxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu{FyrBn`;Xb<[b<[b<[^^^^^^^^^^^^]YYVY]GR^!$wwwmkj 0F@4YOZ]V><<8k~xxxxxzsfgke1i})W-`0gX1AIY+C$6@!1;-@ 0sBp~I{xEur8o~yNVVVVVVU]_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\ax}{}V|q.mu9qt7pv?sxGvxEuNd9bk=iQIJwFpoCaqDepDctDkyExxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuwEtzFxJIII^^^^^^^^^^^^^^^]^vP{=mxEuP%$666>=@@@@@:Rb^UrirunNLMKjvrrrrrrrrrupyG}vBmxEu}G{V6MC,5I0=V8H#N3BJ1>G.:K0>tCq}GzxEuu<=7O]ZPqmw{tOMNLn|wwyzzy|~QL|OQV7M:(+C,5R8C E'8B$3?"0B#4q9m{?xv=rr1optV^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\aa~u;qxEuwEtzFxI~I|Pl=if;cMxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu^^^^^^^^^^^^^^^]^pks^rc}l>9I# !!!"$#LFLwty|**++AGE?Ykf`t_egcLJKJ`hefb}_`by\iPiPkRiOV2YS-MU0SY2XV4OV6MV6M_8U>,:"&"!!!!!!-*-`LV\KSZIQ\JTzWy[}Z|{Rzy}~~~~~tY^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\at~wwwwwvwxww~}W{v?sxEuzFxsCoj?cl?fvFp[5Vf;cMxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu^^^^^^^^^^^^^^^^^[[[Rtq0kv>sGc1]=Q$2J)Ag0Q?u{;l|9ly=juBhuAhuAguAhtDktDltDktEluBiv@guAh~Ds[4G9&B)'M22(U.SR}G{y9umbTYYYYYY\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\ahw2Z?`?`?`?`?`sv>swCtxFuxEuIc<\<*-E-6L3=9$-f;cMxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu^^^^^^^^^^^^^^^^^^^^X|nu;qxEuMf;c=&2Q5BI.dJjJjJjJjJjHkKj{MGwJ|J|J|J|J|MlAdF07N3BV8HB*6f;cMxEuxEwwEquEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEovEo^^^^^^^^^^^^^^^^^^^^X{rtAvwK{RfAhA)6S5GL1?E-8e=^}GzvDsvDstCqrAnrAnrAnrAnrAnrAnrAnrAnuCrvDsvDs}G{`9YE-6L1?U7I7#.Y5VRyJwv>sheY^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_aa^cgt6YB_B_B_B_B_?`C_nDtv?krAnrAnrAnrAnrAnxDw`9Y=)0E,:M2?:$/f;cMxEuxEtyExzE|zEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEzzEz^^^^^^^^^^^^^^^^^^^^^_aa`a``\fxNvt?pvDs}Gz]8UE-8L1?W8J1*<&2T7GL1?E-6b<[}G{vDst=oyVxoZaaaaaaaaaaa^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Xj^MWE)8M5AY=K'#f;cMxEurDgJNMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^\Z\\[\\VeR~x@u{FyK]8U=*/F.9S6E(5!)P5BF.9=*-b<[K{Fyy=t]~lT\\\\\\\\\\\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Xm~YEQ=-E*7R3D f;cMxEurDeJNMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^^^^^^^^Ye{Pyv?sxEuI~]8UB,4I0=U7G-$9#.R6EI0=B,2b<[IxEuv=r}Z|nX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Xk\JTA#2I0=V8H#f;cMxEurDfJNMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^^^^^^^^Yg~Fpy3h{;l>t\,G?"H"-T*7& 0$M->C&4:"*^4VB~v>st5o|T{woX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_\YYShfQ]I(8Q5D`?P#b9ZMvtDkmCZJNMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^^^^^^^^]`kkkkgffh^WYW\}f_Zccccccccccccccccccccctnq{twxrtvqru}xwu}ugkkkkkkkkkkkkkkmc]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Yo~}'''!!!!!!#$$    <&22 )2 )2 )2 )2 )5!,2(5 *5 ,1&1&DOKKLMMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^^^^^^^^_]XXXXYZZY^a`WvhQXXXXXXXXXXXXXXX\_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^UypbARS7FS7FS7FS7FS7FW9IR5EV8GV8HQ5AQ5AKPNNMMMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^XnkX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vv}V8HI0=I0=I0=I0=I0=M2@H.<L1>L1?G.9G.9IPMMMMMMMMMMMMMMMMMMMMMMMMMMMMbbbbbbbbbbbbbbbcb^^^^^^^^^^^^^^^^^^^^^^^^Vp~q}}}}}}}}}}}}}}}}}}}}}}}tnW^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vv} Q6AB,2B,2B,2B,2B,2E.7A+1<,!<,"8)8)GPMMMMMMMMMMMMMMMMMMMMMMMMMMMMQQQQQQQQQQQQQQQPQ]_^^^^^^^^^^^^^^^^^^^^^^ZgyvvvvvvvvvvvvvvvvvvvvvvvxeZ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vv}xxxFFFFFFLLLEDD  /,886464J*Ef?^`9Y`9Y`9Y`9Y`9Ya;Z_9W97646464646464646464644/?!@v>v>s=s=KOMMMMMMMMMMMMMMMMMMMMMMMMMMMM:::::::::::::::7:[a^^^^^^^^^^^^^^^^^^^^^^_\UVVVVVVVVVVVVVVVVVVVVVVVU\_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vv}]]]P4C\=NV8HR6AKwURRN~G}IIIIII~IQRRRRRRRRRRQ}RQQRRNMMMMMMMMMMMMMMMMMMMMMMMMMMMMM@@@@@@@@@@@@@@@>@[a^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vv}cccE,:N3BI0=E-6l?fI|xEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEutDkFMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM<<<<<<<<<<<<<<<:<[a^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Wup_fY@*3H1;D-6@+0f>[yGqsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjsDjoC^zEzMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMFFFFFFFFFFFFFFFFF\a^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Uzv~l]s P2FW7MS4JO2BuAwJFFFFFFFFFFFFFFFFFFFFFF~FGMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM_________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Py8JLBE00N3BJ2G0:M2@wDt}FzyEwuDlKNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^O|>NQE>+(G.:D-6I0=tDoyFuvEqrDfKNMMMMMMMMMMMMMMMMMMMLKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^P{=MPDB,.K0>G.:M1AwDt}FzyEwuDlKNMMMMMMMMMMMMMMMMMMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^`YmP5R3MN0H\7VwEttCqrCjvCtLLLLMMMMMMMMMMMMMMMMMMMMG[tnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^bPk=B-/:)$R5EJ}GzzGtGNMNNMMMMMMMMMMMMMMMMMMMMG]{uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMMMMMMMMMMMMMMG\xrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMMMMMMMIGGGGGGBYyrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMMMMMLNcgeeeeecjtrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMMMMMLNtzwwwwwxuqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMMMMMLNnurrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^WVWU\_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^acbbbbbcb^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMNLFGEInurrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]_prqsd\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_VQRRRRRRU^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMKP]\\]ptrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\ax~unW^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aF3:::::5B_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aTlE"I0=C,5V6M}G{xEuvEozEzMMMMMMMMMMMGUzxxwrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\akX^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^aI;@@@@@@@@@@@@@@9Kb^^^^^^^^^^^^^^^^^^^^]]]]^^^^^^^^^^^^^^^^^^^^^^^^aZ?>@@@@@9Rb^^^^^^^^^^^^^^^^^^^^^^^^^^^aI;@@@@@=>>>>>>>>>9Kb^^^^^^^^^^^^^^^^^^^^]]]]^^^^^^^^^^^^^^^^^^^^^^^^aZ>=>>>>>9Rb^^^^^^^^^^^^^^^^^^^^^^^^^^^aI;@@@@@@@@@@@@@@:Kb^^^aaaa_^^^^^^^^^^^^^^^^^^^^^________________^^^aZ@>@@@@@:Rc_______________^^^^^^^^^^^^aI9>>>>>:F_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^bP@VDcCiETH*0H.@@@@@@@@@:Kb^^^````^^^^^^^^^^^^^^^^^^^^^^_^^^^^^^^^^^^^^_^^^aZ@>@@@@@:Rc^^^^^^^^^^^^^^_^^^^^^^^^^^^aI9@@@@@@@@@@@CFEEEEEEEEEEEEEEARb^^^^^^^^^^^[YZZZZZZZ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Xq~|rp;irBmqBlrBn~FFF|E|KNMMMMMITtrrrrrrrrrrrrrrrrrrrrrrrrrrrf}CO@_^^^^^^^p(Rfe_^^^^^^^^^bQ7<<<@@@@@@@@@@@:Kb^gSGj^^^^^^^^^^^^^^^^^^bO7<<<<<<<<<<<<<<7Lb^aZ@>@@@@@@><<<<<<<<<<<<<<<7Ob^^^^^^^^^^^_aaaaaaaa^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Uyxz{@y}G{~G{}GztDlsDktDkpCaKNMMMMMITtrrrrrrrrrrrrrrrrrrrrrrrrrrrcw4M^^^^^^^n.[p (d_^^^^^^^^^bR:@@@@@@@@@@@@@@:Kb^fTIi^^^^^^^^^^^^^^^^^^bQ:@@@@@@@@@@@@@@:Nb^aZ@>@@@@@@@@@@@@@@@@@@@@@@:Qb^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vv}wv>sxEuxEuxEuxEuxEuxEutDkKNMMMMMITtrrrrrrrrrrrrrrrrrrrrrrrrrrrdz0@,U^^^^^^^q&M_ e_^^^^^^^^^bR:@@@@@@@@@@@@@@:Kb^gRFk^^acbbbbbbbbbbbbbbgS:@@@@@@@@@@@@@@:Ogbf^@>@@@@@@@@@@@@@@@@@@@@@@:Qb^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Uy~n~p{r2pu;qu9qu;qxDvxFuxEusDiNSQROLMGUzxxwrrrrrrrrrrrrrrrrrrrrrrrreo5^^^^^^^eK4e}4e}4e}>u`^^^^^^^^^^bR:@@@@@@@@@@@@@@:Kb^aZ5f~4e}4e}4e}Uc^aVKNNNNNNNNNNNNNNOH>@@@@@@@@@@@@@@>FONNK@@@@@@@@@@@@@@@@@@@@@@@@:Qb^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\htqowi}nqkyGvwCtxEuyFuq?zn;~o<}g9oDOMKP]\\]ptrrrrrrrrrrrrrrrrrrrrrr`^^^^^^^\emmmj]^^^^^^^^^^bR:@@@@@@@@@@@@@@:Kb^]`mmmma\^bL3::::::::::::::9<@@@@@@@@@@@@@@@@>9:9;@@@@@@@@@@@@@@@@@@@@@@@@:Qb^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_ZUWOhyKww@txEu~G~M3:2';+!)&mQMMMMMLNnurrrrrrrrrrrrrrrrrrrrrr]YYYZWWXXXXXVY^^^^^^^^^^^bR:@@@@@@@@@@@@@@:LfbbbbbbbbbbfQ:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;:::::::::::::::::::5Ob^^^^^^^^^^^^^^_ZVXXXXXWXabbbbbbbbbbbaYYYYabbc]XYYYYYYYYYYYYYYYYYYSiyKww@txEu~G}Q4G;),C,40' v>VQQPNNMOtzwxtqrrrrrrrrrrrrrrrrrr\èiiihmonnnnnpk]^^^^^^^^^^bR:@@@@@@@@@@@@@@:;;;;;;;;;;:>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>@]ebbbbbbbbbbbbbbbbbbb_^^^^^^^^^^^^^^^Uv~q}J_sw\^^^^^^^^^^bR:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>@Za^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Vt}Mh@aFdFdFdFdFdFdFdFdFdAgN`yDtyDtyDtyDtN`AgFd=idR@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuIb<[B,2I0=D-6S4J{FyyEwvEqyEwLNMGewrrrrrrrrrrrrrrrrrrdz0@,UxEuxEuxEuv=s{X[\[YXXWYZZ^O9<<<<<<<<<<<>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@><<<<<<<<<<;CCCCCCCCCCCA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ACCCCCCCCCCACZa^^^^^^^^^^^cccccccd_Z[[[[[[\aaaa^[[Tr~{QeF^KaKaKaKaKaKaKaKaKaGdR^tGztGztGztGzR^GdKaEecRyDstI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{tI{yLb>aH.7N2BI0=V5MvDsuCqrCmuCqIKJEasmmmnnmnrrrrrrrrrrre|=I:\xEuxEuxEuxEuxFuxFvxFuJc=\C-3J1>E.7T5K{IzyFxvFryFxMONFv~xV^^^^^^^^^^bN:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;Ub^^^^^^^^^^^^^^^^^^^^^^Zcfw;_FeFeFeFeFeBgHcvIz|EsxFv}DpU]?iFe=j^VAlxFuxFuxFuxFuxFuxFuxFuwEwwEwwEwwEwwEwwEwwEwwEwwEwwEwwEw|CqqJFeFeFeFeqJ|CqwEwAm\W?hGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGd?i^U@kwEt}GzoAiG.:I0=K0>K0>K0@K0@K0@D,8j?eJxFxrEhJONKRssrrrrrrrrrrrtssstttttttttttttttttxEuxEuxEuxEuwCtwBuwBuE~`8Y?(.F+:A)3Q0G}Bu{ArwAm{ArGJI@sxzyX__________cN:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;Vc___________^^^^^^^^^^^Zcgt7[EaEaEaEaEaAcG_wCt}?nyAq~>kTY>eEai\W:kDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDeDe:j^VAnzFxI~pBjD-6F.9G.:G.:F.6E.6E.6>+.f<\~FxwCoqB`FMLGQssrrrrrrrrrsqmmmmkkkkkkkkkkkkkkkkkyEtyEtyEtyEtyEtyEtyEtI~b???????????????????????????9Ub^^^^^^^^^^^^^^^^^^^^^^Zcfw8^EdEdEdEdEdAfGbwGw}CqyEt~BnU\=hEdbI~xEurDfINMJRttsssssssrssssssssssssssssssssssss|Cr|Cr|Cr|Cr|Cr|Cr|CrF}c9VB)*J,5D*/S2E{FyyEwvEqyEwLNMDx{W__________dN9>>>>>>>>>>>>>>?=:;;;;;;;;;;;;;;;;;;;;;;;;;;;4Q`\\\\\\\\\\\\\\\\\\\\\\Xaey6_BfBfBfBfBf?hFcxFuAn|Cr@lT];jBf:k^U>g|Cr|CrzDsxEuxEuxEuxEuzCr|Cr|Cr|CryDtxEuxEuxEuyDt|Cr|Cr@lsI{AgAgAgAgsI{@l|Cr>g\W:kBfBfDeFdFdFdFdBfBfBfBfEdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i_T>i|CrExq?fC-5E.7F.9F.9F.9F.9F.9@+1g>aI~xEuqDeJPOKTwwvvvvvvutttttttttttttttttttttttttQ^Q^Q^Q^Q^Q^Q^S_L\FYGZA\QU|DsyEtxEtxEuFGFGfDcRBDWCMXBKTFTML`NK]NK]NK]NK]NK]NK]NK]NK]NK]NK]OJ^LObHSdIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcCPZ]\zteocococococococococococococococococococococococococococndr^u[s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\s\r]u[|T{|Tz|Tz|Tz|Tz|Tz|Tz~UyuPkKoLoLoLoLoLpK~lMS]O_Q^N`fQrJ}oLsI|`TLaQ^L`ZYzCsyEtzDswEwU\M`Q^LajN~BnxEuAnhOKbQ^N`U\oKoKoKoKU\N`Q^LacSsI|oLsI{`T@gFdBfJbnLpKoLqJN_AfFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdEeKaS]Q^MaWWq?foAhoAioAioAioAioAin@huDryFvxEu}Gym?lX3[]6_]5]\7`Y>fY>fY>fY>fY>fY>fY>fS<`oGQ~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O~O@g@g@g@g@g@g@g?gBhGjFj?mPb|CqyEtxEuxEutDksDjsDjzIqS0G; *B$3A&4D#/H )F *F *F *F *F *F *F *F *F *F *F!*I(J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'Ae*I8q~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~5g~4g|7i{9k{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{9j{8j{9kv=rv>sv>rv>rv>rv>rv>ru=s{@pBn~Bn~Bn~Bn~Bn~Bn?k|DsBe;j@g:klM=f~Bn,)>,+@+(A(%A(%A(%A(%A(%A(%A(%8$`6L~Dou@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fu@fFdFdFdFdFdFdFdFdFdFdFd@gQ^|CryEtxEuxEuxEuxEuxEuI|Z7QC,4I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=B,2b<[IxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu|CrvGyHbBfFdAgjNAnxEu@laT=iFd@gQ^|CryEtzDswEwKaAfFd?hgPAmxEu@ldR=iFdAgN`yDtyDtyDtyDtN`AgFd=idR@lxEuAmgP?hFdAfKawEwzDsyEt|CrQ^@gFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd@gQ^|CryEtxEuxEuxEuxEuxEuxEuxEuxEuxEuI~e=^B,4I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=B,4e=^I~xEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuFdFdFdFdFdFdFdFdFdFdFd?gR]>g@k@l@l@l@l@lDt]0AB"J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(A"g5LDw@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l@l>g~CoHbBfFd@gpK~g@k?j@mLa@fFd=ilMgR]?gFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd@gQ^|CryEtxEuxEuxEuxEuxEuxEuxEuxEuxEuJe9WB"J'(J'(J'(J'(J'(J'(J'(J'(J'(J'(C#c2U|=|u9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qu9qFdFdFdFdFdFdFdFdFdFdFdDeKa`T_U^U^U^U^U^UaWPOEJvGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyGLyDJtSQbW^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U^U`T]VGcEeFdDeWZaS^UcSS]BfFdDeKa`T_U_U^UHcDeFdBfV[aS^UcST\BfFdDeJb_U_U_U_UJbDeFdBfT\cS^UaSV[BfFdDeHc^U_U_U`TKaDeFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd@gQ^|CryEtxEuxEuxEuxEuxEuxEuxEuxEuxEuDtdIw?MzGLyGLyGLyGLyGLyGLyGLyGLyGLyGLy?Fxk^~njjjjjjjjjjjjjjjjjjjjjjjjFdFdFdFdFdFdFdFdFdFdFdGdEe`FdFdFdGd>`<_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_<_@aGeFdGeEc=_=_=_=_EcGeFdGe@a<_=_<_@aGeFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdGcBf=h?h8kKa|CryEtxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdFdFd>`<_=_0YlyFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCcMh\qZn[pWmFdEcFdEcUl\qZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZnZn]qRjCbFdDcIeZp[p[pZpIeDcFdCbRj]qZn\qSkCcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdDeM`WZU\Q^\WzDsyEtxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdEdFdVm\qZnRjvFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd;_`sGeCbEdAb~s}:]Fd>`QiQi>`Fd:]s}~w;_FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd`@b=`|mz6[Ab;^MgMg;^Ab5[p{t~6\AbAbAbFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFdEdHeJfIfJfIfFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdEdHeJfIf@a`sJgGdHfFd~p|?`IfDbSkSkDbIf?an{r|@aIfJfIfFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFd;^duzAbEdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd<^mzct?aIf@a_sGeCbFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFd8^iwAbEdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd:^q|at5[Ab6\]qGeCbFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFd:^gv}AbEdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd;^o{bt;^Fd<_^rGeCbFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFd8]jx~AbEdFdFd?a>`?`>`DcGdFdGeCc>`?`?`?`?`?`?`?`?`?`?`3Zlz~as2Y?`3Z\qGeCbFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFdCbOi]qZn\qUlEcFdDcGes}|wWm?`Fd>`[pwwwwwwwwwwt~`sUlZnUlly|w|mzUlZn[pWmFdEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFdGeAb;_=_<_>`GdFdCbGe~at;^Fd:]ev|He5[=_.Wq|||v~0Y=_<_>`FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGe^r<_Fd;^btPi?`Fd;^o{s}<_FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdGd@ggEl8euz9fElElElElElElDlPtSuSuSuLqCkElCkInSuSuSuSuSuSuSuSuSuSuSuI{i`ArIJI|xEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdDeWZaS^UcSS]BfFdFdFdFdFdCcGe}ik~jm~k]YS^UYRm^m~jjjjjjjobkj`cl`grdkWQTFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFNMNnbimagl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gl`gmagmagMOwDJ{GLyBI|^Ynrdcl`gqcc`ZmCI{GLyGLyGLyGLyGLyHLzIM{)7a!2Z!2Z!2Z6@kNPGLyMO~=Dp!2Z!2Z!2Z!2Z!2Z!2Z!2Z!2Z!2Z!2Z!2Z4_@6[m=\b<[`;Xf=ayEwxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd@gpK~wz6ku9qs8q}>nAk@lAk|>ns8qu9qu9qu9qu9qu9qv;rv9sF#99'? /N*<C#5@!0? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /? /> /> /I&*K((J'(L((C"-=1? /=1B"-L((J'(J'(J'(J'(J'(K()O*/Y17J'(U04/P7BB,2;),M1B{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdAgjNAnxEu@laT=iFdFdFdFdFdDeGdtI{}CqxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuyFvyEwP3FE-6I0=V8G N3BJ1>I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=I0=J1>N3B#V8HI0=S7F2 )V8HI0=D-6S4J{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdAgoL=h~Bn,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)>,)=-*F!'K&J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'J'I'F *F *H!,L$/V*7F *Q)5- a@QR6EM4=[9O{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdBfcRsI{oLtGz\W?hFdFdFdFdFdDeGdjNrJ}oLoLoLoLoLoLoLoLoLnMpKxEuxEuyFvyEwB)95"*9#.C+7%  * ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ' (&-'.'-'-'-'-'-'-'-'-'-'-0:LTgJSdIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcFVcUA`_1]]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_]6_^3^OKaGUdIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcIRcHScIQbNK]NK]OL^QNb)3 ( ( (06EYRfNK]VQe=?O ( ( ( ( ( ( ( )'!C+79#.5"*F+>}GzyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdDeBfBfBfEeFdFdFdFdFdFdFdFdDfBfBfBfBfBfBfBfBfBfBf=iLayDtyDt{Gy{GwRRR^ddddddddddddddddddecFCDDDDDDDDDDC>>>>>>>>>>>>>>>>>>>>>>>> 7OOOOOOOOOOOOOOOOOOOOOOOOOOO@b*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>:A_a__cdddb___addddddd_IJJ J|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdEdEdEdFdFdFdFdFdFdFdFdFdEdEdEdEdEdEdEdEdEdEdEd@gN`yDtyDt{Gy{GwPPP~Y__________________`^B?AAAAAAAAAAA????????????????????????%7MMMMMMMMMMMMMMMMMMMMMMMMMMM?a,???????????????????????????????????????@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&7MMMMMMMMMMMMMMMMMMMMMMMMGFG8b,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&7MMMMMMMMMMMMMMMMMMMMMMMMOOOAa-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@CCCCCCC>Rb^^^^^^^^^^^bccs0YlJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`|n{8^FdFdFdFdFdFdFdFdFdFdFdFdFdFd@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&7MMMMMMMMMMMMMMMMMMBeagjfA<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>FLKHQ_^^^^^^^^^^n.[pJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcAmAmAm>fPV2c<_/d\PA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=::5Fa^^^^^^^^^^n.[pJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcxEuxEuxEu}BpU\?hFd=i^U@lxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu{Gy{Gw  OOO|X^^^^^^^^^^bO:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&7MMMMMMMMMMMMMMMMMM>grmem@MMMMMMMMMMMMMMMMMM9:9<]_^^^^^n.[pJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdAgN`yDtyDtyFvyEwP3FE-6I0=? 0pfk|X^^^^^^^^^^bO:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^^^^^n.[pJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdGd@a>`?`>`CbGeFdGdEc>`?`?`?`?`?`?`>`DcGdFdFdFdFdFdAgO`AnAnCqBqQ3DE-6I0=?1qjl}X^^^^^^^aaaeP:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<@,h/@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^^^^^o*Yl  J|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFdEcNhRjPiRjKgDcFdEcHeQjQiPiPiPiPiPiRjIfEcFdFdFdFdFdBgMarI|rI|rK~rJO4GF-5I0=?"1n`iz}zX^^^^^^^ZZZ]N;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^^^^^l4_t J|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`xly:^Fd>`Tl^r<_FdFdFdFdFdFdFdEeEeEfEfI7NJ*2I0=B,4e<_F}xDt|4epiY^^^^^^_F<@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^^^^^aVuH#L1>E.7T5K{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`xlz:^Fd>`Tl_r<_FdFdFdFdFdFdFdEeEeEfEfI7NJ*2I0=B,4e<_F}xCt{4epiY^^^^^^_F:>>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^^^^^aVuH#L1?F.7U5K{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`wky:^Fd>`Tl^r<_FdFdFdFdFdFdFdFdFdFeFeH7MH)0H.A]_^^]]]`UuH#L1?F.7U5K{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`wky:^Fd>`Tl^r<_FdFdFdFdFdFdFdFdFdFeFeH7MH*0H0;A,2e=^I~xEu|6fpjY^^^^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^^]]]`UuH#L1>E.7T5K{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`wky:^FdEcHeQjQiNhQj^r<_FdFdFdFdFdFdFdFdFdEeEelFvu?grBmpBluDryEwxEu|6fpjY^^^^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^ZyHMQ J|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`wky:^FdGdEc>`?`;^@a^r<_FdFdFdFdFdFdFdFdFdEeEeuLDv}G{~G{zFxwEtxEu|6fpjY^^^^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^YxEB?  J|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEcFdFdFd?`wky:^FdFdFdFdFdCbGe^r<_FdFdFdFdFdFdFdFdFdEeEeqJ}}BpxEuxEuxEuxEuxEu|6fpjY^^^^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<A]_^Y~FFFJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu@ldR=iFdFdFdFdFdDcEc=i=i=i4d}|{p|7]FdFdFdFdFdCbGe}at;^FdFdFdFdFdFdFdFdFdEeEewEu=e@l~>gK}QQ@x|rV^^^^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<9:7<`ba[FJHJ|yFvxEuxEuxEuxEuxEuxEuxEuxEuxEu?k`T3n=i@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=FURSRRiS`vRe}Qf_[fgTYeU^n`gH9A' ' %9!3~GzyEwxEuxEuxEuxEuxEuxEuxEuxEuxEu|CrpK~aTdRgP_TEeEeDcEc@l@l@l>ePV1b;^8]@aHeFdFdFdFdFdFdFd<_:^;^:]CbGeFdFdFdFdFdFdFdFdFdFdFd?h@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:KfbeaF"-CE#G"A,>!1?!0;+J,;V8GV8GP6A];QzFyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEuwFv|Cr@k@l=fwEuEeEeDcEcxEuxEuxEu}BpU\?hFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdSu$E9Hl^^^^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;Ia^`]J6EG(2I0=I0=I0=I0=I0=I0=I0=I0=I0=D-6S4J{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu}BpqJ}EeEeDcEcAmAmAm=fW[=iFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdUv ?6FfXWX^^^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:KebdaG#/CE&D"Q0>U7GU7GU7GP4CG.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>:;9<_b`l ,7 X9II0=D-6S4J{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu}BpqJ}EeEeDcEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdElIElJ'*I0=@"1`PY_\^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^h,8V8HI0=D-6S4J{FyyEwxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEu}BpqJ}EeEeDcEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdGdDc?a@a?aBaFdFdFdFdFdFdFdGlGDjE$$E-8;+^QV_\^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A>33//c?MMMMM9{+@,U*,->A@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^h,8V8HI0=D-6T4KI~~G{}Gz}Gz}Gz}Gz}Gz}GzyFvxEtxEuxEuxEuxEuxEu}BpqJ}EeEeDcEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdEcIeNhMhNhKgFdFdFdFdFdFdFdDlKFpO)0N2BE&7cO\_\^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>ALLII_AMMMMM9{+@,UATUTA>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^h,8V8HI0=D-6R4HvDsuCqtCqtCqtCqtCqtCqsCowDsyEwxEuxEuxEuxEuxEu}BpqJ}EeEeDcEc|FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd;^btEcDcFdFdFdFdFd=idR@kwEtwEtxEuxFvxFu{>nvQ~^]^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RLLOOMMMMMMM9{+@,UK0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^h,8V8HI0=I0=I0=K0>K0>K0>K0>K0>K0>K0>D,7i>bI~xEuxEuxEuxEuxEu}BpqJ}EeEeFdFdGdGeGe<_o{FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd;^cuEcDcFdFdFdFdFd=ieSAnzFxzFxyEwwBswBuz9luM~^]^_F<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1SDDGGLNMMMMM9{+@,UK0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]_^h,8V8HI0=I0=I0=G.:G.:G.:G.:G.:G.:G.:A+3g>aI~xEuxEuxEuxEuxEu}BpqJ}EeEeFdFdDcCbCb7\nzFdFdFdFdFdFdFdFdFdEcEdEdEdEdEdEdEdEdEdEdEcFdFdFd;^btEcDcFdFdFdFdFd=idR@kyEtyEtyEuyEwyEw|=nvP^[^_F<@@>>>>>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJMMMMMMLKK7z'=(SK0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>A]^^h,8W9IJ1>J1>K0>I0=I0=I0=I0=I.aI|yEtyEtyEtyEtyEt~BnqJ}DeDeEdEdFdFdFd;^o{FdFdFdFdFdFdFdGdDcBaAbAbAbAbAbAbAbAbAbAbAbEcGdFd:^duEcDcFdFdFdFdFd=ifQ>i|Cr|Cq|Dt{Gy{Fy~>pxQ\Z\]E:>><9;9<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJMMMMMNICE1u2JK0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>AZ][e*6\`FdDcKgVmTlVmRkFdFdFdFdFdFdFdEeL`S]Q^PcQOS.QbSYRk}l7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJMMMMMI-9I1>GUF]GZFYM\S_Q^Q^Q^Q^Q^N`U\oKoKoKoKMaBfFd;^o{ifhfFdFdFdFdFdFdFd8]jx~`s;^FdGeCb=_>`=_?`FdFdFdFdFdFdFdGcBf?h@g?pASD$#D-6=&0K6>}l\aY||pxr}4@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJMMMMM5g/K0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@9D{dMWH)9R6Ea@Q#N3BJ1>I-8I1>FdEnFjGjBh?g@g@g@g@g@g:kJb@m@mAmAmO`AgFd;^o{ZUYUFdFdFdFdFdFdFd:^gv^r<_FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdEkGRJ(,I0=D(7P8DhY^Vv}~w6@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJMMMMM7m&@K0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@9D\JTA#2I0=V8H#N3BJ1>I-8I1>F_FhFdFdFdFdFdFdFdFdFdAgN`yDtyDtyDtyDtN`AgFd;^o{_\^\FdFdFdGe=`8]:^,V`s}bt;^FdHeAb8]:^:^:^:^:^:^:^:^:^:^8]AbHeFdGkDQA# B,2;#+I6b_}Ac4Z:^8]AbGeFd8]gv{{gv8]Fd=h\[ExIJG}u9qt8pv9py7nMQ<[BWCA<(.,4A@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJJJA& 7C@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?A>*:>#? />.F+8J2?I0=>*/j?bURN~WAnDlCnGl|Et=e@l@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@1RJJJJR1@@@@@{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>AI8GJ&2I0=I0=I0=I0=I0=B,2`9YIxEu~BnoLBfEdDeGdtI{}CqxEuAmXZ?hFdFdFdFdFdFdFdFdFdFeFeI7NJ*2I0=J'*GOElFd<_^rFdFdFd>_~~Ed6\=_=_=_=_=_0Y]q]q0Y=_3cUU=eAnAm~BnxEuxEuyEt|CrQ^@gFdFRD>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/U8888U/@E-x{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?>?><;;:>@@@?>?=@I9HJ$0I0=K0>E-8C,4C,5:**`6QDxAn>ftI{BfEdDeGdr@xz9mv=r}7iRS4d=_<_@aGeFdFdFdFdFdFeFeI2BJ"!J)-JGPEuFj:eazFdFdFdBajx~wwwwwwwwwxw]qWmZnZnZnZnZnRjnznzRjZnWt`dmJjNiOkMxEuyEtyEt|CrQ^@gFdFRD>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@5NppppN5@5c{{g{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?@CCCBGJIKD>@?ACCBDI7FJ(2I0=H.`?`?`?`?`?`?`?`?`?`;^@b}v4bAg;iFdwEwzDsyEt|CrQ^@gFdFRD>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A>1111>A@{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>BF\GTGYCT\caeP:@>CGNGZF\GVI3CI-5I0=E-6o@jK}G{BraV6lAg@gAfFdFdCbGe~s}:]FdFdFdFdFdFdFdFhFiFiEsIDjJ J*2K+0G)2B&6C&4>#/G);u>rx@uv>sv>sv>sv>sv>sv>sv>sv>sv>sv>sv>sv>sv>sv>sv>sFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGes}<_FdAfKawEwzDsyEt|CrQ^@gFdFRD>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@{@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>AFfF`FcD`Za^bO:@?CGZFdFgFaI3CJ,5I0=E-6l?fI|xEu@laT=iFdFdFdFdFdCbGeo{;^FdFdFdFdFdFdFdFdFdFdElIElJ'*I0=I0=I0=I0=I0=E-8N2BwEtzFxxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuxEuAbAbAbAbEcFdFdFdFdFdFdFdEdAbAb>`Ccr|7\Ab=dG_zCs~Bp}CqAmP`@kFgFUA799;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r008B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>ADbD[D^B[Zb`dO8>=BF\FgFjFdI0=J),J,5E*/n=aFy|Cr>gbR8gAbAbAbAbAb>`Ccmz6[AbAbCbFdFdFdFdFdFdFdElIElJ'*I0=I0>I.:J,4J,5E*0N.:zCq~Dt|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|Cr|CrIfIfIfJfGeFdFdFdFdFdFdFdGdJfIfGdJgt~@aIfFhNcuGzwEwwGwxEuQ\@dFaFPGDDFC@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/KKF=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>AGjGdGgFdY_]aON4HuGwxGzvGyvGyvGyvGyvGyvGyvGyvGyvGyvGyvGyvGyvGyvGyvGy񇈌񇈌Ym=_FdFdFdFdFd>`SlIcFaHcIeI=YJ,7I3C?"5jcmu6@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`UlCg?dBgBiI8QJ$&J,5?'n\`|xz6@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`TlGeCbFeFgI;VJ)/I0=? /l`g~w6@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`?`6\Oi@a;^?a>cH5MK# J*2> obf{0<<<@@@@@@@@@@@A>6666>@@@@@@@@@@@@@@@@*%% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@I0=I1>I.9J*0J*2J'(I-8FaFgFdGd@a>`?`2Zct>_<_>`?`EdGdFdGlGDiD$#E-6D&$FAaGkFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdZnZnZn\qKgDcFd=`^qwu~|wvx{R_AQGUCWROp_GI\JT]@@@@@@@@@7MzxzwF9@@@@@@@@@@@@@:< @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>AIIHFp~gixrt|aOXB$3I0=J+1I;TGZGUGTGVFcFeFdBajx~wt~wvxxMhBaFd@j\Oq9Zl?fp;[^LAiFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=_=_=_<_DcGeFd8]kx|Vs@@@@@@@@@2T}w|~xJ6@@@@@@@@@@@@@79 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;;95mag>-I0=J(+IAaEqFjEkFjFdFdFd>_~~Qj>_Fd`FdElIIsJ'(I0=F(PTj_^_]A>@@@@@@@@@4QI8@@@@@@@@@@@@@9: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>;}i\a? /I0=J)-I?^FiFdFdFdFdFdFd?`wPi?`Fd=idR@lxEuAmgP?hFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd:^gvKg0Y:^8fCAlL J'(G QTcbac^2*.,;A@@=9:*Pw|xJ8@@@@@@@@@@@@@9: B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:974n^^>J'(JI8QFjFdGdFd;^:^:^2Yt~Pi?`Fd=idR@lxEuAmgP?hFdFeFcBWBWBWBW<]:_:^:^:^:^:^:^:^:^:^:^:^FdFdFdFdFdFdFd:^gvixjyixkyn{btgvl~W^BAlIIsGCoKT{VxUtTqVwegfjL9@>HQOIWxwxvF9@@@@@@@@@@@@@9:9>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>AOONMguoUXl`grddYTnBDtIIsIEkHQFgFdDcGeeviwgvctPi?`Fd=idR@lxEuAmgP?hFdEaGgQRQPbziugvgvgvgvgvgvgvgvgvgvgvFdFdFdFdFdFdFd:^gv{5\8^6\<_wl}7fElEwFUFE"@J&yvywn\0@:Rgbd`UVWVB<@@@@@@@@@@@@@9:R /=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@R9? /=BJ|FyElEmFjFcFd@bIfPi?`Fd=idR@lxEuAmgP?hFdD]Ilbbb_zFdFdFdFdFdFdFd:^gv}AbEdCbGegv:^FdFjGUJ*2I0=E*7M5AX2@:Ob^^^^^_^C<@@@@@@@@@@@@@9:m!@ 2=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@``>`>`>`>`8^AbPi?`FdehL4d>`o|=m{=n7dcN;eD`<\ShI8@@@@@@@@@%bK_B2=@@@@@2u{u{tq.@@@@@@@@@@@@@@1^}v~}J)5D#1I'3G#+G[EnFg8am|Pi?`FdFdDeBfBf7a^tFdFdFdFdFdFdFdFdFdEcEdEcEdFdFdCbGex?aFeBgHcvFy|BrxDvxDvxDtyCsxCs>jaS=hFc>_TkI8@@@@@@@@@'`J^@2=@@@@@2r{yo0@@@@@@@@@@@@@@2]|K0;F)8J,:J*3GZEkFe:_kzPi?`FdFdFdEdEd;_^rFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGev<^Cb?eE`uDx{@qwBuwBuxDvxEuxEu@kaU=kFf>bTnF2;;>@@@@@@'`J^@%256>A@2s~x~uo*;;=@@@@=;;;>@?0]}K.9F)5J,7J*0DWBiCb6\jxPi?`FdFdFdFdFd<_^rFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGew@aGeCgIcvIx|DsxFuxFvxEuxEuxEu@laT=hFc>_TkJ9AA@@@@@@@'`J^@6ADD@@@2r}{o2AAA@@@@AAAA@@@2]}J2?F,;I0=I-8H[GkGe;_kyPi?`FdFdFdFdFd<_^rFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGe}W{v>rxEuG}b>_B2@I5HD3CS9S}M{{LyyIwzMx[4@@@@@'`J^@S-@;Wgc]qz>==>z`};iEn>tYcGpzLxKtvN|G_D`E_B]x~Pi?`FdFdFdFdFd<_^rFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGe}\}v==>}w{el:TF\?_XR}==>bt;^Fd?hXZAmxEu}CqtI{GdDeEdAb}Pi?`FdFdFdFdFd<_^rFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGe{Szs2mu><;;`F^@X(@W|Qj>_FdGe@a;^<_0YWnFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdEcFd\q`s^rYn|zpsxgd=MGRASQO|DtyEuxDvxEu~\}`~^~Ws[{9:D5@>Ya^@2=@@@@@2r|nu;qxEu}G{rBmH0;H.<[db?,:>>202vws8oxEu|I~rAkI'(I&)J()J()A!0> 0?!0>@BwCaBY7Q[jXTWTEcDcFdFd<_:^;^-VkyFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd<_s}w\qbt_viqa}b~c~bgTbQdReQ^U[Y\W\RZfUW{VxV[ZXYF>DBQUTD@@@@@@@@@@6w~ky:^FdFdFdFdFdDeGdtI{}CqxEuI|Z7QC,4I0=B,4]8UI~xEu}BpqJ}EeEeDcEc~qW^XnEcDcDcEcFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd;_wFe8]?`7edK~9jv?s~A}d6XB''J*2E()P.a>a=_>_}oQYRk~>_<_=_>_FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd=`myVmKgPiJmlYLs{PySgFg@4GI7NE6IP9TyEwyFvyDtyDtU\JbN`JUYeccccce`F^EZF]F]F]F]F]FMFABBBBBBBBBB:pvt}xipD[N`N`N`N`N`L`N`oLtIzqJ}vMW>_D5GI7N@4G^A`S{PyMtuSPjPjOiPiu^e_rzPiOiOiPiFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdEcDcEc8]ato|;_FeAhNayDtyDtxEuxEuyDtyDtyDtyEtyCsxCsxCsxCsxCsxCsxCs}ExtAnK.`?`7\Jfs6aAg@gAgFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiFiGiCh@gAgAgAgAgAg=eBhZp4[?`2Yas~FdaFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd?`Pis}<_FdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdCbGe^r<_Fd;^bt`Fd/FdFdFdFdFdFdFdFdFdFdGeDc:^;^;^;^;^;^;^8]CbGeFdFdFdFdFd>_Qjp{.W;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^;^6\<_Vm.W;^-V\q/FdFdFdFdFdFdFdFdFdFdFdAbOiq|o{o{o{o{o{o{t~Tl@aFdFdFdFdFdDbJfcucuatbtkyo{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{mzo{xkyo{jxz⊊FdFdFdFdFdFdFdFdFdFd=_Vm}at;^FdFdFdFdFdGeEc;^;^8]:]FdRFdFdFdFdFdFdFdFdFd>`Tl^r<_FdFdFdFdFdFdFdFdFdDcEcS?h ?h=iDeGcFdFdFdFdFd=_Vm~at;^FdFdFdFdFdFdFdFdFdDcEc~튊 XZZYLaDeFdFdFdFdFd@aOiu~s}s}s}s}s}s}xUl?aFdFdFdFdFdFdFdFdFdEcEcmzvs}o{q|r}r|s}Am,>gW[=iFdFdFdFdFdGeDc<_<_<_<_<_<_<_;^CbGeFdFdFdFdFdFdFdFdFdFdFd=`;^<_/Wky{7];_8]=`,}BpU\?hFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFdFd;^o{}AbEdCbGeCs7V_=lFhFhCgAfAfAgBfFdFdFdFd@a?a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@aEdFdFd:^r};_?a=_Ab7TW@cF_E_H`LaKaLaJbFdFdFdFdMgNhMhMhMhMhMhMhMhMhMhMhMhMhMhMhMhGdEdFd<_kyxIfKhIfNhI1>I1>I1>B-5`;ZIwEw}BpnLBfEdCbGePi?`FdFdGdGeGe=`_rky;_Ge?aUlI-8nI-8B*-a7UG}zDsAlqK~BfEdCbGePi?`FdFdDcCbCb8]\qjx6\Cb;^RknI0=B,2`9YIxEu~BnoLAfDdAbFeOi>_EdEdEdEdEd;^^rky8]Ed=_SlI0=B,2`9YIxEu~BnnL?hAf?dCgMg;^AbAbAbAbAb6\]qky4[Ab:^Qj񊊊B,2B`9YIxEuyDtvFxnLnLpKnLWiRnTlMhx{}}}}}o{OiTlPiZpWmQjTlTlTlTlTlNhhw}{`sOiTlKgq}B`9YjIxEuwEwyDt~An~BnAl}BqD]8b>`3Zq|}u~2Z>`7\EdAb8^>`>`>`>`>`.Wgv|Ni5[>`/YhwjI~xEuxEuxEuxEuxEuzDswEwKaAfFd<_s}s}<_Fd@aMhIfAbFdFdFdFdFd:^gvTl>`Fd:^xEuxEuxEuxEuxEuzDswEwKaAfFd;^{|o{.W:^4ZAc>`5\:^8]CbGeFd:^gvMh2ZGdxEumxEuxEuxEuzDswEwKaAfFdAb\pkygvasu~gvkyhwnzn{btgv`szlyixkyn{QiBaFd:^gvhweugvgvnzcumxEuGxEuxEuzDswEwKaAfFdGe>`8]:^-V\pKg0Y:^,Vev~]q<^Fd:^gv<_6\8^4[狊HxEuxEuzDswEwKaAfFdFdFdFdFd;^btTl>`Fd:^kyZn=_Fd:^gvGeCbEdAbzDsowEwKaAfFdGe@a<_=_0Y]qMh4[=_.YfwSk3Z=_.YbsGeCbowEw KaAfFdCcSk\qZnRjnzcuTlZnQjs~hwSkZnQjq|Ge!Af>Fd;_w><_6s}劊劊6 VߊߊV .a}Ċڊ犊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊񊊊犊ڊĊ}a.??????( :G!ixv}*U}Q!|||uuui!`?xv}*U}Q!|||yyy?ixv}*U}Q!|||?\aLW^HU413+++,,,...!!!"""...,,,*++635cLX_IT^GT_HUxa-UV)xv}*U}Q!|||FB#)>%<-9*>%@'hHV\|w{b%xv}*U}Q!|||OrYcZYa @F'EOX|}X}LZGZhkronklmmmmmlllllllllmmmmmmlllpopyyyu{J[IZZIW`HP,;F6C>EJKKK\RXsZgy{l{z}a%xv}*U}Q!|||rca\_1 &  w8ps:t?b9c?d=b=#8A+9)YIQ{jC-Wv}w`&xv}*U}Q!{{}CeqWbT_rdzextkoleiPSS\Z^pppymyoznyqipthlZY\WVR9Ec&>q>9UP2?D6@8;9QEPP~WoKm>M$5u|w`&xv}*U}Q!##D1;6% ;9~6{}Z|]u>kGGqQ))( $#RW$[ B5w}w`&xv}*U}Q!dSUkcoqpPQYLLI_BZg=^NDM:B>bVcgsnxdwU\EGrA9[: 5@&@D'B21\?uCI2w}w`&xv}*U}Q!=RC%P,FA>  c4b>|jy8h_\Md6^Cj6ZI2w}w`&xv}*U}Q!QWw/=(9NN;5>030oRnX~xft<`SZoOW@o.+$%>-3"B$+A6v}w`&xv}*U}Q!zZfwU@6!nxMvF|'&I*FE|~e}eu?`GdEdFcEfF\I-9H0=yVsFpmlc%xv}*UkiV@hYRLNJXjlL{qLsL6BP8CsEoyAw~r}d_aaaaaaaaaaa`c^qGcIeEcFcFcFbEfF[H-8H/<|Lvt8bikf$xv}*UTOT"1A$1p=jw8s{`Z\\\\\\\\\\\[^Wq7aDgFhEhEhEgEkGaN0k\aS\M-wu}*UPda_ihwset`=Hb 363<-7)0x*U0B@t{w~QEx?:A%0F(:A|~E{zU[ZZZZ]^]]]]]]]]]]]^][XTqE*2^]~|xXOmA3Mipnǻt?dtx,Vfu}}eeRSF1d4*Z0!<)(@(BY1XYEZbgdgegxotxouturilkklg]^^^^^^]^^^^^^^^^^^]^^\{\zZ|0.K#>(30.$$^[WBG3\nҶűlZne'R?eq|H{Er @#>DbxfV[ZZZ[^]]]]]^^^^^^^^^^^^^^^^\LH ^]oudTsb6UT?p;+mtŲn)`ufBeerXYI7uG6s_<]d>\J,I=!=G>GEHEeYehttrrtc]_^^^^]^^^^^^^^^^^^^^^^^^^^^\f~}d|?'>;"90-"G#WY)tS'kV(qK%Y=#99 6&"]^[UsXaQZcT[x]u}[|{vyxxyw`^_^^]^^^^^^^^^^^^^^^^^^^^^^^^]^^\nkf=`c<\'"]3dk:sCIGHEtDon@kZ8PR2J^]]^\VrpA}C&A?OPo,q@K7NEF%"'"IQo~}_v4pR"@ }@yxFu|xSZYYYY]^]]]^^^^^^^^^^^^^^^^^^^^^^^^]^]ZXv7rs=nJ0;I1:N3@D0.JTHnC`tDmsCiuDoxDuxEuI~wEsK1] 7DWHfa~LWR`jjOMGELHi~{vxay|F~_>_$(%>3>V|Yzr[_^^^^^]^^^^^^^^^^^^^^^^^^^^^^^^^^]^]^hg{oyCvsDo9$/8#.R2HO3?ELFvDqyExxEwxEvwEtwDtxEvrBnQ3GS4H^^^]]^]Wl@zX,Py('&!FGxzeVhR6LR6I)!';.6T>HdE^}L|}_|j[_^^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^]`ov@suEruDpi=do@k{GxwDuyEwxEuxEuxEuxEuxEuxEuxEuxEuxDuwDtwDt^^^^^]]^^Xl~{fJ0ipBouCri=dD-8A)6o@l|GyxDwzExyExyExyExyExyExyExyExyExyExyExyEx^^^^^^^]^]^_`]bvJtyDwR4HO3B#O4AT5JzCxwMt}[a````^]^^^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^[dS>IN2@o@myGrJMLLLLLLLLLLL^^^^^^^^]^]\][a{Gt~@vP.@K,6 I.9P1E|A{zMw}X]\\\\]^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^^YcR:FL,= n@iwGmJMMMMMMMMMMMM]]]]]]]]]^^^^^^ccaa]Wpzvtxz{wyy|{}iaddddddb]^^^^^^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^Zg 4!+D-:=(4F.;!?'4C*9IMLMLLLLLLLLLLL```````a_]^]]^][[\\_YbX\[[[[[\^]]]]]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^Zi|3!(O4?E.7P4@$A-,E/0JNLLMMMMMMMMMMMGGGGGGHER`]^^]^^^^^^\dgffggghhhhhh_]^^^^^^^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^Zg|}++++*+9%19$.Y3W`5_iin@je:c]3\^4]^4\^4]\4Yb6bDELMLMMMMMMMMMMMM999999:6Jb]^^^^]]]]]^[ZZZZZZZZZZZZ]^]]]]]]]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^Zft~qF/9J1:uFkKwwFovEnwFovEnyGq|It|Is|Is|ItzIoI{OOMLMLLLLLLLLLLLLRRRRRRRQW_]^^^^^^^^^]^^^^^^^^^^^^^^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]_Yj`\*!/'c:^e;^FHHHHHHGHGHHIMMMMMMMMMMMMMMMMM````````_]^]^^^^^^^^^]]]]]]]]]]]]]]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]_WoAHF/4L3?wEpwFnLNMMMMMMMMLJJIIIIIIIIIIIIIIIII]]]]]]]]]^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^[c|5t@\7R`9YGHLMLLLLMMMLP_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]`W9H2:~H{G~MNMLMMLMKIJFRyuuuuuuuuuuuuuuuuuu^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^^^^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]^]^^^^^^^^^^^^^^^^]_ZF!-Q4JwEsxDwLLLMMLMLRXWV\spqqqqqqqqqqqqqqqqq^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]^][Z]^]^^^^^^^^^^^^^^^^^^^^^^^^^^^^]_`_`^]^^^^^^^^^^^^^^^^^]_YD )O4GxEuyExLMLMLMLF_ztvuqrrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^^]]]]]]]]^]^^^^]^]^ef_]^]^^^^^^^^]]]]]]^]^^^^^^^^^]]^YWXW[^]^^^^^^^^^^^^^^^^]_YD!*O4HxEtyEwLMLLMLQQatpqqrqrrrrrrrrrrrrrrrrr^^^^^^^^^^^^^]^______^]^^^^^]^\`{d[^]^^^^^^^]^____^]^^^^^^^^^^]]_A:>9P`]^^^^^^^^^^^^^^^^]_YD$P2DzFw{FzLMLLMHdxrqrrrqrrrrrrrqqqqqqqqqqq^^]^]]]^]^^^]]]\\\\\[]^]]]^]]^]`c[^]]]]]]]]^]\\\[]^]]]]]]]^^^]]_D>A=Q`]^^^^^^^^^^^^^^^^]_YD%3O8NuDpvCtLMLLMIbtqrqrrrrrrrrrqrrrrrrrrrrr^^^]^_^]^^^]]_\@?@?@??@;T`\[]^]^]^]]]]^]]]]]]]]]_\?>@>>?>>>>>?G`]^^^^]]^^^^^]]]]]]^^]]^^^^^^^]`ej{yxGvyDv`8^R2JGMPQatprqrrrrrqteZ[YX]_^]^]]_W=@????@;WcdhdcX9>======?@?????@?==??<;<<<<<<<9Da]^^]]]^ZYYX\a```a`ZZ`a\Z[ZZZZ[ZT_xHvyCwG/8/&GSMG_zsqrrrrrrqtcqdpbz}z|i\__^`X=A@@@@@>FJHGHJF?@@@@@@@@?@@@?@@@AA@@SUTTTTUUUUW^]]]^^^Zt~{gIvOzNyNyLzPxododPwI|ihrcoeoeoeoeoeoepdoeqc|Y{|Y{wFvwEvl@jj@fg;ia6exBGOV^spqqrrqqsf}^z=====>@????????????@>;<<<;<^a````][[[\a```[Z`[~iy5\?a>a>`;bC^8g8gD^6fs@s6b~:h9g9g9g9g9g9g9g9h|uQ)<8g2Wz>>>>=::::::::::::;7Eb]^^^^\[[[\Vw{|6[@_=`@]|:j6bHZ5dmC|8iv>rt>t{>o?i@l|Bp|Ao=g{Bph;i>hAfAfAfAfAfAfAfAfBf:jpLDwX6L:),@,06)"O1?xBg~C}KOwxwwuvoljhhhhhhhheQeQdRgTPIrBEfeGtxGsJJTnidkkxRU}U}U}T}V|GBCCCCCBGVUUUUUUUUUUUUSZhfffffgggggduznprwjTWZZYZYYcSdS[YWZbTcSoK{DrmL`TiNyDrrH{bRcRYWYWbRdQ[V[WL_CeP]]VQ\DdGcFcFcFcFcFcFcGcDe\TfQ_Bi[6N]9V[7Rf=azGxyE~B~DvXvYvYtX_abccdddddddd@g@g@g?gEh?mfQ?kwBl{Djg8T<$D!*G"F"F"F"F"F"I JJ J J J K!FW /6j3b3c3c3c3c3c3c3c3c3c3c3c3c4d~7f~7f~7f~7f~7f~7f~7f~7f~7f~7f~7f6e|9jy;oz;my;n{h@mBej>jFd8ltGx9^WX:jeP9^iN?gGcEdEdEdEdEdEdEdFcCf9jeSDv|G{~G{zFx{Fym@e:&@(#A$A$B$="j6WwYH>ZH>YH>ZH>ZH>ZH>YH?ZG?ZH?ZI@ZH?ZG?ZH@[F>VQCcoQkOkOkOkOkOkOkOkOkOkOkOkOkOkOlNlNlNlNlNlNlNlNlNlNlNlNlNmMmNmNlMkMkMlLjNIbEefPqI}P^Ag^UtHz[W@gR]sH{eQBfJalMlMJaBfdQrI|Q]>hYWrH|\VBfFcEdFdFdFdFdFdFcEdHbBfeP{BnvEtvDsvDs{EvoCpFZF;WsQvW~|U|}V|}V|}V|}V|}V|}V|}V|}V|}V|}V|EdEdEdEdEdFcBe?g@g@fBgEiEiEiEiEiEiEiEiEhEiBg@fChFiChAf@fdFcEdd;eCdGcCe?gBeFcEdFdFdFdFdFdFdEdFcDd`v^q@aGdFdFdEdFcFdFdFdFdFd@a{Um=_t~ct?`GdEcFdFdFdFdFdFdEdFc@glL{BpwEvxDtxEuxDtwEu{BqnJAfFcEcFdFdEcGd>`{as?`FdBbDcFdEdCbCbCbCbDc=_~Qj4Zwfu?`GdFdFdEdFdFdFdFdFdFc@glL{BpwEvxDtxEuxDtwEu{BqnJAfFcEcFdFdEdFcEbLgPjJf?``roy<]Rj~SjHdv~\oKfJeEbEcDbEbFcEcEbEbEbEbEb?ekK{BovEuxEuwDtxDtwEu{BqnJAfFcEcFdEdFcAf@gAcAaEd?_gyw2_QpHj7aYt:bEiEhHkMmJlDhFiLmLmLmLmMlGpqPEvyFxwDtxEuxDtwEu{BqnJAfFcEcFdFcDdePpI}O_DfHc@e^]TuuShKnN{V{zU{|Uz{TzYDQXEO302***+,,+,,+,,+,,+,,+,,+,,+,,+,,+,,+,,*,,*,,*,,*,,+,-'*)Dm@i>j|f<_{FzwDsxDuwEu{BqnJAfFcEcFdFcEdWZ]WJaDdFcDeO^\XYYXXYXZY]WyGwvEs&"MKM[WT@bt6l9j8j8j8j8j8j8j8j7k&~%%%&#~8GDDDDDDDDDE=uQ=DCCCCCCCCCC~EBLAEDDDDDDDDDDDDCCDDDALY}Iw3hApZRz8j7j8j6jNW[ZZ[2)0 T1PI}vDsxEuwEu{BqnJAfFcEcFdEdFd>>>>>>>>@1iEQOOOOOOOOONC>>>>>>>>>>>>>>>?:Redif^`fffd/--G'DKuCrxEuwEu{BqnJAfFcEcFdGcEbarjwNgDbGcFcGcHbHbFcL`_T`SyFwvCr  opqgX\\\\[\YMM?>>>>>?@@@@@@@@@@A4cCNLLLLLLLMMPttFHQNLQ^\\\\[n~$07I)GK~uCrxEuwEu{BqnJAfFcEcFdBf>d{Tp:cCgAfAfAfBe=iM_>i{BpyFvuCr  qrsiZ^^^]^b[:hH[3eqF{=e@l?k?k?k?k?j@l{CqzBpyFvuCrprriZ^]]`U8=???@@@@@@@@@@@@@?@?:)fCOLMMMLND`(3?@?@@@@@@@@@@@@@@@@@@@@???@?9Aa_^^\f6CH)GK~uCrxEuwEu{BqnJAfFcEcFdmKoJMaAhdQpI}mLnKnKnKnKmKnKnKoJ~xFwuDs sstiZ^^]_V=A??@@@@@@@@@@@@@?@??PF`ENLMMMLNG_=B@?@@@@@@@@@@@@@@@@@@@@@@@@?@?CYX]^\f6CI)HK~uCrxEuwEu{BqnJAfFcEcFdAfAfBbCaBeAg?e>e>e>e?eAfAf?gFcyDtzCrR5FF)7~|kZ^]^aW<@?@@@@@@@@@@@@@@?@>?M;LMLMMMLMM?Z:@@@@@@@@@@@@@@@@@@@@@@@@@@@@?@?<>\^\f6CG(FK~uCrxEuwEu{BqnJAfFcEcFdFcFcJfKgGdEbIeKfKeLfJeFcGcDdJatGztGxL2AA'3|u|jZ^^\]U=@?@@@@@@@@@@@@@@?@>?XINLMMMLMLPQf:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?@?A\^\f!8EJ+IK~uCrxEuwEu{BqnJAfFcEcFdFdCbVm8]p{u~>`GdEdFcFdFcI3ED+3oCm~;me[^`Q<@@?@@@@@@@@@@@@@@@?@>?WGNLMMLMNAj1A?@?@@@@@@@@@@@@@@@@@@@@@@@@@@@?@?@\^]_ONbB")f>b|FzwDsxDuwEu{BqnJAfFcEcFdFdCbWm8]p{v>`GdEcEcEdEcI3FF+4oCm~:md[^`Q;@@?@@@@@@@@@@@@@@@?@>?WGNLMMLLOCl0@??@@@@@@@@@@@@@@@@@@@@@@@@@@@@?@?@\^]`OMaB")f>b|FzwDsxDuwEu{BqnJAfFcEcFdFcDb~Um@`KfEcfvs}>`GdEcFcEdFcpFvuBnuFvz9ie[^`Q<@?@@@@@@@@@@@@@@@@?@>?WGNLMLPD~|=JAB?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?@?A\\~--0K+IK~uCrxEuwEu{BqnJBfGcEcFdAf>eVm@`Gd;^eux>_GdEcFcEdFcyEvAoJ}>shZ^`Q<@?@@@@@@@@@@@@@@@@?@>?WGNLLNI4zy)).@??@@@@@@@@@@@@@@@@@@@@@@@@@@?@?<>^^+,,F'CKuCrxEuwEu{BpmK?WGNLPD{@9@@?@@@@@@@@@@@@@@@@@@@@@@@@?@>CYWMM`MGYRBMVBLD/:5")a9[}G{vDsxEuwEuxDtvFwoJ~kLEcFd?k>hI]?WGMNF-fy6?@@@@@@@@@@@@@@@@@@@@@@@@@@?@=DebE'DK+:K-=N1AI1;g=a{FzwDsxEuxDtwEuxDt}AnwEuEcFdT[TZHcFeFdEcFdEcFdGdFdEcFdGdGdFdFcFbHh:0H-fsj]R<@?@@@@@@@@@@@@@@@@?@AAVGOCoE;D@?@@@@@@@@@@@@@@@@@@@@@@@@?@?@HIWY$&1 >(4F/9c;^{FyvDrvDswDtxEuwEuyDssHzEcFdAfAfEdFcEdEcEcEcEcEcEcFdDc=_?`EcFdEcEhK;QB"*ysss[R<@???@@@@@@@@@@@@@?@?23XGP=X,>@?@@@@@@@@@@@@@@@@@@@@@@@@?@?<>^b (8$/I1;g@@@@@@@@@@@@?A;FPNPKxxxxJ>A?@?@@@@@@@@@@@@@@@@@@@@@@?@>Alq)*4+$+$=(5L1>I9SGEjRGrgRdQeQcRYXXXIcAa}vEcFdBb7\~~>_Ec7\9]@`@a@a@`@e@nA?Z7j`a}Zosg;@@@@@@@@@@@@?A;FMKE4G7)?@?@@@@@@@@@@@@@@@@@@??????@=BX?KS3D(Q),CHs@sAi@fAf=hEd>j?jKe=foLkFdEcSlPj{|jx@aJfXoWnVmVmVmWnJdEgREiP*=m[n~rP_|o=@@@@@@@@@@@@?A;FOMjcT'k^E=@?@@@@@@@@@@@@@@@@?@@@@@?@>Awx}}uxN8EI-:/,!8,DJUAw48@??@@@@@@@@@@?A:FEE7*:T3C?@@@@@@@@@@@@@@@?@???=>@???B,;B!/F/;@,2uCnHz_[:o`U7aiJ;eCaFdEd@g@fI,6KBY5buFdDbxjxKfRjKfZoZnGjhSrFxsHz}CpdTA_F|AA?@@@@@@@@@@@@?A;E]]H;SEU6C?@@@@@@@@@@@@@@?@?@AADB?@@AJ7EJ-:O3FL0>gCowGyWX=g_ZKpkWKlNgEcFdFcFcH;VI2CHWA\ot|DcDcCbCbCbCbCb:]duZo5d_T>hdS@`D}<>@@?@@@@@@@@@@@?@?::B)N.A@?@@@@@@@@@@@@@?@>CDMOeW;AF^F_I0>G+4tCoCsO\=fEc=_ev>_EcEcEdFdEjI7NI*0H-:A'0`7V}DxwAqxAsxArxArxArxArxArGeHeFdFdFdEcHeBbgv]o>eaU@nbS@\FzAB?@?@@@@?@@@?@@@?@@@C*Z;C?@?@@@@@@@@@@@@?@>CEXOaVH4EF`EbHc@_xFdEcFcEhI:TJ&(GSEeFaGcGbGbGbGbGbGbGbOiBbFd;^ozdt:dHOE!XDM:>???@?@>;=@??@@?@?:#b.D??@@@@@@@@@@@?@;PdTzC$G,9I+8I,8I+2I.:EbFfCc:_zCbBbFcFhG9RG%%FUEiEcDdDdDdDdDdDdDdDdNhOiHe?`s}ku@\KWR38RM^ZXB@@?A8e`8A?@?@=Ac2E?@@@@@@@@@@@@?@?C>[zyrmsD'3I9MF^F]GdEcyKe?eiIzy`}nz5cBVEI:Gc_74>@?1othk6A???@epLAnT[AgE_C[A^>`>`>`>`>`>`FdFdGd?`wixLho{|owCUKXLL_OQev{H;RU`nU:@?@?AAELv3B?@AA?@@@@@@?A>LXVY7emL~?kU\AaRWe}~yzzzzEcEcGd=_~~`s2Ydt|4cA[FJ$'D-YgYVK<@??@>&(\.C@=58@?@@???@:0MiUA C5N=j>b<^@aKf>erI{_gvnzkuFPJS|bb~ewb{UH~g^;B?A:G4{4F;Lsb=B??AAA:^s]N]vO^ELR\s~nynzp{KfAcV[XShqp{tw~FdFdEcFdAa>`Ec?`eu:d@cs:tu7pz:m5bRY6ap}vf-<@B7MC|;:Vrf.:@@97?5wiTVAG=`7iRmJfCbDf8bxFdFdFdEcFdGdGe?`euctftggwMy{FvTMz>Kzj`f}qaX;B8M@p1Q{pa`??^eI9mzl~b\}@EpV]fwmyJfCbIeA`u~FdFdFdFdEcEcGd>`hwxKuz=yU-:A!f6Xw8xbyyy4B4K@&LS`t==~Ub[gFn|Cvz^wo:FCPG/Qnnq~zBAqt{{pnOi=gm`WqdkDyf~v~u~JfCbXnVm{FdFdFdFdFdFdEcFdCb7\UlSp4gcP{=mv?s~8ijF;WIkg_ FX|65S}~u8ss/<$DS<^usUp?`=_Bb:]FdFdFdFdFdFdFdEcGeAa[p`qIjl\PttP}qJ}fSK_Rj[YJO4RQs~8KDWvu{q}zCuuGsICMiCrvv_uHeGdRkNiFdFdFdFdFdFdFdEcGd?`[phz1cQZ=lq;dA#K$0|8i|9l;W0TKQOQJEUDaEW>z&*)))%wzGe-V@Z?_^K6fm4Z:!&N+@~CwsDxBfCggV}CbCbFdFdFdFdFdFdFdEcGd@aXnmxAeZ^IuoGoC2AM6KwFvwGwOaG_]c`dRC[FdFYExBBBCC?|}XlG`LcEe]V{HygDlB1=S9QKxuLzKeKfiY~JfKfFdFdFdFdFdFdFdFdFdEcGdAaRk}=aJawDuxCtwDuwDuwDuwDuvDt}G{_9WD,6I/=H.bKbxEuxEtxEtxEtxDsxDsvCs}Fz_8WD-6I/=H/g{FyvDu}Ap`S@gHdAbRl}=_KfFdFdFdFdFdEcFdFdFdFdFdEcGeIeOi]lE_IbF`F`F`F`FaFaFaFaFaFaGaF`IaJbKcD^esxAaWmEdEdEdFdEcFdBb?`@a?`AaFdFd@`HeUn7^@c@b@b@b@b@b@b@b@b@b@b@b@b>b>b@b6^cut}/WMhEdjFcFcEdGd@`fvzky@`GdFdHdRkSk}~}}}}}}}}}}}}~~~||jGc"AfDdFcGd=_v~}=_GdEdEc@`Aa"gOL_CdGcDbRjZoYo\pTlEcGdGdGdHeHeYoWmnzSlr|=gCMbBlBg@g@c@`<_7\;^?`>`>`>`>`>`@a9]]q)T`rC8CHM{DGmZQeRR]BcXmmziwjxjxjxjxjxjxKfDcbseu~o{ctjxhwyG Q! $D')ohaP0_XmUl(Teu;^6[?`5[~nz2Y>`z4ZZ7PxDt{vEv{BqaT=eXm|gvNhs}x~YoVmKf@azzjxCc{hym?huFwV}Ao`S@gDb3ZJfly+VOiNh6[zbs3ZMhVIxDt3W[VAeKfNhZot}Dc^rWnEc}my*T9StGx3[?_r?YoxDtxFv!iˊ芊芊ˊi!HeDc??(@ @xuMUtx0#VuMUtU_HP(%&### "!F8?Z@M}kmVq~~FuMUt_H;F$,pGtCUjnurqosssrqqnop|vqYgEDs1%+<24udn~_[_:ZGuMUtd;@G,>Vysnooggy}z|yojR\r-8o5/*2TZU?႔GuMUtcu{\NH/$iBbldd{m{ILP%D M7Gw@GuMUtysRO{MedeyGebZE";weAb?HuMXsp/1lU"R\GRfcgw~?aGg[T2!,xDzQFuMȭK~tZ0;Aq1]Q?Ei]j}B`FeB^K2Acynx|IuMjbZgvXPX8iD9Ck[osuuuutvXsCfDiF`M3CzwDq{_9vMzbvp:u/VuS"H5$[JT{a}~w{jWZZZZY\wltXUMSNUIMz.(Z}fGMsPpxLa|{]x`^8H/' 5/,aQ[g{y~eXZ\_^^^^_^[aa/5gI$/&.)_|_;Gb8bIyRgwTfIK"7 93=m~~`YZ]_^^]^]]]^]_tUt5,*?&5  ]Zvm+!XpyHwg[lE?*5*)%lKgm~~]Z^^^^]]]^^^^]^]]^83!FPNzGtO2D ^^Zzq2"$[ufNXbB6Bm|Ow0,K2Kw{Z\\^^^]]]^^^^^^^^^^d\X/Q=,,w@KoBeuCqxEvuCqT5H]^^Yzp/,\OLa(Eo^Splbn[vDun?lrAqqBnF.=  nAlt[_^^^^^^^^^^^^^^^^]^^]bLd<^eJzv@n^:V54KxDxzEzzEzzEzzEzzEz]]]^]a]qbwh8V_]^]^^]]_YBDs`:\LMKktpqrqrpigggg^`2]rQ`^VD<:KP2bx``_\`RNPM\O9EQOOR^^]PN[^]]^^]^^]`gm]4WGOKktqrqroz}qʲñıı[\$NcMa`J=;;:@^]^`]Z^``]]^Z[Z_}fuFpy@L^qsqqsjflycX\I<>=FX\P=>>=@AA@<<;=====<<YjowqpgmMmIG8Wl<`@afX]Q@CADNNNNNNL_igfecnyztOXSWmG}TVfKwAsrI|yFuzEtZY_VhPFeFeM`BgBgCfCeAelQZ7SJ0=f>ZASdcd`^^^^CeDeDhgPsJ{R;ZC1DH2FG2FH1EH0EH/FG/CM2MrCzqByqByqByqByqByqBypCzoDzoDzoDzpDzpCyoD{mF~nF~rG{nIEcmJHagNK^`QS[\U\UTZdOP]mKDdFcFcFcGc@fnL}Du}G|XG@A=JXKXGGlmk]4[|I{{AoZXe@h;jTYP4376/]ddcMDDD@?@@A8hDQOOLKbA?@@@@@???AIOabcr Y.S}J}zAoZX@@@@@@@@@?=>K^]\%[/S}J}zAoZXL\b "Z.R}J}zAoZX@?@@@@@@@@@@?BVNSf0+G-:sCo|G{vFwAmZPdyAfGeCbBbCbBbUlRjCgMNqERQ=?X =$.i@dl=btAlBnXTVsFcCbQjSlXnFdjxcs:`U]q?qjV}`GP@?@@@?B6vC}R7C ;*9PWEd=gaU^KWn~hFc}ZoCbt}pSZ{DtmF~At<@@??@@A6vu.K:A?@@@@@@?@B?@G5CL-GZJ3AH8FH5JF^Hc}dtAfILyI;UFeHaHaHaHaMhEdztCRSALY?@;yT;C4O7A@@?@?@=RppH0?F]Ed|axUQiLBgEbCdCcCcDbCb\pwv@SQCQ|CSeJ=D+a_:>>@@A_Wm{Yuax`x`z`z`zay]vXteuyQ]wHe@emz|Qj@a<^Tlt~w~JIUQZ@`MiXmVm[pHeOizUmzቊG).Zu>fYWp{t}Lg]qy|TlzZ}JuFx}}CoLWeyt}Xn~Oi?`p{=_~Vm[:Y@mVR]Dft}zRkSky:^VXnhM#Rwxˉˊx\q??(0` $QKNQ}bIѡKNM\fH>^686999677C?>PF^XOfJl{v[KN$OcpVlUJIs`tzlk~MGH%M>.3RAS:Uc]KNsbGHJ`Nzl8z?eHz3$C<,tI\slh{rc[\_^^^^^^^^^]^[`sxFboS{t@k'"D'BJ{xDy{E{yEy|F|```]cjxc~YE`(":,)qG\}pn}a`^[^^]^^^^^^^^^^]be`a$# R/QOKLLLOOO[\^^_z{y}uZ[\]]]^^]^^^^^^^^^]^Z{^YQ?%6_;O7!0(#E'CINMMMMOONZ^]]]ZZZY[^^^^^^]^^]^]]]^]^^]_XB!:i=gPJNNMLKKKKK```^]]]]^^^^\^^^^]]]^^^]^_^]^^^^^^\bq8gNLLLTjijjjjj]\\^]^``]]]_g]]]]^`^]]]^\W[^]^^^]`L^jr8cPLPjqsssuvvv]aa]_ZQR_b\ar^```YP]``^_W8P`]^]^]`Kl]5^NJcuqqqqjgggcB~AzdZE;CL:jc]]WJJRS:HLJV_[PX_^^^]][hgEfFLctpqqswaWS]S;>CSOQEHC>>?B@@?:Rb\bb[X]]_cai}p@`vGrscvmxkwkwkwFcJdGg?dFhBg@eLmh}Zuzsttuuvvvvvwvvyxx|jy\q`sbvNjAcFbEbAdTYuEuyBpnMAggz?bZr^pLjHjUpTog}j~HjHkKkIp`\}ApyDsnK>aq{M_TZBewhl[n~~mwURQMIFPJGNJHNJHQHGNFDcRTrZ`oY^pY^pY^ja_hc`hc`hc`gd`ia`pY^pY^pY^pY^t[\UKkbQdNGr49bwDnzCsnL?bozL_TZAfTVXUiO@59<=4by-_x/_w.`xrr0~A>?>=B>IGkHm;i@@@@??@HWcr>iz?8K}lK~?boz`TU\iIeJjK}K:1gqne]L;?>?@@?H_GPCW6A@@@@@@?=>Qd/g|@7K}lK~?bozMhRkVnbtBfR`T8SqcrdYF>@?@?A8~|BQEdG>@?@@@@?@@?@`?pQ'EI{mK~?bo{]qs}RjMf@gXJ{vDqaO<@?@@@A9{EGc:jUcjM(GHzlK=cozfTNiBaOiFdBbO`/0J[S>@?@@?B6xAeT8A?@@@@@@@?OVTgD.3[5XI~wEsXRo}IaBbAa=_JfTkAeP;U}N8>@?@@?AsC^=@@@@@@@@@>I>jBco>f?hbN`yAbMhduasSk[oF_9#(HCdaRdRJ_~{Kg~hwJflyp}Hei@`piWH>@@A7lm>8A?@@?@???B_RYK'8E=h\VAdMaQFr^j~PjUlQjnz|a\_???@@=?>L7?B?@@@?@MH@L.GfNNj}ww{BeC\B<[]FX}UzyV|zU|kxBar||ISeXbU9>JE?>O+D@@@?CZS9?G:VE^iws|HhO@aFWD[B\B[>_gv}IN~ShW=iNA+R<<@@?:`XDX=Zhz`siGIhRbr`tCbSkMhx{OO~y\zX}gM5f6b=>BgHKoYgt`sQWpFdCbBayna8bc@d4Uob[ZtkQXi[pDgEcFdEcMhp|hXqI~TfLA}G|o}d>jNBQUgxvr|Fd~FcFdEcFds}lykVyX8dbC[v_vE@q@o7GeVoWP[ISCjqfxzaszEdFcEcDcEcs}uyn}g~XOCKzFFwHBuCCuKM]Tftu`rxIcAdduv~Cc@`s}y{{{|zv~SVTKYKeYqUlTlFdmz`s~Tk8VgMjvq|[oo{nzdux~vbZ~AnMZdxvu~u~]q^q[p=PiIbQq|‹򈉊򊊉‚Q̵`( @  jlkwxwۦwavmkuWXjgg|opmonmmmzWXhIO`WGPG.DO`OGlWDik\cyFAu3)acbmS>cvcgIlIGs}fc{lsVWp]I^x_hogijgoDYCBglXUnm=>(GQEL}gntfZ\[\Xq_Sg2F4. bXbP]u{dgbCim_[~p_Z\^^^_[tw\tF$AAzDH,?]a\nXapItqR|DY??3MZLSiqfYZ]^^]^^[c`nv[@":V3UKyEwH[YadenILU[PQxnozp`[\^^^]^^^]_wA98#  ugIYtrsnjkVF^GEF_XU]]]^_on>ZusjxumiMBFH==XBW\ecisrqqpqnqmsmrnqltovkzi|h|Zs\tTnGfGhFggQDsGX_q~KcXlXiaplz~}~zx~vx{z{|{|z~xy}{tqagAX@W>VtGx{CqN\yQ^Gb[^oVS9B9QZ5Wi6Vg'ao6k{NwIxSksBqFx=aZHzLuLwFuHrB]y<[w/GVR2L~FwL[t]gX\OWiGD.7m^N??>8QJIbI;>=>?H^]RmS>?@A<|{GCY8B@@@@gYDv^K>@?A9o>|K=@???@?D^T6N~ExQXvL\<_CaOl?NbkM;@@@>^|2B@@?@>K6O`M(=}DmjIoJhs}[oUnNdgLteL>B9bTQ;A?@?=GK`k3#PMXU[aYnjxmzdZ[[C??Ek:C?AQShfAx]pi{hbQ<@[6BCKGcYY`g}y\pcvOH;EUe|}U_dpAbr|{j~k`iz~vNbXm{uqengl|^FNsx}wvNklystrack-0.20171212/klystrack/icon/256x256.icns0000644000000000000000000035305413214501362017403 0ustar rootrooticns,is32~סchx~煁pv}q"|ƼYʜڥVVչê֑Ubl~̛|U҈vͩ}RFxbmqnl|b|j€zpve}_pp{bߴϲGYgyjdfkSAgNfhWkGf]^nusb|xdGO[bs~xwsf]Y_WFo}þyJcدqFrqq{}2$JPgm|N1:|gvq`2qlNƞx~~J^s}wvNX{uegAr{k`i~v\cOH;EU|Ud]ihQ<@[6BCKY`}TIVK>E:C?AQf[\\H74;;DŽ6EXdV>{GCʬ7C\g\WG.ܺJIbϽ/D[^b^V9QWVakwxkBF=Zzuwur][G2F[clipz~~~~}qgXWVGC\hh_XWeirq1srqtvz||stnfhgQDXqSKNdjrtzz{vmmj\QSLGLNSW^fN;FQ[luĿysrmnhF;Xrm響ա¿İn>Zusjڬ>IYtrsnjk=PMXjllmm H+J?BNLMMnLPnA9clGGD\DAˎkXgpnmXOG.Őlx Sxu<#`gfsndtuyISdK[$uCNNWgSNL^t|vGAQoUswC_xjRlk|XmsF@u}e`a]kOdoN{HaZaaHN?I?PTaa^zRgXS=LJ.O9?Q\CW~TJFJYjmd[C??B9bQ;A?@?=GK3PX[L|2B@@?@>K6M}jodYc>Y^K>@?A9|K=@?@?D^T~QvS^bV]mS>?@A<|Y8B@8QI;>=>?H^]<LuQG[oS956'6NISsqxaHLLFHBt{NyBI@>B\csqpnmmnlokihZ\T[GGFgG_W]yTN?AVWV[dcitYU_a\XSPDFUnlixmiMBFH==EF_XU]3^_o^]^]U[]bj]`\W`_`PL`]]_W[__^^`\[\]^_],^^]^]^ZjNNZ^\gig`X[]^^]^]]^]^Zl]V| [YadeI[xzp`[\^]^=]_wA u]a\XIq|Y?ZfYZ]^^]^^[c`v@VybXP癙dbmp_Z\^_[twFzHlXnm>Q}tfZ\[\Xq_24}c͊lsV]xogijgDCacbSvIIO`OWkIyF3wavmWgoomWIWG 橚jwl8mkih32} ^i`nV  '}~zwuu)ydqoj~}jQ Mbd~zo <~Xb(?Va߲G[Xz||` *Y8hrj*(dU*cfhJg3X~s{q jGz Sr E{~1n)|7}~(t(z8}~5=yxwx!o+Ly~~wQFGHHGDT`^_`^\kdrjjd]bnsps up zstssquwsrvxw,zfovyvdKs€ {dzcW0Ժů`LᛖڷfϱԀ۔^ āӀӁ jcӁԀցӀӀ ݍg؀׃ӀӁ :g΁Ѐ֮Հӆ ٥Q6O0#CҀܲ~`)\nӅ)̡a#Qs[JzzC,\hӄ&̍{k"B{y{y|O]lPbT؂Ӏԁ'K=plwfJhð廍TDzՀdž%{*d`"nЊ1/ozԀ-Ƈo 4* Ƽu9@QrڀڹkEOǻ@fW^hYƻۊWHzPYƻ߹CC*Ѽƻ,pAj2ƻ۶ۆclIt~HM3Sƻ,ٱ^697>^f{ƻڲ¾ >Pb|v ZAZx~~qqpc8Mv|o{#zuSVYeqlldz scdu~c`}#dc}yngOKFBCMTtr,cdcd}yV8Cvv@oVPICfscdch+|XIfʯo>Bg|ddbaKn8@؞tQipgbkhO\}ðқKgKsW_vNhէצDZzsGhrtxa|SX́#ˇ9:^w|h@W[\[jljz\?&ѹ.Njw{e\?NyTiaidb`0كAêϵT.5IER}q}jfgJD̀ EGc˄ʸc(HKczhkntf`8c̀ |BQEd̃ ɻp'IKb{T\IJKKq˽_GPCɄ ʳgKKbzkv]e^OuoIRPZـĵiKKbz_ZfVUON8?H$Il{&xbS@'JDEEF.Pԟk`{zWC=P(a*,LDCFA,TY=9Fc/]1MJ?f=\C\S Dƥ`tN-,2lk?36mlʨqVB?atfg=gɧu95gae=nɧg+.o+iPɧG<.bJɧݮԁOVJ`kG%.A%ɧٱf>897?FOlɧڱľbz Q=Iqlb~Mdvuu]^[kgjq[ondx~v&SKKYUTFm"`~IAdvC@sy{|zv7~EFEDEsuXCFHCK]fu`x,FFEFslkXb[_E@7GeW[SqxzazEFEMphqTLA}G|dNUxv rF~FCByac4Uob[ZkX[DCSMx{OyXgM5f6b=>BgHYt`Qp>g}ISW=iNA+R<<@@?:`X=h#`iIRb`kBr|IeU9>JE?>O+D@,?CZSGEisHOFDBBPUQn|a_??@@=?>L7?B?@0?@MH@LfN}wBCB]}yzK~hJlpHipWH>@@A7l>8A?@@?@?&B_KE\AMQ^~AMdaS[<_j`YI=@?A8f}@=@)?@@>F_9HadJ~{IBA=JTAP}N8>@?@@?A^=@(>I>job`fNBOFBO/[S>@?@@?B6xT8A?@?OVD[wXo]sRM@XvaO<@?@ A9{:jUMl=oMRVbBRTqdYF>@?@?A8~G>@?@ ?@@?@`?Qm?o`Uiej}:ge]L;?>?@@?HW6A@ ?=>Qd/@l?oXeIHL{+lrdfRFGC?@A8Y>@??@HWcr>?l?o,LTATXi@94-/.0A>?>=B>IGH;<8Nm?oMTBwl~UMPNNQNcroppjhgip!tUbN470>wzn?o?Z^LHUTgjHHKI`}yn>qFJG?FB@LhZzsttuuvwvvyxx|j\`bNAFEATuynAgBAQWCEFDR][YHXUYXIOKIMMLQNTDFG?ck?>sgTdnTWHBAQ]Z[Z[lnmlrn[c^snvab\LSCEBS`Yx|t{}mkeFG@AE;99:;CSOQEHC>>?B@@?:Rb\bb[X]]_caipvcBAdZE;CL:c]]WJJRS:HLJV_[PX_^]][hgw]aa]_ZQR_b\ar^`YP]``^_W8P`]^]^]`K]]\\^]^``]_g]^`^]^\W[^]^ ]`Lr`^]^\^]^]^_^]^ \qOONZ^]ZY[^]^^]^]^]^^]_XBiO [\^^_z{y}uZ[\]^^]^ ]^Z{^?_7(E`]cjxY(:q}}a`^[^^]^%]be$ R]^ZftG!`lze3RIKNٱM\H696CPXJKKNڰϾ}h8mk QQTTUUQQit32{ urttvaux𶟅x xwxtEW ɺMOWhtwo Ï=~Pvtvq )9zuwrh ͲӊJ6jw )bm C+{m Šhg e    utszW6=<<; =6gyup utut{W6=<=5gyup uoAKvwѸ}yl=Qxzٝ 9ld#0ilٿzfZ&@wx硄 t}}۹u}usUSOCЭ Əmsi}sm"!/$ |}g[nv۹{nq uy:Xxyyt~e $yvzz}٥י~}p tpmbvfV`ͩ ~ ܨv ~Ƥ'  Nȵ {c}_e̽ET( n$˥ܩE;qtR4B;]|vw hɞ孩>4os N0:0Vxqsr xzp %E:F>oypVC|twm ';/;2nzĕa6Ęi=n }xE:,DTw˪ Zag 猈KD,s̷jj򽀋oT鸹4$$5>Sjr~qzm '2I:74'BwomujPwy(/=KYXWbyutzQ*s(/;by{xtury H㪫149^yrstuusz kh +':=A;azsututnu? `YML:)[{suutw~vo}s 㗖,Cruupvnvi Ԗ0I~ruuqF4mma)bzsuuqE3mmb)bzsuuqzxA3|рEI~ruuqtrF7рCF~ruuq}~wstрCH~ruuqkh{elkjlqpvrrрCG~ruuqtvvr sр ӀCG~ruuq{ ipvr sҁυҁFH~ruuqwr q΀ۃ͇рѭ7G~ruuqwq|߇阖-Druuqws"MTt [[0P}suuqt`fmijlmssA='"%#" "#! '**>_zsuuq}u{{zzQO2*,-)CVRSRSRSRSRSY[TRXZY]L3?`T7876CFcxttuq‹vxtutuq ouuttuq  pvtutuqpvtutuqpvtutuqnuuttuq putuqovtvp ~wSYZYZYZ[Vc}z{|| ntssvpWZWv~| kljT$*"  !/jbcdf%ejomnmjjhmu_ed}jjx^^v{{xye#Wjde rftsdxrr{iNVRax~Ćppmu<Wgy݀ځ){jb|irtoilpogpqawL,0"?g} wwl[ţӀ־Ə|~jZ]Uo ml ف~ggsbhghmmoor|< ځҀ ج{{vvjfie уڃ݅׋vw8 ֺ ìӂӁ҃ӃǼvv^J@{f[τ ҀӏzturlSsjЁҁӀӎ†oq{yՁ ӃԄ ԂӀӌʯ4C Ձ Ӏԅ ԃӀӌɮ4CԀӀԂԁ ѓӅԀӄӁӌ޲3NptӅӃу{ԄӁԃӃӌ$DwzӅӃӅӃӉ؀ӌ߰*HtwԄӅӆԁӉԁӍ߰)Guxәӂӎ߱-JswӗӛԂӏ:{~ RYςӆӋӱ 4?pnڂՎ΅ӄӉӱ ʶ!'^^Ќ҄ӅڇӄӪھq9:kwononqtssto{҉фԀƿ҃өŠ++1.W_ejijc\]\]Ybч҅墂ցӪ|(?7@,0ш҇ԁǏt{y}ɁԃӢč +:4;49҈хыtv@69E{wԁӤ ̅F=imҍ˅twHBAJxtЁԁӠʊI@ mr͇΃پ{p;=hwpo pxf<8hzրӠόiord86lywxth01fwrtrvc0-g{Ӣӌqw|l98lyqr(ڪc7ҿmhLI'6H^|| ӜэsrpdkxuwuttzPum1(/Px}|ӟхps}oqmirututu{{ڤ]W܀)vy~_%>zсӗđ&vo/.H?ljqxwvttvnGH}AO'~vp@yu|ڀәݕ&rn;:@.`miouu~sZ[u|ӓ0Ք`\"dsokPJv3k Uba--nӂӐ֔"zt,$yr96մsUpm`߯us]\I=GEeՁӏ֔~|>9-WtkqY96֌G Z#{r>xӐ֔ ՏmM d%矚dZ<(BXZdgtuՂӆՔz|K>3.$܁f x#x:0:|{z׀ӈܔʎ~\4<;:>2ɂk u$b6<70n~o+%uw v }%F b^w v }UoYIZ^M>cr[5@B1w v }䅙풑;% 9{|q) #iw v }{󸵐qbrxoiS^pl\RcqU?@9P~mW{3} v }|_ pt8+)Qx{7w v }|ácaFO|}rkmml"mmlpy{WPFCJKXgҘts v }| 腂)%-*%'Ʀ v }|$WU3+,.!".,+5XTTU.5 v }| y҄ v }|u ECCDFӈeccacE GP[r}mo|F D)3Vefho}cr ncyTDSopa 559?EFASgbZf yVih[sZhI0H7EDEBTem vh} omfa'xcZyh.QHYDEC>P_mlTu ^[`[zY`=blggc`_\^`a] qTr >O_dcbjooplcdeeomzl|cfdcd_~_ddc`a dccdd`vy`dkkdcdb`a`add`en^cb^u }Whdcdceeil_b`a `abc^samd ccdd`jbbEDDCF8-//.- .,>FDASgdbl _fdcdakaaDCDG9,/../ -?FDARfc`j _fdcdanxe^IG26FGa_[dYx˿Čl`ceVHD19KLef ffdcd`pzcZ=;$89WTUaWz̀ҍeVZ_K64!+CDfg bbdceapqj\PPJS_j϶ŷvqCG<ir edkidcdb\lpgP=?8FWkƩݾ~8<S^ `_b]dcdap`ZH>FC^wҟʽqztpig`Wky~ ~~fbnmd ccd`wK=-!68bޞŴڏbXC1Qds fbb\}d cdde`u%ttggMFMK`fݟξʭzl\E]wy fbe`~ ddcda`c`udc:7:5Ya}ܛ ӶrߠT=im fbfb dcdbnuj_vzuPSbbw{~"Ϯ]^L\~yz{ fc[Sq{ ccd_sYtc[$仯 ́ 5jb^a feIS`}̌ ̋#ؔM^_0+CC\fc_v_ccddj7*-'7DA dbxfjfonjSFHCT_|̈ ]]̌#Ž7-30CGXgZKWlgcdcc;2W\t dbvY`_j iaNDB:LUẘ EE̋&,!/,CH[oU7Jeaddgf,YbdcljxafonmndgE*[~̈ OMjčˀxu8-,?efdcdcotrsrsn`h}ydfTQE2rü̈PNPKxx̖ʟ*(19EGRQQRXXcaddcda`a`baldccfJBD4}̊A?LNF1̖˲&9/-+%0EBAEffa\cdbgyudccgC3ZaЀ̉NJRJQA̔ʬ $14::9=FEDHccttffdcdcdc_`cdch;"šXGP=̖ι $1]bbdcdb`bdc dem{̏WGMNF-̘ǩ+-11=FDEDEDAEcdKJgmecdcglhcdccdc]c$~̏WGNLPD̘ȵMGBB/"9GDEEDFJLcdfem`d^u_dccdcEAJ>̏WGNLLNI4y̖θ,'KCEEBKifcdcbm`fcv}`dccdcFBF9̏WGNLMLPD|̘˭-+KCEEBJfccddbm]{`dccdc3+C:̏WGNLMMLLOCl̜˯M">FDDEBJfccddbm]{~`ddcdc3+C;̏WGNLMMLMNAj̚˯N">FDDEBJfccdccfgdbefefeccdaGG2'u̍XINLMLMLPQf̗˯8+KCEEBJfccdffbaegeffgcDC5)|̍M;LMLMLMM?ZҀ̕ί6(KCEEBJfccdKJahQILKJFDs̵̍`ENLMLNG_̓ɲ6)KCEEBJfccd?>[eF=@?@CBFCrώfCOLM LND`̏̀˪6)KCEEBJfccd[YxcX[Z\WDFFCr̈dCOLM LMJRrv̍ǵ6)KCEEBJfccdfdpcgf ei_>BFCrЎdCOLMLML=G̏ǧ8)KCEEBJfccdcbrwgbc bbc`TSFCpȃɇcCNLMMPɍ0)KCEEBJfccdddbbcddcef jfFC{݀ۇiEQONC<؍Ʊ-'KCEEBJfccdcdZWadce^XYXXYWGEKWbljk~~Q=DCEB }whpzjWZ) 1IDEEBJfccdceD9[fbgQ8>@><?@??@>CQONMNNMLNbePI^gUHWg]HQfaMMafQI]hWHVfcd cdbfPBEDDEC<=>;QWUVghmQ?BD8! 634769; @eiE9]nQ>dlG9XjP9Ngcd cfjSDGGFF@&($"6<: QQRTIEGGJJTik}|%znprjWZZYSSYZTSKDLTNDHRRWWRQVW_e]V\dceTQB697=GEBDXYYX_abccd BB<>)2<@?[قى̯[_`]:6ZdC8>?@BA=BiiC:alffhihfjLD6),)1BCKOwxwwuvoljhGFbi^Wkw˄ɊŸ wumdfg^SUTTUUWWUUVWWXWXWWVVUXB:;9<@:346DELMLM!4.4-/JNLLMvzy{ !-(.'*IMLMLG@., .1AM :, @GJMJD4345CM >2@GJML~GE-0@FBABF>0+@Dyi\_bQ>BC=-)@GDE~<;$(=BCEEFEE=-& ;@{nbehVAEHB0,@GD7NB4{l^GYnihgec@>66!.>EL_ o@ED=@GDED7Á@,ӱzeV Dڀ)ֳ~LWR`~{aF>(3VY {oCD$#23ELFDEDEB34pA&?&Ӭ@K7N׸_4" @F%7=0130JTHCDCDDEIE13zpAFl%3\ϳ@JGF<,!>HYht!fd'"#)'(%# B\n e#eqHE #DbLH |xO3p ?x%ʈeeRS1*!(1Egeootu \Z.#L2b_ ҁB@t{w~QE%(AEqkTI<-10/3*T>a\ w#a_ihwe`H33-078:=w{|{ojTIA6887;2 L8ik xT<ɻ78"$=8{qaghgka02VFml xV@¶LL68EArqcecbf[-/EA xT1ƊMF*Eeu`ddcf\-0D@ x U2͏OH)Cbu`dccf\-0E@י} xyǐ]G-#LUu`ddcf\-0FBܚ} x ӖW8ERu`dcci_025-ۙ} x ~ĸ[U32"'QSu`de\KB -$ݙ} x ֡fU6ݙ} x ˴w(NN53RXxt`ZO@I?ۚ} x ᰘ,A>4>|yh\M6 ՚} x ټScQLB=DBVgsxw\G9 &'a\ڿԜ| x 刘Ց16ZukG)RWf[<ۜ} x {ݶ}eW_dekeSZppyyzyihYVE>926;EPgKgP x |㰊\ 8:bcdb#IjGO| x |ֹYY@EXXZZknmml"mmloyu[ZIH;6EKRZylA x | ъ#ƣ x  |$ȖLH1+,.!".,+3LIGHJN x | y҄΋ x |u x{yxxÊHDECCxt[3_rVYq {z{x[AKNZ tD^ WE}m* 9MMA WX_muu}`@D3J l+O N6z(b3MzvI~Z{xv{a=X|gNsx~ YVK@z)zjC.hPI}xxya0XU(e ;6?5~)n2>4{N;@k}eUdmud_b`mn} qoopf\yjtGDQDoY3j E==/v O(o)HDZeRBXmijKDbe~ocjhy MBB@<7;?>@9 ])` gLCGDRZY\TEGHHYW nSrGADFG=v}=GEE@A EFFEG@fzk@GFHRS}~}~| |EFEFB?@?AFF@HU7@ >>@6c t/MFEFEGIO]EIF GFIJKDexAWFEFF@R~>Kxv}_DIH Cm{v}`@HAR }=KFEGAR}=Jwxwv}_DIHI JEm{v}`@G@R ~&*)%wG-@?^m:N~sBCgV} CCFEGA[`IltqfKR[YJO4RQs̀~8KDW{zuIHUXMCvv_u HGRNFEFC7US4c{v~j;Ig_ FX|65SusJI>hxzUAfwy4B4K@&LS`==UjqaX;B8M@p1Q{pa`??^eI9mb@VfmJCIAu FFEFA>E?e:@suzR6pf-<@B7MC |;:V.:@@97?5wiAG7R JCD8x FEFCZeR>gnkFJ|ebUHg^;B?A:G 4{ 4F;Lsb=B??A:^s]NOERsnnp KAVXhptw~ EEG=~`2d|4AFJD-YgYVK<@??@>&(\ .C@=58@?@@?@:0MiUAC=><@ K>rQ6PYo FFG?wiLo8|oCKLOv{H;RU`nU:@?@?AAELv3B?@AA?@?A>LXVYTFIFHx{K>m~UARWe}yz BBF>}n5BEIc_74>@?1ok6A?@pTAECA> NOH?s4k@KRRZXB@@?A8e`8A?@?@=Ac2E?@?@?C>[rDIFFGEyK?iyRBGFG OBF;o d:HEX:>?@?@>;=@??@@?@?:#b.D??@?@;PdTCGIEFC:zCBFFGGFEED NBH?m eAKDW|<@?@ ?@@?@@?C*`/C?@?@ab@FAB?@?@?@?@?@C*Z;C?@?@?@>CEOaV@@?@ ?@?::B)N.A@?@?@>CDOeW;AFFIGtO=E=e>EFEIIHA`}wx FDxjKRKZ ZGhrs}dAFAA?@ ?A;EH;SEU6C?@?@?@AADB?@@AJJOLgwW=_kKNEFHIHAo FCf1?=PQ5nxyb>A48@??@?A:F7*:T3C?@?@?=>@?BBF@u_:`i;CFE@@IKB5uFESP{|j@JXWV WJERPmrP_|o=@?A;FT'k^E=@?@?@?@>Aw}NI/!8JLTNFHEIkkJAq{xcvEFB7~~>E79@ A7j}Zo;@ ?A;FG7)?@?@?@=BXS(QC@A@A=EK=oLkFEGDZb``_aX@MskGFGD^eefjraFO^W>@?A;FxxJ>A?@?@?@>Alq)++=LIGRgdecYXIA}vEFA?@?@?CATFDG@uz}hYO:<89@??@?A:GW G9A??@ ?@?@Y\ ;WGCF@Vz~wB@@9|FEFGCLmeFEFC[^tl^R@?@?@?<>^b 8Ig|}{wwytEFTTHFFEFEFGFEFGGF H:-fj]R<@?@?@AAoE;D@?@?@?@HIWY$>Fc{vvwxwysEF I?fy6?@?@=DebEDKKNIg{wxxwx}wEFmnVRIDFELUODFEFEFMR(Id\`Q<@?@?@>?{@Ѷ9@@?@?@>CYWMMRVD5a}vxwxvokEFA>V@G;ex>GEFEFyhZ^`Q<@?@?@>?z)).@??@?@?<>^^+Fuxw{mGEFEFpuuze[^`Q<@?@?@>?~=JAB?@?@?A\\~-Kuxw{nBGEF FCW8pv>GE IFo~d[^`Q;@@?@?@>?0@??@?@?@\^]`OBf|wxw{nAFEF FCV8pu>GEF IDo~e[^`Q<@@?@?@>?1A?@?@?@?@\^]_OBf|wxw{nAFEFFFJKGEIKKLJFGDJttLA|jZ^^\]U=@?@?@>?:@?@?A\^\f!Juxw{nAFEFAABCBA?>?AA?FyzRF~kZ^]^aW<@?@?@>?:@?@?<>\^\fGuxw{nAFEFmoMAdpmnmnnoxu siZ^^]_V=A??@?@??PF=B@?@?@?CYX]^\fIuxw{nAFEFH3q{zyupiZ^]]`U8=?@?@?:)(3?@?@?@?9Aa_^^\fHuxw{nAFEFTSoy[QUTR[xuyu qiZ^]]^\UR?@@?@??C6C@@?@?@@A?EVU]^]gHuxw{nAFEFB>T:CA B=M{yu qiZ^]^b[:?@A4ttFHQNLQ^\[n~$Iuxw{nAFEFEF<9CFEFC@AA@9Ayuyrbgf igGEFEEFA=>@1M6@>?:Redif^`fd/Guxw{nAFEFFEW]JDFDO\YXYZ]yv&M[@6987&%GDE=u~LAEDCCDALYI3AZR8786NZ2Tvxw{nAFEFFCySAH@`||{wvNN $LCEF<9:9CFE JKFDHKFM'R;7Of{wxw{nAFEFFDepODH@^uhn{z|{YX3*+*+'D]WXZYX JGUZMGHM3$PADTh{wxw{nAFEFEFA@AAE?gw2QH7Y:EEHMJDFLMGqywxxw{nAFEFFEFELPJ?`o{a?FBDFEC D=~Q4wf?GFFEF@l{wx w{nAFEF FEG>v^@GFFEF@{U=tc?GEFEF@l{wx w{nAFEFFEGHGEFEF EIAugFE<;CGC?BFEF EFDYr\BFEFEHBe{v {oFJIIKFs|}@ ?E?fw{g=:;7Eb]^\[$\Vw|6@=@|H5mvt{||{<<{I7AB>;>A B:pX:@6Ox~ vv}ldkjv|umLOPC?A@A?ERP%]^]]^[jvswlNRQRjlVKt}p\`a`_`^^``^^]]^]^ ]\acb_jty|cƒ zyqVZVV[S9<;?@>=>@?@>;<;<^a`][\a`[Z`[i5?>>;CD6s~||}}N0dzJqpz}z|i\__^`X=A@>FJHGHJF?@?@?@AA@@SUTUW^]^Zt~{gIONNLPooPIiropoq||wwljgax }^Z[YX]_^]^]]_W=@? @;WcdhdcX9>=?@?@?==??<;<9Da]^^]^ZYYX\a`a`ZZ`a\Z[Z[ZT_xyG/^`SLW_]^]_X=@??@?@G`]^]]^]^^]]^]`ejxy`R]^\f4f\^]`W;??@??@????@;T`\[]^]^]^]^]_\?>@A=Q`]^]_YDOuv^]^_^]^ ]^\`d[^]^]^_^]^ ]]_A:>9P`]^]_YDPz{^]^]^ ]^]^ef_]^]^]^]^ ]]^YWXW[^]^]_YDOxy^]^][Z]^]^]_`_`^]^]_YDOxy^]^]^]^]^]_ZFQwx^]^ ]`W9H~]^]^ ]^[c|t\``_]^]^]^ ]_WoFLwwRQW_]^]^]^ ]_Yj*/ce9:6Jb]^]^[Z]^]^]^ZftFJuwvwvy|zGHER`]^^]^\dgffgh_]^]^]^Zg|++99Y`inlne]^\b`a_]^]]^][[\\_YbX\[\^]^]^Zi3OEP$AE]^ccaa]Wpzxw|iadb]^]^]^Zg 4D=F!?C^]^]\][a{~PKIP|z}X]\]^]^ ]^^YcRLnw^]^]^_`]bvyRO#OTzw}[a`^]^]^]^[dSNoy^]^ZkzoFImysrsrszkJBj|a\^]^]^^aS=D=YwpuiDAo|xzy^]]^^Xl{oCFp}yzyzx{kD< i~`Z\\]^]^]^^[_V?G@^x~qHDo|vvw^']^\f}W4<:EC^`iiRR);Td}} j[_^^]^]^]`vuuio{wyxww^7]]^]WlXy('&!FGxNJ#?YzhUZX[^]^]^\`suqstrvxwxwx}|^-]^\gxK7HfajjOMGELHix|_$>|r[_^]^]^]^hg&ys98ROvyxxwwxrQS^]]^\VrCPo',qEF%"'"IQo}R}xxSZY]^]^]^]ZX%vsJINDntsuxxwKM^]^]htK0;4c ٺr"חL\Za}t= ͅ*U$0?AF~U[Z]^]^][XTApw`Z\[^W7DFEGNNysc% ̃}*UkihYRLNJXjlqLPsy~d_a`c^GIEFEFHHxycX~a& ̃}*U wO#0>x'I~e?GEFEFIHwybW~`& ̃}*U vN"5Dy'I}f?GEFEFIHwyJ6x`& ̃}*U Q"W2uxF5ze?GEFFGHHz~G0w`& ̃}*U R!Gs|?,~f?GFD@CNLUSD5w`& ̃}*U Q!;eoQJ *{~f?HDNua>BA6v`& ̃}*U Q!zZw@6nue?F:OsjI2w`& ̃}*U Q!ԲQW/=;0of?M5u`& ̃}*U Q!䋉##D6;~}]>GQ($C%-v`& ̃}*U Q!CTztlP\pmonqtZW9&>PD8Qo@Ća% ̃}*U Q!|rca1& ws?9?==A9Y{@\͘b% ̃}*U Q!|OrZ '}LGholml"mmlpyJIZ`,>K\sǚrvVY_-U) ̃}*U Q!| FB><9>@hHƧ i ̃}*U Q!3|?\a^4+,.!".,*6c_^_xa` ̃}*U Q! | y҄<19:G ̃}*U Q!|ut8mk@!i˨i!??VV{{zzWW$$CC""jjϧjj""CC$$WWz{{{VV??!i˨i!ic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP ߂#ł;0,߂(!៽Jp YH*^c?0ס؃+8%'yle% oAfT676][߁%);&_\R6Ø@x7wj~@4D &1,Y-:%bI8>/òPrB <:ʜOUIǩ2KnxPEF ^ ֧tPផ.aY7"=ba]瀵Zv*Z69]Vvh gUu)su{?@qg)bo|}gѮ]%5M(ʎWd3a)|$>K뇓Jok Mr,>Nez tuۻJ0QO⬍Hs/)&#;1? 1'\U[&B_w7*VqYMCkM~D)?/L;w?}#Pȃpo֘#}` oέXAc(ɯ5aR5ۅ9A.3i]̮N2Gﺢ5yDNLÛ|)JP+S" {C=Ҧ5tejYV(PSyghi޺`2^JmlCO0J~q6J]6a ꮼ>I$lefrleDoOȈJ"F[ꐢ_?ϟH S6jf,ոmc ԗo"̧p"a֒R/Qg 3E!2Zh>k:Y̭d3Uf щ}O~(Jf0VA 9IJ݃:1MXb݂R=G$ Mr1;+$뾘ٱ}!1ZxްqBfU5z9ʞe/Fԅ7&[/񍥮 |dAh]lD&6 [fNf^GL7K3(?~<6ڄĦFx@%͆4B1g@E0i<;l;^=dviD0dUzoR9ޠpT68~jޫ2vwE2.(Ksbv :J yмSWu_tk@M~UaZYG[aXzlQ&I+B}΀\;Bs&moвZq bٽ!Zxu+hz{c0J[D|Mf5{iCb {s*1ಏOML2 Y#kR^߰lH#4K(!SZ0Ybhǣ24Df5=DlEl0Y}l9_e@9I3ט[7|ވDQ{tQEj+1>f6wndܛDK?YK͒Zq$"^2*)s0kתq"Y5iJ8p0t\ձjJ ~q9Y9O_X<|T"M6:M _qvp|.YOJ# ,ۖzc!etoty{ HrLң1$u\܍R}o#u?ܘdPFsB-:X- q8idszt+ .OΊX?Ƙ?ܦ~~3}|ݛiPIbf1'? #Ҹ#wzTLM >1a0̞ O/ŵè9u_?> A!<$o>W̫?|x$F~KI|dGÈQ%DsLYlE0-$mF pwn % B%Sp6iǀ]dx7f'K~ m)ecJUDG+o;Rm&*$6',;P 5b!D6k۔blpbW@5@^<շ`f%aӊ Zwf|Ӭvw !&+X@ݵydxw2mA'[g-kD -.ZmitWյXvt$f [;]غC V E:)AүB -8_;gBɦd&MO@3zLc̱sW%6"az/ `.<'%Ag(ApH0Iy#8- d&)E94Q:cobkH9vIǑ9@LY[bB( ^E':G,L85bJl"JU8o xmUk_3 MqZiAɸj;䜢;N38py9oy*D;%( 2G Hյj V8S!g+5^^SLdj%ܽ.kuۙu2AL F+w=TvZ*[tcǐ9}{S?ؿ0t|8 @iE1tWx* 'PrV;r/x#KrDzhs`p\)=!Q!˸tˠG3 cD^6*/#+>-vՂzI#)+Ya6!*@H++z v>1&B\ݖ9QFW&M*ЯIv;6W 9'V!;>-n#pe  eXHASӥ|?üLF׶!=3XyeC,}= m35F^57?^mZK w X3EZjkQAbFQfuHC@Ǩ:`ʧhA7x+k @|.ǿ蒝-*Z|y zBlDW*b\}T7A28\G}za\؅x|n@:A VK϶Ǐ[Kk2:N~~XpȖrIZ샓fb.DX '#py;"&ڋqeP"/&%ꗶ'N J#s30N-ube!b vjv؅j! bVJ6bi/l`A22EZ jbb~ 8LgLUӭz(N9{ûQ/l!?H^F_`5^^^D\+9۲'lSfL "P|BE5e(-|6ç]l̓j@qZzO-bEeOX.9;{]6ߗx)U4_ %oyq9VΞ¹@J0,̤+W)j8Ҥ݃iM^,uDiG]ڐ$Rzt_s:ѭ`_* h2xISjŒA&8[|i5) eAEnFDthq78g9>#pP4r{>FSȵ?Ps3[΄V8iO`zꅞT,(*W !pPZfP^'C2d6`Ȱ>nv,EŅb=7T޺$hi[5>sN ]W3jZ -#m+'ز 9hv}sz,vznNhmWBIJg&agTz1Quπ/ޕu[o=^?fvIe C\A$?:4f"h(V.Y dh)j1}1eHs&pzO0@ޤZFiT.Jlc nȪ!OFwi:&݌Mo6vԹu= 0!z)PƥPM2L SLJ7&QWX紘EG$ ٜrò?ET1c@#Vɑl@ƄVIm`G?g"~+׉gv'@s@焙Wlj5 MobGm|ņnщ%:Kb,c2\! xs^ym06A5[ˀU=>z 2h]p&ۮrE.lzWW93'Ld!N5p4S~J0]{PE׺s8k2iaԊ .8{N[t6(1d>ܮ޸C0WMfKuR.v?Ca/׾S_֚OgZrMk>ЩۚӶ.}q%Bx0xN&j$F9GlxCP@"X R=y%P8YAoAg0vcY]?t)9:g D"ZwшKEC;bݻ$s;qSpX]k/d@41f{. ޭa2OOB+]&̶E&d馟q4zJ6j TX@ CXtP:+a= eayCCLͨGfٛ2n'XoNzѡͰ\yaaUw 95`\E0a9xEAJ!ow=,'ƙiPwVʩ^hTd:2nq՚C>,V'!ߊ5=CHCZTo EM-E7ɐL۷*@{>Dl\K אm[Y (,xxKJ'<'FdךnT5˖:*u*Rs otCWU;ݐ]6iصhf\lO2o+R ϋDAS]7 k;9ϊ\糙aqꋖxwt@_"{OofKV$b?t{qaeNV*dExNNmƪ1R0xW1}g*_ c)KJ"F%[(YBV5-Op=`L$P9"]sn蟚%y<>P 5 Ue[bօQpjz s;IyHu*pk;8u^sHZ4f͍NCuԮe&D>B0p{%h?w95Gl  54HOe%Oukc=Ps#ф3R;7ԿhL{ϭx<}3n\R޴ !*ӶRJfMqs\Z6 9}|xXv%y;*!{Γ?^ 3AOq#"JL8cXP pglc(n[ !La*IDl]%6v-`+ogձD/3. YMݚ@msUNxm+wDg Ǹ!Rlm%Lr H~KR:uX/} g;/dϰBFCOwF)6N1=m'8B,/7As$+=WSJ~[gVUdpKPcc!UYݎ\ &yiH)3`5g PΕ$~#]w?JI5 QWJ)nVi?IlឺB%ڈہ#[DD˺uHegEp+aXyJ1Pc) 3ϡBaI{ Ie4zbXhċA1~3 Flk9MKDɐ9<*Pl moXpޭ87Hʁld8 `~t{25bw\םeyntj Oq5T>Z d|%v9 /q1NY8.j욷le@KrǴA8NmnCw ;>(?%E,:XVڎ؃j S$HA4&ri+y)xI)LdKM& ȟw\pA,HG o+@emz|*Sw,I #}@Ni _KPEk{Y3XI;%m5%wZeCO&tB-|| XSˏ"-1nRwͭs%hܾ#eڀ~%eC*"RG'YeM}] JS' * )5Gz;Kbke,Vli}h=`lFwz^+9a\X1FS"ry(Gf nlJc8s p < V|M=Ch{pSʩ0%#rƧr=ājαv9rWGi|8qv+a=3m0=ѭ_VJ\BSsl00]\6HO:&MVK ǫ!Q=ՎÒiV'*sHu( ŸErɭLL_402ks :c[^)4{[{g(5A@}MbQx ;ˣ2M%X7nvxI8x6tvU'DN2U+nŗ]<*Տe.e  @XɮmN~3vi2IVa)vv řz)#< ;tVYWlpZ<+pR4F魦Âq{* 33RVYOn*|Q_^k)N@jk%ovK owuCKܕ i8M|2t dS2LQ *݊S-Ju5&t|gEꃏ݌rkuV4!5գC1wB¬à|M{R*|{`YQsTL=J)Ӣ߹fڷX` ڶ*#J&wÑ/^|(RdnӵD9Vd )Fo sో-\yR ;,^GfIBQo2`+C,R[KЂo=HIX|x01l'@Z,Ւ e1: o2u4Rs0"8&&Fs׈x//pEeOTxd G,&] 8Kr(s[ao}SFE? W %T޷kzDis[90yq;V"z.lOrE9 ԚP>uz<8e'AF/{d/^|YTNfʔ܆͑k8*L-~_[n`-,yk$y`{5 Bgee3JRbN`9nLz¬uI'џ)hPrnU!`ؚZ˂}l0mUЎٮ5@1 :>MCX 0qk`@iCSb dm;jF.u{l3[/̹pp3>EB踐Q:l76 +9'J9O2w㪖ifc]*E6Ơ[ <.}}n`ӈb# $C]_d暳n-ߍN7P2=}\(QkPv6ih' 3N!"G=3tJȮ*ֲ֯V5G޹\9U0"%cKɅ̡cٜ$<{SE0S?-)+9W@m@Ln {”\s-t]*>fFM39~PY ȋwdql3oiҖ~\ezǴn)%~&eBܴ._D} O:x4tQPq:ITY0O|R«hm]}L.& Us`yQ\[Z Zd%"'H$c7=miXk%6|7`0g*pl皬aB]Lo"ʴrd''ޭi+d_rʴP')7 dF_~1kZ4_{{Ls6EC]:pkǨz 6xEeI[[Zhi$T!uk;D7qSVjnOQhn&0õoI$B3^I4hSq\NXM/`bs0g}g|ӌ p)Z q_7yRC͡TmZF<6(H,ICz 'k~l(m=l@nĂ7؁ǍXe) jؘ >c-sb/e85łF9׳}\Vӓ~+BPaJm[% /)CôfDahETmXh:;ἃz!"ކHi;OKsllRz~R^,X=aY9yw _iI3XH}q-(TiY$.@p1 OҬ>4JOcǩ^!Z|Q>1, ># ~ܵ 'pCXh3p xZ4ݣnгSf5!4_w}Ҍ"͚9C E(`t/eqT).n_^^j FyT3\=ݾ.|nD +l@n7ꇊy?ۉЦa#%t^DufJF_5pM5as/d$/`B)"U߳:eި n7e\ Ν9m}L'.X냍,tYhW%yƳIǛRg ^):.F%8|ԟk4o :l~x/ۦf&|k 6ӎϏ'Hp! jx9a|_;&I3$H{FS0ɅÄ—՛VI(1!н5+-N#| 6` Y$p;1O4 )]%{d-<]b@efzcv8qTcBWQ:{Oz'͏IxǬ,_áڝX8f`eOĬA"C|SLlSKQWD6T;mH/q8&*m$7on 3cfݔI _ v7}pG"2PM0S/\{%o MKh[P6xr G$XA#;Vڞ@=|:(ppO>$ՙCTf(HwAnzj'R>Rt01﯎Lօ[57bKgaQI%|Bqhw-l`oOm&t7/:IU9ڞDZH4[Ǜ(m(+w=@K 2%g`*Xr\:*g8-m7Yd=KI譸m^/i؎Ɠ UcJn =S(13zE+L盢Q )A\آ:Iڀ+FtZ'\c7nNGpvC5>@vr\V;ct~(;N5 pY:u A߾ b,W0A(ւw^y6u'd|?.=x}^%qU$I*` )K s"a$JreK IMnI U `u$n2ƴn7U)ĬD9LHc: kwAn<|X\-a}*v3\ڃ٬iؗoQB0ťמAQ)߇rhD u@Fˮ+mM']BXsLm;twh(uK5zv^v05~;gp.n.Q nmы U`TL=a˾$zcKMР]AeO!%(I-z#)}㊶}zlfUZ8JdWA3D/TY:was#C29jYlB䈶#4H} *68a3w/dzt08! [UoHL%霯tn!ϼ3Q{ _˛L'PN[W/X?@gľa q 5Gy`|7߯heD3-mf % sT`.x'.*@+5ώvez f}hEO E#c9!\S32ft( | %v-_(D&ߡKߌVY6rUYʦ?y.,84ĴWB!} 1nyA.ž:V&TG ᝪCQ™)$#jMɪlX?̍M=LqZf*Ήhy­O٥0'5r+t`98Gv. c3伱1x  0ppѢF?7rMB?@`Vi>ocȂ H8Md:aNv 1_.-L/٘"x L8%HӇc\8^<J*C87B/dU[ Pz٫QVE[=k5 # 2P`*Iu3 Ѹ90;™Vϑ9ŗy }Bv|WEףFfp!1#I/r>ieX6GjeR#^`~T3F2;ݥDfu}_F n+%aH./&?팲xؤG [ x+a8 | %_ɢ_c,gRbLBy8Lw|^ߟCxm[ACMKICMN}ulFNbͨ WS:>ɜd?Jho^+z%,ǥO W|W3%yGc6J.*eaDvVzgzkyv*<3}-;}/Q k2V' !#6Jux]#c"xx`^ŠZwrැhFB0RB+̅WSmXМ"Q=|R4r0p3?Ճɇu0Y%ɸzC\*F4gOr0b^M`V/JLƩPC`rORH?BY ~w6g'#Tdñ%=3bzANUec__(*QmrvR2 .yKV3嬈_/UsͧfD,d6'W"enp k Kpgz<ߑꞆEG &q۟3CS%go/NIx%B84/l\bxO C"P+=M['ЛVSo|tI`|`:UPM)}-! ϩԕ \)ɨk4L&rJ׮ush]SUJ\༱e4wWN^R hg ~kH7G\BE>OTtD')r(8Kͳʯ zB[S&<5՘rsܕt/zJ{^NTb#W#/ĢW<~ѶGjqH4f]5$mYU°wd5![hdKr1oqqѱlQ$h/K {q"e H(t{'zZTTt -@ U`L96t A]\uR5'o*v,r> a>8e?D LF`qK-x<_yS|Cr!p}Z G]1ݡzKSxd qed~NiWT>ΡHfrm9 fS7O&wy{¾ֳ&lĴf205=C% qZ"ϑ9]u'ڌζUn@2/PUk]C;?7LQ\uvІ\HzG*tORXOH4C븘yuGj &i<XWQ4\.UQ>V G;][t?8\NkhghV$')>~}rRnoAh.&q๦G*,œ 3hQ|!j=lc:xV,%Qo[~Cfu3ؚ4+s{^riB`MGΎ+<~5|콜s='ݷX"AqUIZC1TߨT_4'eѹR8- v/id b&dTS:KX8-z92ͭ Mi PʦGDʾK%( 2Vp,J0i*&LZo:wPlL{NгZ.dy w8vY"P wU['JQ i vqjYsWYX*+0 頴-Wzo_V8q/3P5G#Sc?L_m(/:xҌDUP쎓{I rZg^U/5e\7%t퓿&?A͟w3ʊZ|ݴ`^$eG G9AV<ɾaO]1 l'(dM)&7تO^Dd쒫FC+8w%;5:2Z 6HU==/7)0 _u=\4ʟ+ >g(Аgø7S9t2cmYj@&J0fbI KyAC^ 3>dqH.^!,FY""h Z Eɫk95XŹxˀW19: OY+emp n_M\"}.Q Fx7{GwDqNS/^רIMAJ-Gxɳbɏ&h[A">I϶AB KK@ߐ;H&o6htT4)(j®c{;nfV!-]2{ H!B=fNiw`7S#Ŋe 7%AIuH#d|fYHN ?5 Ec7@Iw%[4@+O8gW9~,?j=[!rPw 5ʷԊO'y/ԛ_vJDNQA q ^J,MU Etj˒_9BßkzcM^-|?,F>ֲ,(o;c~:N9}9&&_k<!W8w;5 [7hv;ypXUTgyWնw:CaTe8)Mc47X@˜oJB'izSA~)CL_pw`YVuZ@,<%gm7N\=g9TOVw  b0@۶1'I+(FӤNZa(J} ˱Q_RS?k,Bl č:M2 U5MZ'߁z:U,'M'.Qg-Q:Y~k6̘3q5?H&7$hGj쫑G+x*Wзd Ż08:}` K+:&頬 ݋ QI3jlEy1t]2xY9AG`$k %獙×<h В"ܶ$@ic7.ٱx SkdLfAit["sZǨͳ;uv_PEUz;; +]OO7 *#Z+QsQOm<+G9#çI(\ͶV gPȝ@H>Α(.M;qEщDR[)^`q(/ZN< ⓾2Y((nA"7%JA% x8qr5%]rVX G^ֳ(>?EۆGc.%=0HqxPr9Ht&Blu.kr@"(O&tc0? ?Oи;DidY->U7D%2BT;rF|\Riґ:j;1w\p5| SZāc, Q-1Q2f[yY+*4B ̄ BA)òX~D3INȬĨ]vPD9ik(9GpA6u?pzij`Rys|zi؇L栯lITTEWmgRR*.S[>BqkeGZOHAT=]B[RTh !z0OPT:%d¼^UŀkS=#Pw/;+jvwO{ meYrQ[y) SwQ~u܅,g*iK1!]F( oEIO'n>yq&+WrŽh@+AəEoM#.vLv V%7#s0a$8QǔQ@ؾ"3 x_T>lDg~35>w%-k9XC5X*̍Yp4SՋɂY@U ׳Nض21~\bSQ@n5xm );L=|=46tXO}J`YSC4 )nYڅg~c[A%5緲d3BZQ_J"Lo7lbsab2&k110\e^|PtG t8ק`d PJ!Z#m,ŶI U\mpQ&BRc;%~T48ge y BH0x0Ŀ,0y_`U`UʝNA_@ _NH蹺ؖX_ݵ?suVJoJ"Uvu7NWk Aҡ'OG^G2l!(8 w7 00+_V'1(oȤˆN!PZ2zN3_L 9fch{x$oAZz,[t罝ؠ'Sn%~ۅ фW%NϺoxXfMd I<Ű1)۞.Vu_WSxx!yɼ'LVT/&!\~Aw9?BKU X&!Iv tY}#+lUkf,ob?M ~3Wm;&ۺryT5Ut@ 0dzqZd/@Aܺ "S0{)&mrT0HN;w?zҏ|H[lvYCLZ7!ڜHdi + Rߝ%~t~RTWֲe`ӊSC; @L@[dK' FzG "p G8h_d{0|<~Ml M_t׫ěXKqM5 7?Q y*GoU~ 6v/DWgq"vo}w{WD)_({O">!E`_۴y D2i[Ը4 OދE6uq%R`}uErykhN'ק]\,حQ܃ҽPd!uu`H` #\skקlO#kcT;_3ߺLP5?qITĀ&($zc*p&ɘ]{A~?on߷/Y`X ) dAg>ݴH>U5rW,]]u,`rz*}#ki;^ j=Iipgi=Z8hr )[Y:?\ꈖxU+K?sjH\DTes,`0ȈtBDl 薡 ,@6r{Һf* K^HܑA<ÞD<4?s=٢m𤛋7U HUL!,[]s'?$bGbZ(0Wb[؟}(DL=MF.8@:  vx@,M%v>]wyʇ8O &E- O1x9?e , Y1;ȊKW\1Z)dlkS`BN;.}w w3h[a䫪\~,˝mRx<3ढb-ERM?d }KAewXZ3] or='*,;" a+kpZ"i7*YZ5ze25ɂ'*GVPAtpo2X{z(i(yfgDdb674::%xVz F[N)VOZW?JQZkL6L҉S w|>2[k(W rTG!T y"a+.sƨŃ]%}oJV)(Xk!U)pPqu, &ݔ!k/Ԑ>֢%F*R;]ugg&*M0B]((sWϫg(dB/9R#ys|v~Ib6.dPy3mඐ[fQɷ6M6k2C<9e3Le%6<̣UdCzڪԀL7Ɇ%LuKs~/YhğAr3Zov5x\7mc':epB"UKMȧڧw &|v?WzbNxZXu2<+ Ɉ.-an<&ak}WuYؘ Fz$\)jl;2 (>ʁQvUiBZ:dyycYL ^g/_)\:8L~( MλMcI+GV3Z\+w@D9 LdvcAPXFF `^>d h~cSbc\;q JoID'G ~I3s3 kY/:^2@OxD`*.೻gC軂>7ϺW3zMs84(Qs>1 ^P {/BsXe$ekTLޓ !Z'Y93j 2G7޽{;@fD;y+E;*4|)7P}ks U⌈0W)BF+ ͖l)! L<%5j}#?  '}╻U&hudEX^k",KuW F ]W0 l3*: iE"*O"!flZJƹT| :ar*e}+eGۇN :@N`-p%-h'8\AgyVx6xн++BQ2um}qt!WkQ\FoݻQx,Aq qݽ""ՠ1~8Ӂw ̵;I (۔<Xd3#(_1/!"b. ӥ qs$9l%@<ՎUN~&B l㤿n(ʣ+n֎(c|[eJɎE Tt}dº쯼ahےNIb۸ҵB(==R()uIccnL#Wo79Bysp(9'a!@,cZZ(RFLfXFAIw:xpD=@}^X,<cl_7l~ `lc:t/&Y1gDB}^A?`s4_uO2t_{* ٖ!y\} M菱d[F!m .y^fDlRV0)}-s L QA{ޙ4*>>N@ +w"r*xu_LVi!#(|$ibͼ\Z4H ›+6wosD%L[ie40 !fX/Npsǐԉ_z[oھLz@:*BF"0/h9oKdQFeT'X&̻vbC#$lt^n1SG=6rW>8 `mgAMpY;#G2nvN^}Nb=]" ?'ѨJ+Kx@W#Fe& U.P<\ֽ6=P1le5/J6A@[.]1F9 0L0 [q A#Ba](Ls? PvKouܩ+ )SP'] n!C P6"Y 0 1i#7}׻Fxar}s}c ^j[P{=)Ms_ݜ:n"NEc5}R#C= C]`vc)򀏋oobPFYUSk{㉦`btUT)-^}0}&Cʧ F'@7fi {I 0I&9-L㥙PWzs r`O}\]9h_&|L9,vژ%Z`4.噚܉jSO8Sr1&*9 %{Z$:^Q6 UGTa~4e̢,n.>-/{uHreLSV -ΧVMus4Jk۵Fn %83>jty[.13 c3#^2D'`:n *N|MvРglXdDL[kD-踄ο3)Vأ9_,Pc/OJcODJ48W1)%]~dޓ wPeW}W,2V7DolVD#靼yipܵOLP$cǥҿYiӅ:wSR_ ldG5Ң8#(QNMb,YU~rayI VXH%!% ;c^:ev\/ϫJUt3QJ'+%A*`"j%n`f o=g@ Txp^9!V@pNV˧"E7v\+ƺhoQ;_cmC;mcSVۏ#Q!JE.r9 XK"ݕ@-%5^Q,IH؋̄&(puCB&RW&y Ҡ{5@P)5Yvk6)=2qz-*|s%|NCy BenJWb\Eސ^Szќ*E0) ї4")#=CV8Ҧߠ{z^EMWS>NL;77l3TFŪq29t +9. 6Sh#Vx@ Fb|j$rkND*K⹡$ݬnH. IUUUUU|`XP̦`8нm֩y#z:Ku(F_R-Ku Xz۽m& WV=tEζGwP]_@Q=UJi)_ti]l7 qȈ ; `NgSę2K5L>=.K JI$I$I$I% EɘOۓEI)t^]Sd)jN6m椮 ^iS~76 -fI WLV|*s!9͆"Ma%R@b&tU 4OJ9P.=+!s)q=7k,χj?J| o>]baPQw"Zp z06I$I$I#B]g]$yn&l@mqt$/i:\*|s Ů^R10k}7YDw8pZ;Q2ކ֧>JIoCk8fǸ6) +%>;/R0=c\9m^PĽ[6jx)j/-2`n@C"ٛOVChd"= Ғ9n\"/`kU̞|%T2en& ![cL Q\<myj蒘ӣt̽ni2k7 >%39?N3EuvDW]dU`+O# umEpHo/ɥ{@.-R5aU pT9jMB,Í:Ax*W[&"SKdP[#M~9a$`H `xŴ'4)\t;ػikv.b-by̲LM{ͷԋMc+a}( (x\yIXQME Ŕ:v+eF[O`}y(l@l0͟m0T4ˑ% 3{jJ[ K2:ik%iO;"M(Јn#/ڿ I˽3[H䗒!;)JM'"UX:1ӳ|++X$d})2>X2'X)vϵDbRswB,f^C+9Ar`\7 #~#qDo~}K&L9F`NJ[G&0 lFf[9U*1rx!%ˮv[L!۷ZT$3ԙ#7X}w@em- ܐ+jq'cH 䴱η~8jr™\]ï%h(jIq KBf]}4'< =>8P UGU'@ӂbEZ}UۤzZ2BeYA_hpЛt@xw9Òpv-r0 hҩRS_:1E]'{E>\2e"UpU3Ƭ(p"[N}NL t AKҐrLrhw<*F)/h"k0U~:anYF@a]jx1K ѻ2 &G^®Oo@ _Pe@ҫeW )\ w6S]ln z7 b?q{xO9Áa_NLc\z` yN'u6R8THK_SI: uիTκ >|X>0흥;R"Ph&z097ʨ^E)t`T҆lg;ΧJ=.%L60Uͧ8n,MK ja/;^d f2zyZ7l*ozxj;n á%-~@HZ!wW\,Hzp6Y1S67G#mN& Cg\~/1*]r%_`֫&׉%?+3sAQ\.XQgy7RvD p;5bv4+cjz ZW*Q LU! RNGM!zÐQ}E4`A8ETjOڡ_-`k#l:fUE\ 8Z*'@M\#0o150@uU@,e=Ӛ(b{pXJvWYxzGIA3dm/˯Fzp{AO#bjGfI\ +; gzoQ;`\D杨̕ӳ#ĩ4#ta=# ݯ}ُs{Γ oe(3} r D{qG;_ÌHf,?b ÙV_7\{i8gˤKcdb-6nA|>Av푐}Om۲ύyőr_hSݰ*ҁla>?2Ne owbFtOQx{0Hk H.2> GCKީOXЂ5/&` |wG_Gs2T I](:Ptz |Ku-UDg~ȯ5o)wR"VcJTe~S[`g:U'Mlˡ8 ,AgXDį@fS@y2D{@Ԉ t27 H:T( d'(m]{Js59?{otf4Oxn "CB]N/,⺛0I&R &a]SV~pb2_+Ѯ-!hT$ K9c"oj̥mY˚.O}Xt@NAx{Z&0FYcG@%ꬫ>W;1@}}?\?d4#Z 7`?usk7CTƞ JAc0Ť=Q73ɃޘQ07KQfֱC7,jR ~ Bk %o>_Rtt?6piɞw FUY]~F%gNѪ7Q?ؒkI@B3Gh5]ܖҒ!IITN$ UیCx]T9DkCiC$2@K!Ȓvh+3긷ɹ%eU(XǬSUN0Q<Seb8|JUԅQJ5MT" ΌΊҞQΒ'vy$ksUȪw4;d7VR+W:]/sƛ^Rh9U/6B1&koD{q pKͯjox'X@ac~xfRm~7p @v!{gY[wIDH9!Uc*,w`.a)ӫal|ѽO<*jl<9}"_, @jP;AJUNv/MLvꈏ+tw9%x Z }FX@F?depaPk[e M"YYDU^77\F,i{d{&9.KVwÓ &)?mb9x!79uh.%!C>;ͬek:8臄ÓPfȍ@6F+ӉPtd{Q2~+!e{#gL Fʓ-?4s!:+PcWǷWc\U"n?1bDs coT}c^ ^8~J~sê"R4{,(V,76Au8cgPW7$@w[+ Y|3wɇFUYˁӏ,5psQ*dj|u,䲆odKl N7Ib`e>ɹo8Y'#,1%+F.$ @sAOXP{,_8M{R.R&\UYͺrh|{2[ز)O{ B3cYvs}ya^V/1_8LS3%*ߎYwkogD;H `hcd?(KflwQ kv F+a'Yp *z7V5UvӽG#ii9ET>ǩ4SbKL &29q7x{@( V35_()ͭ ɾpc^j<axrݘ S^7t/s/sWR$ 5[neb%UU_Z?#^8WvpK`|<5BqɈf 檅XXv~Ic nZ#7quUt$z$}MZ.ɫy"zb FAr|)qjܡ)ݢƓofLdv_"封v{ƾ]0x6멲u=/QL[+WADqzr) PqZs(|6|"YTUm|Rj'fȝE-m.2Ms52X/`ʌhdև/oI[#T21Cy'~UdPꘊj)^p.:nKay ;|SDJD7Okm㢽\$xrG@z뎭 ]C|SbRj` &ȴ&%]vyM Q%_9b 05 N"ZçI@J<چC [SJR>|R&pZe]cER!6j`Kc*r_gcY_d!0.' V4%GLx"3cL' ]5j|&(|B_'K<3 چ\R,)6lh+p]$l6p6a fpkv8\M?'m^6exmN7e &aQ kT 8Pڱq ,{X QwV./B<B\`<0A2&VڪֈFq@+J 3vP##EFDuJЌ176v 8GZGz:|yU,)(_Y+ f#tQ7,UX8|paXϻU S-,Iޙ& AC'LK_E (}/0i2 O tPӑyWm$i; '?FN2 di}ɒ0PڜF1G'`G_,@׽#頥XB@ԅc%Kr '?Gt卅٩l*΀S/8"o*fV9.ӯW>NOǯ^[)c'eVX~{䈲k fחՠɬv+F-"H|X_Y<2%8@|Ҕ, \ Jvz_JԄ@mSW1>sJ Y?B9YQ<`^b{g0v aM|.Y 6MΜ`L=$[WIur*<g z9/W@,Pjf. /qrگu:\ |/A%Da.9,=r J*Eh\1t&?R@KVˤ[7߭^㽗 U:*}M*2BN'١{,QFQBC,XrWh~1<kOa 7@rX\C #6,e1^\[-t[m5 (񼏭&Rd~GLJ ,ŤBQQՓx"C%+cͫz'{ͅԧkZ[ƭ5sZ09$xɽkD!8= eb$񽩟ā/' n#ٔD>È-6tՃ% -jwL$= ˘Q ='{^iQJӘIǁƸ 65 6V9$1R:e/VqtIyfMEY]WK^`CaՆKzoแx=e/?oؐ n竸qh$VRق[=Ӯ!Sݲ0m ,71GPPt߽$٧2]ܾqݖ(/=ڞˌ̔E-5HogG84\t[=ҘlB;˿ w #2'}$\_5juiTt 2}%Num qq+HʦIܷ4UeoTӫgˬ)xf_];n7ěc\>t4vvcD)Nr`S5JXu m9!IBG zQg?s.N-¡$ar/FRH2\t`柔:I'@Np© 6_oV-Cq7fE{~N,>5y~Գ{NGӄ#5YQ$!:Y; aOc9@FZ_~ D_;΂B0@?$Px7GlI*]h|D=s,zRtAaF mS(݆E&PvcdKl ejٴ#w!?Al8LXkZm[n4ЈC@Þ.Aܬz(2m_`@@fz~Z=Lo&9PY(9v$We*/1 oΘ+o-L;]nh0avL([t0I\[Y}jfmnRdj >N}g߆zA 8F'eFpZM?I"_-v߹N(A4tHrt@ǟ^]ßşן ?rF6U5֔.ͨN325V#s!;Ne;1Ec]< "0yIio&ru`KXF@$ͽ秽vE | D/rNS?G*&dԌɇ(6R-2.HqЏ2tX}u~rHFg ;.s0KUyÖs $m5P ’BẍjTB2)";=!DV`˺H'`ŢQ;k6VJP*r+VU~HErlX9ǓUoR owytd9PRę1F_Q*$m9vHq<"vw r`BWin\=wFH:J2_Mmg_-B3tokW %-Ab'_cGVZXzOQ>klZO|:Ӏ51oo[fM%6 ~y2}ii n_4} 9۾_yt07G"V,/FIJ,X Sm~N K5 .W=8)TbYP^F\M]Rw7E?ɠUQ: 0%L> xlk³o~&r}֎`?v U:;$Y$~5>Ji|gss+{$;nqircwdoyE =.:>i `=!? c%I]~t%j B0Ǎb{ܒ|a94"~11/oU S(58J{A[$[ad 4e%hGȶ /6z6K *Q3dK[ec=)"2r%MHNl+Xb} +Cx O{Tv$ O^BG0!l1f ]Bh]-yՑ0u_I1t lI44i:o3GD'BĨw_REk䎦!ȤeK rR3GFܒI$I$I$;=ͭh;s(6R\7@W0 ʺ*4ucR/ ݙ2*yܬUI4sc.FQlغ`/vo7 Zl62(W=: B}ƪz"xIg1/d'N0*E8YKFZZ̊DVG,)Ӽ1smmmۏFv91M8+U2|@?$} lw7 kϐKS 8[ =V"&Kc2-{+@AHLvO oՊ)QR&Y}}m&aKsH tHфGqKv( ě931qk\^-`#^59P"G+=(;v]x$N^2wr7hB9? 3@b7 }pU G܎G/M4PK"Q<5VFbkH섍mTru똼5⃗[,(j|yEw ؑ( f|fMdf3ϻ撩&R__ PAI8T`ȽSosBT껄-'f{&ܽb3<~UNGOA'~k櫿D lw~{.ґhƲWDJo*@ a~ D-@*ԅLhY_X \+A-S[ o`}/o~]J-X_3Y &\+x؝\; 1(+\ ȱaDdHa+;yexbi|' eHQRAJo0ie .|$,y;uL=0!fGpo'ywBB /X_6c{J꣧=:inߩ1>J ] (^Qw * ơdl{ꛮ}wpu0hcJޟX4[o|uw{QN8MHޡ_+nxTghR[X(㴧Y>k礔΁}&"D_LSMmU`vNN*&'XާaxߖG] Y\7jTdu >s oiK~A9KOfeY_ua&/!N >ǫIi{/Hh:nLb% h>'I%v7S# }Ź^R.tg+{M!YbOu F$ xMFXQcSx_\e;ee/̏G \#!Z&۬NV,%?殞)ӳF]Tgg__{*h|~U#w/ZxWx7&8;>6^gO;b4Q&im"WyfI;D|5O)fm A68^$7<*/`dAצ܈KٮF% %LϿk\8Vfj$_0a{2_`h#'x*TK21OL^Zb ۭZ 0LDs 1Z5ڴv>oH״yBrUɛN᫙6yhkyaP?_edĆ$uޖ1qC:z'wʧ 7cuys4iFzQj{ޒk ̳x{/dy/i=y_ ir{yFm O~B9."FJߝ A+ n@*}jndA-ɅƓ'%ܩ&"b<).JC Y>'kR-Q,KPmz~55 d2}DC`}>4t#YL{UNĄ&Gr Uأ6365en83%s\h{ㅿL 1@syW\Ys*: " /]K"+mYQ#WJվbgX3WinEb6>eff٤` }ûc0=!y80ǃ0q<Ȍ Oʽ<'&[ h>2ffLtW|oɅ z$۳S\v_`ٮqvKeV BF" =HbLpC8琜aɑb4vlc*ܛQf'#ј5,6v4fRޜ0"bB,!?hҟ<è\H>P$^Ռ+ZV w!hXGD ]@ ~#pR{@Ց"ity_DX[u0z `Tz)`M:8Ȕ=)HwiymKG_^J)hgPT@r^UxmOyLsFxдRC^{r1Wo{0D_փZt7 GJ[Ҕ `q+!;=u {/*}S޿s9P{&Ug -fr4`8eYS8,C^@9":\R!OߤX([ G!NRF A %甆7|Ӗ^{QÉcweFL*>8Nԋs^?o u`^U?`1首JpEU,7û 8ڱ X, 1;T^I[=mq ٽō8K c 8HA _~x׭G$jmK KlŹa "߸,6n{veղ,MnCpp~fd]Cs82"e%YigI@^F5LhżlMyE_ /[4Gcn==u(?ox?_{{H_wvN ,wGG[A~ZIl>>6V4AH$h }j($3\"w^^ EfrCQ>*ϱ[KR"'#}Y;[c eȆɾqrs^[{z2dW&u`EIT<R*ڻ>[ |F2zLp%K"aWC?QB;<;0$&yYIEE%L`}Pn*B2{p-Ю~C[A<h0R8p>JRy2X5w3;EN@ g+ >PV0t6OL!P:ZXKqo47AO]en* 9ks&ob[6XmN'\qUhx'6IKNO'&o\֨5w@ZTP2`鎖'b_<2usYj BcBCt\㽃qYC_Q_ip==5VjGJ漞nԉztjb>֝1󪊽)=l'@yǕg5ԐЇoYWӋq"9MO;Hoko$)4{ca# 1nB٤L11gGeЏ`fD4/ΔH'7 –^@Aa72꾊Dޯ݈(EԙDu_@`NPN(aAx/#L?!/yfʶY ]gb5ҫPpS1T 9Ti!Oca ɉז]vЯ"_֊K+Jwakfذ8˩يm0} f.١g\69Jn5\/Z=n%^S*n&B*| z[=s@*Mxf 6'EK+^MOq0]UZ$BHVn׉QMQ癗ݞB9; 0W4] k D>'9ҽ`NwؘCM“{twXٞB4l}7 k@2ωຜgH(bg\k#ͮ5TQd [ R/(yP#ZLO[qhŗs;"1╣M/`"s vl,6FcfЎ$VwzPr8B[\ :n%x#D4cYJ \aYKpt{f>NtW U&[91ѪEmJ7:y3mn VZlhq@]<ӦEo$y˪ HMqzp]9 BI^<|Q OhI;JύtPLx3ee 1h16T6ox`h~œ鰴Y9tB/P"H2)}]IA9xC`(}&Tc|V#sȟ\ShTFC|ϻzZ`X!̐8U[* fqB wyk<^pK!O`fČ0 (d cV{b:6Plg^VOk5Ba.J{t$!HNr1w_0Nsdn,כ~/3 /?v6EppJh;uz!ۦAPݨmYpY JF.\3 ;X Xo)Oz\9De!8/ F ŵ[gP;8W &]m,EU*ȥĪUJS mhDZo#6gi8 gXU(u_fhe1e}S7_>cmƊ -~E˪.j: ~~4ip?t>{&odXsxE { "(w:[(*xVbHq5-T7`ܦ66W/﫴'MR4iN<;e?`/y!r54BiuHãFcvbK!gq^Bߝv P)7-+diEg./G[/7>I(Ыi #7 nW'tsK3 іJDžWgB+6ΔfQP*b%;>f݃邋"^+R{/F/&rnN̫b1Yax{kz$$hK?j4dJ-@8&WnK&_+7ky3lvpe^ê-CnY =|ЍfbmīOZ~?OJ@,ݭRvwR:“UVn(.$uȍ=٤W gR-dw>I)I C 13]h3hO3J)Y!J#h/i{"[U`($/Z}X?9lܟ>#X U)xŞ,i/Y:x X`G RD罂E~d;qfikNNve%QebW⏹8@- Nݮ]&ZM S|=̱ 7}A9 $PUl,{ Yߨž}çy6mwZχ!d7w;YMD{f6Gc/=_6jg"U$l~7&ӷ}-YÎ@Ս P\ަ(c'v `xĸ#0A@LP&X뭰c9$UlazJ25{羲D|+L?h kҧ]CTXX~2o|Qz ςxeMQA;Ŷ$pǎ_  ԇ9v*Lr(Ir]9=GJ$ 8%_ gYX zl7` |1A ٦DZ3r㔖$U GJKL]k`J lB3(s;x"@E-0l#4}->bD^u bkU1$']Ktm ks۱p 9%ybaW)~bV vT oojOh~5WEtkO,7"g_Jn'NoD%biw]TMQeb :Z@IXB.QcNjT:+40KtXȄ-^'bt- l%g"ۃje:"pˆ([C>u8MdlX4%No+ 2e S-oPhx۽bW;f;\ޜ4)vꬭ#$,uRr!l!UMi\%"a=}cꥵozH \4[.*]I.boP @u?~ՕaY:7fMkK(M8Fs3)y -=Z申Fq=rZ[ pq#@I5g=bf`*׬5<h&y ]2IdBC`5Dm䦄w"9M3,>a)o3DPyI8Dqë֞x rFN4/6FAHL^+?HO$ص9smIU)U1?ò߄F~W3qܬX}ft: ^1faw9gvSӾ~TK07E,*YB~JŋFc6*',Rh`!SUe(rVM)L+Q72|kW1S4A'3 I?mLJώKi҃Xsc.w^(t]/,:a0.vuR& 58+m_8(%j_{|?)W@+X'X GZv%Рv)>TdD[riQqi. +aL~'5aeE2:ɖk^ WP@࡛XEwev71!\K=#J;`9^0ZN/­@ɗ:܍JJj .]M'LTsʴR y^ڡct\ bufNɪ.Zɧ8a?&!/ߊݺyCرͲ17T/d+إP% l=}eJ'h"]r/8):Ypw-xN]%aҝsv|[PElҾ-[̸(䏞mW@jyP;8jKMmenՕ%5ɒ!RߞD aN3dА~\0z146a=71/' ŀJcj}V;{Uy gF6W2 J$k!]5fNwV01acdM&Qks&=WeDQNM`*.ֵx>;c^K+-qT'<K%W-S!˨h!Io0B%;XN+ B)'=rDhefgW(i c9TH%@NŔXCNJ`jeOF!> ( B]_ץ{z ֬PT*VMf]Ը.Zp$8bɬwaDB <~f#Z6Zv. ڄj?\rJ*%Ci\e)+b _d$Ґa58%r5f dMCl|9OIIYSR2j._ui&p0glwE)lDET(CovAmYߐ~1& ϓmwD' %#p*L=HFccw=e5>rd V1 }eR*NBeՙƗ%S4V(bbG _rI$I$I$XnBroe3ciTBT1rq S*[P*C/vD ׯlR{|T I3Ƥ.=DdCH.hX{׭+P̾k c63׽)Y=@Lm3 MR\>5LSQfOGےI$I$I$vd5V +~i Cl-.]4$,\KpQZFe{, KFȠ~ެU=='}}Aθ1-װsqتHX>Z'0󬱎~LS^B!'bcuzkSu?Q8WF^nK<ƚXߨ֒JG@ 6I$I$I$* ACP9S{ߐ'vRбZ*%~/a !5. ]kΒQ'`FTUNjF `q0ŤL h.Ÿy]a~o(_@HKֽٻ*^X,։]FBĿ:Efk Pmu%=E,&Vz{e8D,wS [O$9ea5RKUQ 5+UҾE=R@2BC`i6W5U"Fwu^mhue}kp3Wٗu,u[d*"9\9= 58UŒ Ep( :6e6b@p` 9Un+ Skw uf#a naO KHq`AGIhzY7uYHZSّl5Hc4qȿq"B괚2U |-01wZk!xzZ5ME™Yܮt1a9Jou-a`. .ۣ=7/څLH_LNtǁU%ׇhXV %dgf"N'ooLJÞ۵zϘHUtT~m%_Ccj@ ynP1v^jEt9._8&j@%mAMG8f hpB2U#!?ڃscA M2= 8N(]Kh %)ߔᚼ'Nȏ~QpG>E0u &vS +gtX6*F:/ePb`]P['I/N,uf pC\J{y)x_OS̑z X+-ڈB$8hLutjdJ‰bvdކDA_mok Wq1=,޵\%f`l܏7jiA9fScKJdtxt\⑀ "?]i{;z&+\QN401;*?RyWd7k6~Դd ApRZG@zN6כN&cX#A-F) NK %k❍2}RԨCZTTSH.P2vmgXA PHOC c߯9ioLR^H\L7uvNTk[ k(yZznD3 v P4z"dR1r##0ڸvZF>#OBOsbͲ|: d=iث,WV FҀ'^|qfw`q^E=[m<.e[B-Bp4c9p~ܦ?dͱ.OHt`hɴ*.Ն^[2@2t:]LcMƌW%p ,~xv(Kz'0%.ŞX¦8\ɥْ"|K_>Zlq=,ad')r ZJ)d4(*3%x|"I e0mSj@J&jrAϧ80i\Zmah8XfsIi{bZ5*,`c!$ oa{^waD2+c 6t_  Z_-*;|(9֦&A~D)w2oy DS#ϩP=njl@[tjϔ$!Ru}n4̦q8C4=ʲK`ڣ=8&ẕ#Qxnxk ˭ $蘏KXݨ7#p%M\AÚfV%xB{vLW<!V3/ p>VƐ}/X?Su8IAPxUGhɩߢ6'/)>ta%mXg&UM&vvfytt3db0hάQ}" 3wgk8Sq}QI.sPym5aJ=EXd5jhr!VZ}D!2#WīMG6~ ȓ`$CFPpօRr˂bũdC!] 0\ *owv#L#庩TQ?/c+uIYDͻ=[e.'/F ! '-`Wǡ׍6>B3̹A }ī|~>-N5H7j29X#]%h#IXpV ]63a:{tepGFdIc= T`'Z^8~tG_ݴl?wڥz:- CZ \T@£g"!z! pQ=&RЗٍ87`h̽_ Z<9L ,"vHooNs݇yёeVw%::+hX;<8FM b ɎWeARQгSܢi})^^ݣW1Qy\) lKT5IB @ANw#kgV_%EWg^*Mki% d_=L]x,bXd) S=1@#θdl*a?A!:"Ca=j1vY'+ ewr/q< %Db5$¥ny%:fdS.ЁA7ʗa!(pW$>|뇘XM"A؄j> پa_Z V" CQPrHŗcvlc1[֨AX(޹evMU޻/餉kpO^ & x?LCMjUp,G3bR#Tn5kZ~Fs }dCIݸnE2.\$z.%@ ׶[En9CErWR;Ҍ["pK/>uZXc-k6rZHUjS=x0$R/[ 3z)w,fP yF 8YFMt-/A0=Ar֚jswԶ}okL"[ |o17dv0 񠃪 π#h!w#GFbzJoj鬛%ѓ-[:ƹқfa8}D\@trD:u6\#~L4G\Xz2qucJR,B,`m>Q23\'ys'9Bm9ՆfC{Ա;NW-K&Bo}DW+sL)ԅ<JȀ&3 DK_+]'7[i*SwLbpae8CImuwf Aqg ^+#ZiI:-|]l' D+5_p '%aRN&BV&q7y.08] `Շq~ YNf#}z͋ $K#dOLzJfhrz ]z`94\,KBU)iG,:nR{ot [$`HFyl=&n >f3ԪB8= YNohy`jx Y1W̦7Ng?S x*: `Fz` c-s:n U}t%ԈK,qҮ䵁į]d}:FؑbL# 04yXHYCP`Pc930^U> ?CX5`Ns_jeT~ӿ{OÍ")>,)]7@F$AI$Ǟ֒?ds%PdKX5Jfi-|o*(r}}z5u.$aPjYb}=0./ĬEQ/YOIq7cQGpa(Y̟_xdVPWqVN"pϹ t ->0+'m_.3weu{eȭГ0e5 -j/u௼ {>3_H9Uu!b(׀G )1>BЈGh~~~)pdW]44꺗7U'_ @Sp}+aGW4{eƌ2VtʒqE^3ug%6 +]u>"Fbݙ(V'%"A^wY\@k?y TachΌ^ 龫/(IX?o5geY5/HAӱ!"o5ET# "`Б@9r1>/zV0eB|fɈvG.($~ 3 2XC|& Ysʁ{@jxW?ݘ6v7CbELwx"B$x_bu{A=-V.Æ8GYJNb|+GBޑRۚ[v9^Y]-Ac[SmG)*c;c"/;;1'mS@2^*PN9D\\w.)Ñiy]3klystrack-0.20171212/klystrack/icon/256x256.png0000644000000000000000000010744613214501362017235 0ustar rootrootPNG  IHDR\rfIDAT{̧gZu<{=x}X'  T)DJ6R5)m?J(QUREH!D P ivaw8;<}Uƞ~g|/I{;O]|j2gk$?D,w`;8lӆXf\9 W  #`} -8>H,3~oO6Dޞ7 p m 15$bcDmgi 9i &G! &MA7<@ Xk~ nrkN 9iHIc,$prjliDMCJZ4;톸SBKN#jRG-W܂FDyDI-bA[%Ԑi 4y«gnBoQ{=BN-&N'HqH-ϱ+_[/&l|J=aBsjH 9"j WN8+b| ׄ֎ٷu$ V9~WL@3BÞ" E̓"@nDv瀟-ҳ~Za p!NGD+h̀=NՈ8 PyK(1A=%$G&p A^(^T 9"V 5" jPB!4 XuCkf|;ɌZv~ڑM\pܕyIVM=-a_|ȂYǝnDmi48cBm5VIܨ!Qb ׉1&9 1 l_ qDi$m 8u]qt Ns'?IOxeƅ#rȷάY?}L(sÃH]Xn&7 x JΨp o2lGTW,- 8;Bo3ADUJQuf֟=w݈1>9CBb4>Fӿib瘾ˈ8Fd;_;WΜdi`Xt+9$E_}"MgB-jz,=m6ϸAdSQqA#l-I =el-!;)j0^ D2sofh,9(\NqQpg|/𡧘͞8wJhzWt@:N_9p&*KaAҜymUo}/\:Ҡ9s`]*\:æ#׆rDTV*qU g)D硯PӀ^~۬y'N 9k\8hq au8:]תsPlؼoCވ̧˔k,!;=yGy In +6-XSqBQra1̐ʁ\P*!!ܔQ$\Q=E\% 8WSCC (wn(EcA+(s BglV wedc'D ƂA+m(h( BӮ!3]NĬO:4y:@9x6܍Z 1C$u "V9 ;d xV,U01 Ksê!Q80 iB{{& \@`AyIl̇$/pcbfVFvZMsbtMe@f 99F!N"1UH3"&H7cls8U#"E'rjYx{<5-t_97p* W:Q/}8刖ْV5̏y*l:=͕cU^xA 2>|dkoo=^YmG#OAV3bl$~w4re#u!ۜ1m;7y_qLJABv8 W9 :DM@b!ŎB"UW .D@Bl4g,+׋ b\pQĝ(xBB_RA:JF͐*Hξ7 w%]C(!@: *  WBȵ5{. ʹFp8'@) &nZ'XV5UP( T *9{,q'ܼț\k`sLCрHQ A#{dŪaՐjXu)jJ5rs P3Lqi"`K@.qDB_Fr SzC3/Fh4 J@"CXP-BH8b\/!ܜțy桇pj)rG?8}Y7@S&-yPԐ@(UAhX`7$x,g@Xyoڱ+bpy;m2~zJ`t[=[Cg7Qh~|5̄&r81_Ỷl+;Ujh8s'(1V+q)lM>+>\%9jvq@9A/Km(VMr3bc&}eo3|ܮu##aiYġ8{s)οx2VzQq*n: (+ 06k!iF\Օ F[fys+JS\Zy] 4ϔ?<#;(%6/R灝zJ{Iʴrara3gVӌ瘕3I]RB:I Ip3"oFJ3bXk15#HZg8(wF F]e0)1ԮU^հ.8ˀ.D9ł{H5Rn;MrK[*l ܷ\2ܝ6 :JtqDNfEBJ{.8R!1/@uDnn~׀w@xw99 1MvD& *94]_,:]/'l.g&F "`]bLI<#8ڽ@=t/n=T# ֜[$.nı8*0V"Y9Q+ BSB-{;@3^!j#I݊܄P3}r'1Z#(/>ImhgynL;X:tL-NN(iV'ufZ"hʡ{Σjس>YyULԑu2#y7- $Iݼ]yq+5,_Ft"[Uc%AIO}؀qƆ3S˼%G\%n88&uC~>Ƌ_qV7J-I݊܄P ]*S  iđ{ύqx^PsK5YQÝ]Ahm^Oxw9% 57N;74 Vscfp0SQqD,`}`FP#J@1ޛ$FK'yܰ b`͍֜m`B=+I*,+܌4aDY\ψܜk HFE=BȨUֲ88d "lofD +F1!b6gR0)m "ƭ1@t}7'̂Ba8j/ 0ZҤ`AaeDsa҃K)K#@P2. *9\%0w 'j`Z7DW pzP:\ mqibf2;Q*k/;"8}` Kyfy^PkV8ʬH<`,x=h˾7B]hAb0j׸; g!apsckwn[AW9 $҆@V(Qvk&P YP+YpZP/:Q!,Cy($rI9k@˔ 8B&{g25Awūq܅YA& M XAQ+ܘL&L7TvX:^eH5ޜ 5 Lw fĚAJOW* Rr[ fX?Mf: uXa/*]\`HrPdmYY*7gPa)v檾rUXE)tiJ= K@1셭 D[O}wx^iq@;O6ϟ4];FkNӈCWNs?!I+w.=ɂX&>^22X!KԜ,9g|Wilg߾ѵ9:<@_3y>:5e'5BSkh5^|c!8n'~lQC8ƭ̹KngA"1#.BB(BW#bN1e` 0PDL5!/WݗPDc)J@X5CZ O\Va``V pzy¬x2%g'xJ3L) @0ɂ٠DK"HܸU5qsĂF&u3@pID! J&z,TݰsB"1% ")0 ul,sSD im^7eG:!sK#Eܡ@Ee?n%,,;;rcIR3P"-SP!ԈQ"1pNr pc;^4٤! ^81 B-)7( `7rwk zk/,F8 "bLg;bN)6+ !2\FU]?`gѵ ķ tI|@:vl݀ nhy@]G̜ba5q&eN+ևpt9Ngn@\KD(b ✅ ܴ-qq`͜A7'uJl'ľ(ӮaZAE8jX:f,GKχp܁J,m]j6qMXPnFKAXHԳX$O,ՙ qӨ*fN1S9mI<!]ˉ-^|mrI<4Yz 673 l RPiuB|gk;Q*ʴjTdor JjWqҳ"\> ]5MW fXzD97rRܨ4O΍-ֆB;o9k%bL1ԙUN&'VG3>|YF _|^yxX: c}Bh.T_&e>澱Ҿ%B2N(9€/vH q.p'ōKlw %c Ӗ$Dfݘׯs˯ɱqKW )?x4=*KD# .BoqRIy h56C8^8!J;) "k̍LjXJ褤 L Ŝ~Rh-aҠ]ycS;$/A]Fv!+P 3p9;bG3Qͮ͟p}2nt w# K̝w";0 ~A M96dE(.Q\2Y%hPE8"r%ogy=\r8^;;]>֌<{(ձGמO3L-_ya;~sh䢘 O^",*CQ⁦"<ڔ?x%\*k/(kL,? _]{gZQJ cȈ7xN}b:f)YA)-_ZgG'Y % BHA$5: ^Q:dED1E`zF͸CP-,`M悹QLQs)f)fB((4>0ЪC z 1Gr0@jd\zenra.wj ~ꊊaXp>^½&|&bw#" N.+baCG,H04PqDI@ $|bZsǝswܝ[b8#8)΂#,8‚; bܹᓋ< %c)^^X4 D3q gA&gnpEN+M D>o]DT"|*kCg:YC#u\3@2rt'BaZ~{l?D: CaCwזzWg?Éisǁ…g`{)!R3&Jg88 :LAI;Ӟ1 h |&YX'.rS LfG8.ӈb|pp}5d^`2}(%cDHB"baE3I1f2 bO" /"s`/=܎podRiң8-?atX@Yq7TQUa 4 *}+Dž[@5 ^P?8t@F\5DU`X8 {}߻yve OEvvsDGQĖ]A ]Yr7X%&mŬxxQT'YaGZк%`6E4q裉 "F2!BPRU8 eiQQ]UHSwx,(qnNg NNCaΝHu q+} %Vt-se4Te:3GB:D\mINW)t<,♵1.a=P1^g0kŇ[b!"f&F;I` Pq6ֿk N;O ILH4< T'FX(yK%R T U,9kKLB(S7^ FxsρD.g[(ĆE9?뼷c@Ospw@CN[GId?Lb ]DnDnAn;w%"q()fvaWԂ, I 0L S˜])$ 8^TH0}:#U=!\-T ;xoLpR(.<(ZgRJqETc8n\ ΣB(h(,h pŧV/ˊָL$Ambr>ƴ5xP$8]3d:^n`8]y谧mWx 2JQh!}[fq'⫧~Ȯs jo |:1f.1WI!4󠉀7\0 <bX3@H(*b8PGY3lI} ܁>B R5cXu&ȳ)% Ġ\;hkM;|3Lf[4s4n<*"{u谨D͸ wRŞlQ{>oi9jkv::)$C6ݹ? k3> "BT%:ytVN׷'U7SnN[zz*%=-~0kq$O ]S pT#JH.J(( b9c0>J\߹è/-;Sz+;>)gƘ*(KnPЗ.nn[sa ¤pN't1-]iiGId"O^dmEBoM\QQX}eZG)!qd< -=cl>I(= —i'Xqb{fP8} DX8rb?4JsG|OD//out8ǎLr!c+\'Yz'ҔP+ yD(xr2a5"F+R!|sK#p枮sb%vkO|7{A;v^ gp̍^&ŊMB}*$opQRMjg$Nʰݡ8y ~ur~΂3x%TuST1,Q_Ռ~po˃D(nQCpRAKĹ2+RR.ӶYː $SLהCQ٘JRؚtL&nF`k2jń&-(0᠆i;fQta(c8]}҈-mbq iz %P2.¡G_ Ei1ꅦHAd"w %+L+h)XPbR7ADXX޹İBU;4`!7%憃P+4UjZУY1M)B9yj=+Hy&PAKo;pAlxwy}sg\". á5ܹ87ccM>֘Fy\iK"j'jϧBnde\):Ͽ %;. .ڵ7bz8XT픜,Xw 8!7XXio3\AKRus,x49z RljD)$͜z ['ĖY;'erIڳWD5܅  BCU蹸}w6N3-vo%rIvc^{6mbcz<ל9O\dn( xs8ٔ6+ՄRjK`Cˁ8i|ZK-~GSjAps. Z C?H;2:tRC[ Ղ 8Tge waDac B2z058UqW ApF!{@1 qabuS#F 3+9s?:t܎D DM8 8M8?mY(e6i:} t%""`%E@X&9i휘q`:} uĝ*L#WJDRcK)F;̕&W Nk`bC =U-8UlP1a]P)T,PŎ抽fEq.4FhsEo@W*z8VwAp>-B =BZꐩB 8 d/"',QRp;-4 SK&߾W(_S:OO1-i~z-oY ϾMGph;nGS+,C2FlF 9CɅ7is3iZ!ǧ8 <(nF"W@Ĕ+^3Gϋ Y`?1TjA]q)fbBTC 8:P%8{8*uE0 b#g>m"ZP *JPE .A07Z<ungnVKX"N<ٜLb&j T%PJ7 OPfa(%&$&pı[b[%^nsuᷕsZm~مhR+ ܔ(89bZ1*f/F)Ju(bXP+ZlM&TjJU*po1SN8ww(@ybJBNCP ( : BUH5DqUvs1c7w\p̔UCYRQ B!";n  Utt 5BqCug[s@@L(☵ܫ(H)cV'@4TD NF`8w$8߱D#(^.# iW'Q(@n&zN*A݂8I+Q*1JMTU'CJZ݉B÷9GօA x8828ߤ^ɿS7Xgp#PR""Kp~jDuhJUGrY۸Ɖ/s8h0DDfp["(W/r'5qsX&f $VFM/4ёiHL+i+@pL&!,C5厙MntZ#̽&l,T*BW ¼TS·Z#0FG"(mՊ ((΁BŰ{ T'׈X$q;R5[5b\ J  IC  17 ֑ZLkaP 0Ij@+H; D qg+rCU6a%Q״$JBAB8V#*"?pϨ@{Dm^Q-0 `.}u wtXZۢVxmDR=|k z#M*9 \qnnm`>DC8:^]8VŗBAPg f .ͯqvr~|2x'ƇBu#[BPEbS@)B6qad9hq{'"UnJA M!R5PK⠙)"웊--rKrZ߮[A3VlfXxlnp4>p܇tʘ̅N)HTH20Dn!ڀ>7t]TRC |ӅKcL ;hĦeDZDDw1.RK11׌ Üa"@PC * s]@Rg1 ʂA ):ͽ qa9>׸acm_f"$ ȓ:´̈́![~ L1S#mtu!J4 W&K4$>WvdHsfһuγS뜅Z"(shB\#Ol^FJиLp/"%~qàQ~'fŝҰs[O]oy饌l1\X!ej;]gZ~ˉS]+kf:!eGqF\`I-= 0 tTYo9٫&j|?2j`V3_c- [fpneyyTS'qp@ǭr#w@n0@p"VG8 [C\ wqpY7% 0@or^EnA̜ʽqDQ1vD7je/qv.%40qD~w]]q; UE#m p Ao{ySs(oQ'uʑΝp#BxwqSB(F[8$]5:|<ɼ&CZ"Ϝ#s~̏?$+-eAf[y;%uWCf9cV"EarvfA!ٟ56&yr{זiKyEB<I8|!TwHVzΨqBd:t .6%n'HƬ&D*oK+#R& oWn 1999*6U]P1~)q)k)]Mk#0 ,D6+g^]A9v%J5;Mm y#Ƭ5 ݈83E]Pu4ގBpJ^{mՄ#EަMsD+rA`.uE9rO% ("V_l0+Rؐ>mgpJ7_""s#=ʼДl 87ء֎_-WO. g]q^xL XKdD wȑ",#C ʰFi F0҆ha$1Є EpGw]ױנ?b4X KxhxymYJGPUr@ar'v1a>o3ܡQݸ , ycc/Qs_ʝ͈?+ yl}e ـO{jXʉ6"G{L&~a~~pȕ+Wkvy 5dk^I]-|Op^U‡Or*RbHD5Vz-qXj G躎^{~"s3uz{$2"sTtYAuuTwpFA09gmRj.UDA^VQE:.)C((t5k@9qvrCP1qwnq%+{;%faD¤"s/T0E(FgW7Wp@p(jqDAQeʴN x9Mr3+uG1€ 7'7rq 8m쇹62Ņ#o\#k)^0v8:Z !Ou !(W^d2C _cM+HXݹƫ^B ϯ^vRqIQ0|7y X>̕ {@8\1}|WynUFa |q+zs*K}|/g.a>o'v-R)~0b[v>s@0z1@a%mAtA=am14 8A 9*QPq#o%RP:.7)]fm~hdD%1s !b Pi >tBJ@BL-s; Սbl(GH!2bLb*PQ$;UM1&w%[@rCRj ṔhPS YkôeܨfJԀ=^~gf˯ŗ> M |ٚoQƕgXzvDVTGqn]Xǟg?#]ҕ=J$Paf(B[/q{TG>{>A { B+ CܾcvUx|"BD0v)Y`Z"F<2D xwwgY3BW;fuB?p7G%!p+V+A :'ILnέΌ:51Z ܎"s䰩d@RQ84MQ>]g F`Pk^o@?iRYVb0@8Lf@#i%THhFl^FD@ JbXxeeTBԄj  Q$ 1w@8r܅vsZ*)]a2TμtE1]iɨj܊-r( u,-Y)+0 ԦM WVr0eaT&XX*!88  fcn\͙׺f8r[hao 5T̍;o묀;١:.ܱ&T!fL7"UBcKG5j  `n֡5@t܃RN0 4Y?=|,A {zfsgZ{+π@uaam)”wӈLI+s&\xm 'O3*Aiyi} %h}Yvƛ,4^a+MPFfZ3d>O>΅=ggai{ fF{Wln,==9q;"98M {J6=q&)O^y]?i`/qW 2mG@ӳ|O Uņᰲ'?5n=̌yÉC> `l"t\{uʕT^Zg2 [md*E N5+Yi!%8C‹z\?=)^:0XYZ/|EvՇɵR%C'F,SDž}$ tܖsU "KC%j#Gdx 4$8(2uG(^2[MyPDlt]߯Fck\zF!y ZT8f), L' ]NLR(h;{8V),w\ x3lt\ihaЏ hEnHpi@B8 hT)x sW1s3BQ?.Z­xu*#uPݘ9 )6t3HYY)J́ *ǖqugɕ+WO6.jC:|Cюt"Ih 0f VBoj&U._su^@/D\R˃3v˵e5!J pD j:6,6Q"`lVSBJ3%`9gZSD#&n'DҊ!,Ŏ*~͍] nN+fhbXQ [uNpD%Qqqz W MT\?]*1͐#>~w:J~cȏɄ\"˃'>8^V=$83'V?sQ'tO>ԂqvKkX01sH (JG姟@F!);%Ƽz Ν_C ZދQG]#%g-/l}z >^N(G{ s[Ml|St5Ur֪ "O#WEՉbV#>F$E^ʹ;$ fRsr4^_uθv|x~u4Tg)lo$C@q6#e$֔ݮL'D ,q]" ++xqn q'5qթSC`bbt5._"HRt^Y>=b[ $Q qDB9&z [HLJhC^~yWib=yZOcd'w1X{!BL tJmQ+UǝwߍW/caF/d-A Qd03WOK Dx9 1& _qpNuc{4`0`ΛQtFn Da7%Ƒa`x"yc** .keaywrMCx6Q(BeZ]ҷ+ӫ\z("RG++z_O_'qmkN;9c?18~f'?7᳛`+#WՆ2=;~K|Svyh})Ύϝ{_+>rotR8Ꮋ%j,yϓF+E'>ā{6\OMӕ31 Q+:+,eu?r8 A7놽c 6t`l| Xv$5)Aq vró'.0 Ge#l q ZGh?=8Λ^8a8wg.Jbc! :!fj;EuNZm߇GGC%f q[lYֿHjXykMpk\'څkAL5) @7mMbB-(weq3[]Fqp8\ǖO܍*mf"{$5z҄B2I!JC AlpfcryzN7A.P#V#V̄A:'O"> Wm 1 Qa^m1r+A!)u\4p3b8GecApu3QQ&isDv)ah@¥)ԾpuƳC#RpA`':q wQJUPMhĵ *V\r|}g[^Y3H}9Ns΍\:rPQ̍2 ޠ5s*ʝPyMqܙ:3ѹ=~얄f\{q<*ljǓm˿$'h)թEkjKό8YX^_7>͜mȿAQ=8;s{%]ɒ-llJh NN'!@ۿȤ LtmJ& 3!-Ltbpc,-c[ow{}^Ylb/}"5d})#b_4K}Y%s)x[X-0I, +t%q)E5|O0"h4*#g/c6ɴFF4*khj (k%S|ivh9u\;s{f-m:u#Ձw,y|y1Tf^FDIӔcK9kJV-WZkҧh-ĸ9.`y嗥4-I2ik_k_Ϫ6ˀ_f/B&y ǎ5; Dϋ6\ .ff|sbSy 2rY{s3T"TJ4nb h60lr.zU|{Mf28B9!,# u,gUަ<ط+Ic ̡oSljlqhqk9R0!i[lRgpE- KpC#ւ /~ @bP(ϻ]3ZH &2ҭ=S Vcr";~pPyKa-&QlÀHaMD10K-KCJwWX/0t%I(|A(*8k'%i0b1Zvt"c*X"%.69F@ILLˉE+fs,͡.KMKzuuԱ&Ԋmڝ (C׀ P*ZF0U!w5 |FT\ LJ,"Ě p4 & ȱl܃G7*i(:H%sv4^ƊIxc&im?bi*&$ Vaaq!l=\#7 .xƒؔ^ebzT##"﷈UHG+W9m sx e:בd"A#$ǀJ.!YZ9 NQ*ZF6M,ٚKx5XQzUNb='J ͷmIMGXXe"(gKI|7Oj>w+RWGȒ`kt3״6{9a1U~?3pjYڤ7?1 S k2 P ([)MlhΖi>&7Dֵf]w.yҤ5Xq܋Z0 3;:d'u\dr6Qi;R.+Jov&MWY|I!S[8:{5hd _Nۨ*"6)*==*)i*$*X  Gb@A{bqYĂEb&  vĮg'UD[TYN(WC:-AjҐl༅659gBjrjETA"\*S:I@b"T瓊 *FDjO߷`UQs|,bDe3a Ueu-i4t R@< Ae|F|q PH,`hIA"*[$XO B=DLrABXIX<$ ء+DC?];rv3ēf>Lhg2qxF~ #~ l&IjE?s2Wc27<9ٹu%_X57}?/Q ¶ZG-#7]¥%Xy!K}A5k`݅sJ P.Ȉ"A8 "VD!(*p!)BA rbXsX7/xc!BX`DA"TAՠjQUW=ehA5ee뚺5| [འ*N, F#Q#"'*(HDƞbTF.b-$eR. "'ptF3QUTUEQNPS^;`'o]dh,6j-pBE4y[3S;m\I:\H}33~ EDi "(ݗ6ő;&ZpL LjH1$)e( ܶm+2~h_٤E,c/({5ԓ5zdd& cWұ &5h-rT)&oa7ujf=\n)y;{`%:z5U/ nb 'ޡQB2H,#w{j=OB}le5"ˆ2b4*ofH&5\'<EOX{Ah`e+l%RUj`,dIJQ+Ak>0Jj&Zo\OFB , P@b c؊(B"A#r}-GoYYq+^ڞav4+Y !VA\`2I>M8IY0Z+#O_3+slӂW_*8[5]_!5`s;ݷ}7c+0" c?$;Xi 6mc ˾1ӄ$`&w -,NB^C+pqSgv{;Yr,PU5/qA2v[XLi&C[DVԆWbwtm1) 0v*A1xOۊ |ʮc \KN9Qal-9iXcYVTut Z3bc %V5'H[FlfPeJ2[>< Insu;D{΂⇋شM uYQ =P|I'3NtCZ.%1 &)vh#ʰ( @#A3 baPjlE($4G+o4~5܆MCV:$ofl9J34f!iǵ,%&#FNq#%yzG{DH +./Dץ_ 4& "  1i $ĕ c,Gz, j21"I9ݬu[oRƞ2o%@}I֭[Ǡ̘^dJdD4D{OE:-Y_ßUIxk~<ɩWL%2J[{IʧNp>A釬zć?s{jཛྷey*jo w{DrIM,.qఉE<%sLBj|(Jkѣ^QBPD%PLj"PyC:֜.Or${8+D&g;OD >B CE겢8J|@ 4*`8b1(`ADX%"RU*|\Z"aX, U% XDTWTr6`0#@$>*QG]uEe*:8'Ht CRĠ J J 1X$bňaUH+DU!Z2PZ(XD '$Y%XZ*|ֺKp&wx3%.KHkm|D5 oa8bK90IE8}MBBF1|뾇X8D%4?GdՖ-鶷0hH纹GImW 7m|mBa߷a>b988Lꆄ`!n5\4b01c #G:XNfCvQ>Ob"W_͖mKFʺA]|i)qvbl|<[ˇ=6%0"i4h3t{Kyu{ V!iJ=@w ZB;= 9]pP%2g0yylPΠ |#ீ׺qF\V.;%K<c}rX%Iv="O,Kq1*mۆ37+@Y9]~=u(c:7jHkvNvso7~xcc/kg^˪m[`ۋ9[ʳc8i'sp }/]\ ..e~glȑ#Gvi 4M. qqTq z\|$`f*j`r@ɡGG}AASMIENDB`klystrack-0.20171212/klystrack/README.md0000644000000000000000000000055413214501362016105 0ustar rootroot# klystrack Klystrack is a chiptune tracker for making chiptune-like music on a modern computer. 1. Download the latest [release](https://github.com/kometbomb/klystrack/releases) (recommended) or [build your own](https://github.com/kometbomb/klystrack/wiki/HowToCompile). 2. Google for a klystrack tutorial or start exploring, it's mostly just like any tracker. klystrack-0.20171212/klystrack/scancode-tool/0000755000000000000000000000000013214501362017354 5ustar rootrootklystrack-0.20171212/klystrack/scancode-tool/scancode.c0000644000000000000000000000113513214501362021277 0ustar rootroot#include "SDL.h" #include int main(int argc, char **argv) { SDL_Init(SDL_INIT_EVERYTHING); SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100, 0); printf("Make sure the empty window is focused and hit any key to see info for that key!\n\n"); while (1) { SDL_Event e; if (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) break; if (e.type == SDL_KEYDOWN) { printf("scancode = %x\tsym = %x\tmod = %x\n", e.key.keysym.scancode, e.key.keysym.sym, e.key.keysym.mod); } } else SDL_Delay(10); } SDL_Quit(); return 0; } klystrack-0.20171212/klystrack/scancode-tool/Makefile0000644000000000000000000000017013214501362021012 0ustar rootrootCC = gcc -s -Ic:/MinGW/include/SDL2 EXE = scancode.exe $(EXE): scancode.c $(CC) -o $@ $^ -lmingw32 -lSDL2main -lSDL2 klystrack-0.20171212/klystrack/Makefile0000644000000000000000000001760613214501362016274 0ustar rootrootTARGET := klystrack KLYSTRON=../klystron ECHO := echo CFG := debug MACHINE := NSIS := C:/program\ files\ \(x86\)/nsis/makensis.exe /V2 /NOCD WGET := wget --quiet MAKEBUNDLE := $(KLYSTRON)/tools/bin/makebundle.exe UPLOAD := cmd.exe /c upload.bat DLLS := zip/data/SDL2_image.dll zip/data/SDL2.dll DESTDIR ?= /usr EXT := .c CC := gcc -Werror CDEP := gcc -E -MM ARCHIVE := klystrack INSTALLER := klystrack.exe SDL_VER := 2.0.4 SDL_IMAGEVER := 2.0.1 THEMES := REV := cp -f CFLAGS := $(MACHINE) -ftree-vectorize -std=gnu99 --no-strict-aliasing ifdef COMSPEC TARGET := $(TARGET).exe ARCHIVE := $(ARCHIVE).zip SDLFLAGS := -I c:/mingw/include/SDL2 SDLLIBS := -lSDL2main -lSDL2 -lSDL2_image -lwinmm CFLAGS += -mthreads ZIP := pkzipc -exclude=.* -zipdate=newest -path=relative -silent -rec -dir -add ZIPEXT := pkzipc -ext -silent else ZIP := tar czf DLLS = ARCHIVE := $(ARCHIVE).tar.gz SDLFLAGS := `sdl2-config --cflags` -U_FORTIFY_SOURCE SDLLIBS := `sdl2-config --libs` -lSDL2_image endif ifdef COMSPEC RES_PATH := . CFLAGS += -DRESOURCES_IN_BINARY_DIR CONFIG_PATH := ~/.klystrack else RES_PATH ?= $(DESTDIR)/lib/klystrack CONFIG_PATH := ~/.klystrack endif EXTFLAGS := -DNOSDL_MIXER -DUSESDLMUTEXES -DENABLEAUDIODUMP -DSTEREOOUTPUT -DUSESDL_IMAGE $(EXTFLAGS) LDFLAGS := -L $(KLYSTRON)/bin.$(CFG) -lengine_gfx -lengine_util -lengine_snd -lengine_gui -lm $(SDLLIBS) INCLUDEFLAGS := -I src $(SDLFLAGS) -I $(KLYSTRON)/src -L$(KLYSTRON)/bin.$(CFG) -DRES_PATH="$(RES_PATH)" -DCONFIG_PATH="$(CONFIG_PATH)" $(EXTFLAGS) -DKLYSTRON=$(KLYSTRON) ifdef COMSPEC LDFLAGS := -lmingw32 $(LDFLAGS) endif DIRS := $(notdir $(wildcard src/*)) THEMEDIRS := $(notdir $(wildcard themes/*)) ifeq ($(CFG),debug) CFLAGS += -g -Wall -DDEBUG -fno-inline else ifeq ($(CFG),profile) CFLAGS += -O3 -pg -Wall else ifeq ($(CFG),release) CFLAGS += -O3 -Wall -s ifdef COMSPEC CFLAGS += -mwindows endif else @$(ECHO) "Invalid configuration "$(CFG)" specified." @$(ECHO) "Possible choices for configuration are " @$(ECHO) "'release', 'profile' and 'debug'" @exit 1 endif endif endif # $(1) = subdir, $(2) = filename prefix (i.e. subdir without a slash) define directory_defs SRC := $$(notdir $$(wildcard src/$(value 1)/*$(EXT))) DEP := $$(patsubst %$(EXT),deps/$(CFG)_$(2)%.d,$$(SRC)) OBJ := $$(patsubst %$(EXT),objs.$(CFG)/$(2)%.o,$$(SRC)) OBJS := $(OBJS) $$(OBJ) DEPS := $(DEPS) $$(DEP) objs.$(CFG)/$(2)%.o: src/$(1)%$(EXT) @$(ECHO) "Compiling $$(notdir $$<)..." @mkdir -p objs.$(CFG) @$(CC) $(INCLUDEFLAGS) -c $(CFLAGS) -o $$@ $$< deps/$(CFG)_$(2)%.d: src/$(1)%$(EXT) @mkdir -p deps @$(ECHO) "Generating dependencies for $$(notdir $$<)..." @set -e ; $(CDEP) $(INCLUDEFLAGS) $$< > $$@.$$$$$$$$; \ sed 's,\($$*\)\.o[ :]*,objs.$(CFG)\/$(2)\1.o $$@ : ,g' \ < $$@.$$$$$$$$ > $$@; \ rm -f $$@.$$$$$$$$ endef define theme_defs THEMES := $$(THEMES) res/$(1) res/$(1): themes/$(1)/* #themes/$(1)/font/* themes/$(1)/font7x6/* themes/$(1)/tiny/* @$(ECHO) "Building theme $(1)..." @mkdir -p res @mkdir -p themetemp @-cp -f themes/$(1)/colors.txt themetemp @-cp -f themes/$(1)/bevel.* themetemp @-cp -f themes/$(1)/vu.* themetemp @-cp -f themes/$(1)/analyzor.* themetemp @-cp -f themes/$(1)/logo.* themetemp @-cp -f themes/$(1)/catometer.* themetemp @-cp -f themes/$(1)/cursor.* themetemp @-cp -f themes/$(1)/icon.* themetemp -@if test -d themes/$(1)/font; then $(MAKEBUNDLE) themetemp/8x8.fnt themes/$(1)/font ; fi -@if test -d themes/$(1)/font7x6; then $(MAKEBUNDLE) themetemp/7x6.fnt themes/$(1)/font7x6 ; fi -@if test -d themes/$(1)/tiny; then $(MAKEBUNDLE) themetemp/4x6.fnt themes/$(1)/tiny ; fi @-$(MAKEBUNDLE) $$@ themetemp @rm -rf themetemp endef build: Makefile src/version.h src/version_number.h @touch src/version @make -C $(KLYSTRON) CFG=$(CFG) EXTFLAGS="$(EXTFLAGS)" @make all CFG=$(CFG) EXTFLAGS="$(EXTFLAGS)" src/version.h: src/version @echo '#ifndef VERSION_H' > ./src/version.h @echo '#define VERSION_H' >> ./src/version.h @echo '#include "version_number.h"' >> ./src/version.h @echo -n '#define REVISION "' >> ./src/version.h @date +"%Y%m%d" | tr -d '\n' >> ./src/version.h @echo '"' >> ./src/version.h @echo '#define VERSION_STRING "klystrack " VERSION " " REVISION' >> ./src/version.h @echo '#endif' >> ./src/version.h src/version_number.h: src/version @echo '#ifndef VERSION_NUMBER' > src/version_number.h @echo '#define VERSION_NUMBER' >> src/version_number.h @echo -n '#define VERSION "' >> src/version_number.h @echo -n `cat src/version` >> src/version_number.h @echo '"' >> src/version_number.h @echo '#endif' >> src/version_number.h # root (i.e. src/*.c) $(eval $(call directory_defs,,)) # subdirs (src/*/*.c) $(foreach dir,$(DIRS),$(eval $(call directory_defs,$(dir)/,$(dir)_))) # themes $(foreach dir,$(THEMEDIRS),$(eval $(call theme_defs,$(dir)))) ifdef COMSPEC OBJS += objs.$(CFG)/windres.o endif .PHONY: zip all build nightly installer all: bin.$(CFG)/$(TARGET) $(THEMES) zip: doc/* $(THEMES) $(DLLS) examples/instruments/* examples/songs/* linux/Makefile $(DLLS) @make -C $(KLYSTRON) CFG=release EXTFLAGS="$(EXTFLAGS)" @make build CFG=release @mkdir -p zip/data/res @mkdir -p zip/data/examples/songs @mkdir -p zip/data/examples/songs/n00bstar-examples @mkdir -p zip/data/examples/instruments @mkdir -p zip/data/examples/instruments/n00bstar-instruments @cp examples/songs/*.kt zip/data/examples/songs @cp examples/songs/n00bstar-examples/*.kt zip/data/examples/songs/n00bstar-examples @cp examples/instruments/*.ki zip/data/examples/instruments @cp examples/instruments/n00bstar-instruments/*.ki zip/data/examples/instruments/n00bstar-instruments @cp res/* zip/data/res @mkdir -p zip/data/key @cp key/* zip/data/key @cp doc/LICENSE zip/data/LICENSE @cp doc/SDL.txt zip/data/SDL.txt @cp doc/SDL_image.txt zip/data/SDL_image.txt @cp doc/Default.kt zip/data/Default.kt @cp bin.release/$(TARGET) zip/data/$(TARGET) ifdef COMSPEC @cd zip/data; rm -f ../$(ARCHIVE); $(ZIP) ../$(ARCHIVE) "*" @cp -f zip/klystrack.zip zip/klystrack-`cat src/version`-win32.zip else -@rm -f zip/data/Makefile cd zip; cp -r data klystrack-`cat ../src/version` ; rm -f $(ARCHIVE); $(ZIP) klystrack-`cat ../src/version`.tar.gz klystrack-`cat ../src/version` ; rm -rf klystrack-`cat ../src/version` @cp -f linux/Makefile zip/data endif installer: zip installer/klystrack.nsi ifdef COMSPEC @$(NSIS) /DVERSION=`cat src/version` installer/klystrack.nsi endif nightly: zip @cp zip/$(ARCHIVE) zip/klystrack-nightly-`date +"%Y%m%d" | tr -d '\n'`-win32.zip clean: @rm -rf deps objs.debug objs.release objs.profile bin.release bin.debug bin.profile zip temp res bin.$(CFG)/$(TARGET): $(OBJS) @$(ECHO) "Linking $(TARGET)..." @mkdir -p bin.$(CFG) @$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) release: bin.release/$(TARGET) @$(ECHO) "Building release -->" #bin.release/$(TARGET): # @make CFG=release ifneq ($(MAKECMDGOALS),clean) -include $(DEPS) endif zip/data/SDL2_image.dll: @$(ECHO) "Downloading "$@"..." @mkdir -p temp @cd temp ; $(WGET) http://www.libsdl.org/projects/SDL_image/release/SDL2_image-$(SDL_IMAGEVER)-win32-x86.zip ; $(ZIPEXT) SDL2_image-$(SDL_IMAGEVER)-win32-x86.zip SDL2_image.dll libpng16-16.dll zlib1.dll ; rm SDL2_image-$(SDL_IMAGEVER)-win32-x86.zip @mkdir -p zip/data @mv temp/SDL2_image.dll zip/data/SDL2_image.dll @mv temp/libpng16-16.dll zip/data/libpng16-16.dll @mv temp/zlib1.dll zip/data/zlib1.dll zip/data/SDL2.dll: @$(ECHO) "Downloading "$@"..." @mkdir -p temp @cd temp ; $(WGET) https://www.libsdl.org/release/SDL2-$(SDL_VER)-win32-x86.zip ; $(ZIPEXT) SDL2-$(SDL_VER)-win32-x86.zip SDL2.dll ; rm SDL2-$(SDL_VER)-win32-x86.zip @mkdir -p zip/data @mv temp/SDL2.dll zip/data/SDL2.dll objs.$(CFG)/windres.o: windres/* icon/* windres -i windres/resource.rc -o $@