├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── README.md
├── android
├── app
│ ├── build.gradle
│ ├── jni
│ │ ├── Android.mk
│ │ ├── Application.mk
│ │ ├── SDL
│ │ └── src
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── org
│ │ │ ├── libsdl
│ │ │ └── app
│ │ │ │ ├── HIDDevice.java
│ │ │ │ ├── HIDDeviceBLESteamController.java
│ │ │ │ ├── HIDDeviceManager.java
│ │ │ │ ├── HIDDeviceUSB.java
│ │ │ │ ├── SDL.java
│ │ │ │ ├── SDLActivity.java
│ │ │ │ ├── SDLAudioManager.java
│ │ │ │ └── SDLControllerManager.java
│ │ │ └── tildearrow
│ │ │ └── soundtracker
│ │ │ └── soundtrackerActivity.java
│ │ └── res
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── igfd
├── ImGuiFileDialog.cpp
├── ImGuiFileDialog.h
├── ImGuiFileDialogConfig.h
├── LICENSE
├── README.md
├── dirent
│ ├── ChangeLog
│ ├── LICENSE
│ ├── README.md
│ └── dirent.h
└── stb
│ ├── LICENSE
│ ├── README.md
│ ├── stb_image.h
│ └── stb_image_resize.h
├── papers
├── format.md
├── help.txt
├── ibm-plex-license.txt
├── info.txt
├── ohplease.png
├── ssformat.md
├── ssiasm.md
├── tooltips.txt
└── unifont-license.txt
├── soundtracker.kdev4
├── src
├── Android.mk
├── blip_buf.c
├── blip_buf.h
├── blip_buf.txt
├── fextra.cpp
├── fextra.h
├── font_main.cpp
├── font_pat.cpp
├── fonts.h
├── hlesoundchip.cpp
├── macroStatus.cpp
├── main.cpp
├── nsstub.h
├── nsstub.m
├── player.cpp
├── song.cpp
├── soundchip.cpp
├── soundchip.h
├── ssbench.cpp
├── ssinter.cpp
├── ssinter.h
├── sslisp.cpp
├── ssmain.cpp
├── tests
│ ├── duty
│ ├── fdistort
│ ├── filter
│ ├── fsweep
│ ├── fuzzie
│ ├── psweep
│ ├── shape
│ └── vsweep
├── tracker.h
├── unifont.h
├── unifontfull.cpp
├── unifontfull.h
├── utfutils.cpp
├── utfutils.h
└── winMain.cpp
└── tools
├── CMakeLists.txt
└── hex2bin.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | .cache/
2 | .kdev4/
3 | .vscode/
4 | build/
5 | winbuild/
6 | .DS_Store
7 | *.swp
8 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "SDL"]
2 | path = SDL
3 | url = https://github.com/libsdl-org/SDL
4 | branch = main
5 | [submodule "imgui"]
6 | path = imgui
7 | url = https://github.com/ocornut/imgui.git
8 | [submodule "fmt"]
9 | path = fmt
10 | url = https://github.com/fmtlib/fmt.git
11 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.0)
2 | project(soundtracker)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 |
6 | if (ANDROID)
7 | set(BUILD_GUI OFF)
8 | else (ANDROID)
9 | set(BUILD_GUI ON)
10 | endif (ANDROID)
11 |
12 | if (WIN32)
13 | set(SDL2_LIB SDL2-static)
14 | else (WIN32)
15 | set(SDL2_LIB SDL2)
16 | endif (WIN32)
17 |
18 | add_subdirectory(fmt)
19 |
20 | include_directories(fmt)
21 |
22 | if (BUILD_GUI)
23 | if (WIN32)
24 | set(BUILD_SHARED_LIBS OFF)
25 | set(SDL_SHARED OFF)
26 | set(SDL_STATIC ON)
27 | endif (WIN32)
28 | add_subdirectory(SDL)
29 | include_directories(SDL/include)
30 | endif (BUILD_GUI)
31 | if (APPLE)
32 | find_library(HAVE_APPKIT AppKit PATHS ${CMAKE_OSX_SYSROOT}/System/Library PATH_SUFFIXES Frameworks NO_DEFAULT_PATH)
33 | else (APPLE)
34 | find_library(HAVE_JACK jack)
35 | endif (APPLE)
36 | add_executable(ssinter src/soundchip.cpp src/ssinter.cpp src/ssmain.cpp src/utfutils.cpp)
37 | add_executable(ssbench src/soundchip.cpp src/ssinter.cpp src/ssbench.cpp)
38 | set(GUI_SRC imgui/imgui.cpp
39 | imgui/imgui_demo.cpp
40 | imgui/imgui_draw.cpp
41 | imgui/imgui_tables.cpp
42 | imgui/imgui_widgets.cpp
43 | imgui/backends/imgui_impl_sdlrenderer.cpp
44 | imgui/backends/imgui_impl_sdl.cpp
45 | igfd/ImGuiFileDialog.cpp
46 | )
47 | set(TRACKER_SRC src/blip_buf.c
48 | src/soundchip.cpp
49 | src/song.cpp
50 | src/player.cpp
51 | src/macroStatus.cpp
52 | src/hlesoundchip.cpp
53 | src/ssinter.cpp
54 | src/fextra.cpp
55 | src/utfutils.cpp
56 | src/font_main.cpp
57 | src/font_pat.cpp
58 | src/main.cpp)
59 | if (BUILD_GUI)
60 | list(APPEND TRACKER_SRC ${GUI_SRC})
61 | endif (BUILD_GUI)
62 | if (APPLE)
63 | list(APPEND TRACKER_SRC src/nsstub.m)
64 | endif (APPLE)
65 | if (WIN32)
66 | add_executable(soundtracker WIN32 ${TRACKER_SRC})
67 | else()
68 | add_executable(soundtracker ${TRACKER_SRC})
69 | endif()
70 | target_link_libraries(ssinter ${SDL2_LIB})
71 | if (BUILD_GUI)
72 | target_include_directories(soundtracker PRIVATE imgui imgui/backends igfd)
73 | target_compile_definitions(soundtracker PUBLIC HAVE_GUI)
74 | target_compile_definitions(ssinter PUBLIC HAVE_GUI)
75 | endif (BUILD_GUI)
76 | target_link_libraries(soundtracker ${SDL2_LIB} fmt)
77 | if (WIN32)
78 | target_link_libraries(ssinter SDL2main)
79 | target_link_libraries(soundtracker SDL2main -static)
80 | endif (WIN32)
81 | if (HAVE_JACK)
82 | target_compile_definitions(soundtracker PUBLIC JACK)
83 | target_link_libraries(soundtracker jack)
84 | target_compile_definitions(ssinter PUBLIC JACK)
85 | target_link_libraries(ssinter jack)
86 | endif ()
87 | if (APPLE)
88 | target_link_libraries(soundtracker ${HAVE_APPKIT})
89 | else ()
90 | if (NOT WIN32)
91 | target_link_libraries(soundtracker X11)
92 | endif (NOT WIN32)
93 | endif ()
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # soundtracker
2 |
3 | this is an old chiptune composition tool that I made as my first program back in 2014 (excluding the tutorials).
4 |
5 | this tool emulates/implements a fictitious soundchip that I thought of years ago, with heavy inspiration from the 8-bit era soundchips (like the SID).
6 |
7 | # and what is this "ssinter" thing?
8 |
9 | ssinter is an interpreter for the soundchip dump format. check [ssformat.md](papers/ssformat.md) for more information.
10 |
11 | # notes
12 |
13 | this project uses blip-buf, which is under the same license.
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY');
2 | def buildAsApplication = !buildAsLibrary
3 | if (buildAsApplication) {
4 | apply plugin: 'com.android.application'
5 | }
6 | else {
7 | apply plugin: 'com.android.library'
8 | }
9 |
10 | android {
11 | compileSdkVersion 26
12 | defaultConfig {
13 | if (buildAsApplication) {
14 | applicationId "org.tildearrow.soundtracker"
15 | }
16 | minSdkVersion 16
17 | targetSdkVersion 26
18 | versionCode 1
19 | versionName "1.0"
20 | externalNativeBuild {
21 | ndkBuild {
22 | arguments "APP_PLATFORM=android-16"
23 | abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
24 | }
25 | // cmake {
26 | // arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
27 | // // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
28 | // abiFilters 'arm64-v8a'
29 | // }
30 | }
31 | }
32 | buildTypes {
33 | release {
34 | minifyEnabled false
35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
36 | }
37 | }
38 | if (!project.hasProperty('EXCLUDE_NATIVE_LIBS')) {
39 | sourceSets.main {
40 | jniLibs.srcDir 'libs'
41 | }
42 | externalNativeBuild {
43 | ndkBuild {
44 | path 'jni/Android.mk'
45 | }
46 | // cmake {
47 | // path 'jni/CMakeLists.txt'
48 | // }
49 | }
50 |
51 | }
52 | lintOptions {
53 | abortOnError false
54 | }
55 |
56 | if (buildAsLibrary) {
57 | libraryVariants.all { variant ->
58 | variant.outputs.each { output ->
59 | def outputFile = output.outputFile
60 | if (outputFile != null && outputFile.name.endsWith(".aar")) {
61 | def fileName = "org.tildearrow.soundtracker.aar";
62 | output.outputFile = new File(outputFile.parent, fileName);
63 | }
64 | }
65 | }
66 | }
67 | }
68 |
69 | dependencies {
70 | implementation fileTree(include: ['*.jar'], dir: 'libs')
71 | }
72 |
--------------------------------------------------------------------------------
/android/app/jni/Android.mk:
--------------------------------------------------------------------------------
1 | include $(call all-subdir-makefiles)
2 |
--------------------------------------------------------------------------------
/android/app/jni/Application.mk:
--------------------------------------------------------------------------------
1 |
2 | # Uncomment this if you're using STL in your project
3 | # You can find more information here:
4 | # https://developer.android.com/ndk/guides/cpp-support
5 | # APP_STL := c++_shared
6 |
7 | APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
8 |
9 | # Min runtime API level
10 | APP_PLATFORM=android-16
11 |
--------------------------------------------------------------------------------
/android/app/jni/SDL:
--------------------------------------------------------------------------------
1 | ../../../SDL
--------------------------------------------------------------------------------
/android/app/jni/src:
--------------------------------------------------------------------------------
1 | ../../../src
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in [sdk]/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
23 |
26 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
59 |
64 |
65 |
68 |
69 |
75 |
76 |
77 |
78 |
79 |
80 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/android/app/src/main/java/org/libsdl/app/HIDDevice.java:
--------------------------------------------------------------------------------
1 | package org.libsdl.app;
2 |
3 | import android.hardware.usb.UsbDevice;
4 |
5 | interface HIDDevice
6 | {
7 | public int getId();
8 | public int getVendorId();
9 | public int getProductId();
10 | public String getSerialNumber();
11 | public int getVersion();
12 | public String getManufacturerName();
13 | public String getProductName();
14 | public UsbDevice getDevice();
15 | public boolean open();
16 | public int sendFeatureReport(byte[] report);
17 | public int sendOutputReport(byte[] report);
18 | public boolean getFeatureReport(byte[] report);
19 | public void setFrozen(boolean frozen);
20 | public void close();
21 | public void shutdown();
22 | }
23 |
--------------------------------------------------------------------------------
/android/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java:
--------------------------------------------------------------------------------
1 | package org.libsdl.app;
2 |
3 | import android.hardware.usb.*;
4 | import android.os.Build;
5 | import android.util.Log;
6 | import java.util.Arrays;
7 |
8 | class HIDDeviceUSB implements HIDDevice {
9 |
10 | private static final String TAG = "hidapi";
11 |
12 | protected HIDDeviceManager mManager;
13 | protected UsbDevice mDevice;
14 | protected int mInterfaceIndex;
15 | protected int mInterface;
16 | protected int mDeviceId;
17 | protected UsbDeviceConnection mConnection;
18 | protected UsbEndpoint mInputEndpoint;
19 | protected UsbEndpoint mOutputEndpoint;
20 | protected InputThread mInputThread;
21 | protected boolean mRunning;
22 | protected boolean mFrozen;
23 |
24 | public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
25 | mManager = manager;
26 | mDevice = usbDevice;
27 | mInterfaceIndex = interface_index;
28 | mInterface = mDevice.getInterface(mInterfaceIndex).getId();
29 | mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
30 | mRunning = false;
31 | }
32 |
33 | public String getIdentifier() {
34 | return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
35 | }
36 |
37 | @Override
38 | public int getId() {
39 | return mDeviceId;
40 | }
41 |
42 | @Override
43 | public int getVendorId() {
44 | return mDevice.getVendorId();
45 | }
46 |
47 | @Override
48 | public int getProductId() {
49 | return mDevice.getProductId();
50 | }
51 |
52 | @Override
53 | public String getSerialNumber() {
54 | String result = null;
55 | if (Build.VERSION.SDK_INT >= 21) {
56 | result = mDevice.getSerialNumber();
57 | }
58 | if (result == null) {
59 | result = "";
60 | }
61 | return result;
62 | }
63 |
64 | @Override
65 | public int getVersion() {
66 | return 0;
67 | }
68 |
69 | @Override
70 | public String getManufacturerName() {
71 | String result = null;
72 | if (Build.VERSION.SDK_INT >= 21) {
73 | result = mDevice.getManufacturerName();
74 | }
75 | if (result == null) {
76 | result = String.format("%x", getVendorId());
77 | }
78 | return result;
79 | }
80 |
81 | @Override
82 | public String getProductName() {
83 | String result = null;
84 | if (Build.VERSION.SDK_INT >= 21) {
85 | result = mDevice.getProductName();
86 | }
87 | if (result == null) {
88 | result = String.format("%x", getProductId());
89 | }
90 | return result;
91 | }
92 |
93 | @Override
94 | public UsbDevice getDevice() {
95 | return mDevice;
96 | }
97 |
98 | public String getDeviceName() {
99 | return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
100 | }
101 |
102 | @Override
103 | public boolean open() {
104 | mConnection = mManager.getUSBManager().openDevice(mDevice);
105 | if (mConnection == null) {
106 | Log.w(TAG, "Unable to open USB device " + getDeviceName());
107 | return false;
108 | }
109 |
110 | // Force claim our interface
111 | UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
112 | if (!mConnection.claimInterface(iface, true)) {
113 | Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
114 | close();
115 | return false;
116 | }
117 |
118 | // Find the endpoints
119 | for (int j = 0; j < iface.getEndpointCount(); j++) {
120 | UsbEndpoint endpt = iface.getEndpoint(j);
121 | switch (endpt.getDirection()) {
122 | case UsbConstants.USB_DIR_IN:
123 | if (mInputEndpoint == null) {
124 | mInputEndpoint = endpt;
125 | }
126 | break;
127 | case UsbConstants.USB_DIR_OUT:
128 | if (mOutputEndpoint == null) {
129 | mOutputEndpoint = endpt;
130 | }
131 | break;
132 | }
133 | }
134 |
135 | // Make sure the required endpoints were present
136 | if (mInputEndpoint == null || mOutputEndpoint == null) {
137 | Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
138 | close();
139 | return false;
140 | }
141 |
142 | // Start listening for input
143 | mRunning = true;
144 | mInputThread = new InputThread();
145 | mInputThread.start();
146 |
147 | return true;
148 | }
149 |
150 | @Override
151 | public int sendFeatureReport(byte[] report) {
152 | int res = -1;
153 | int offset = 0;
154 | int length = report.length;
155 | boolean skipped_report_id = false;
156 | byte report_number = report[0];
157 |
158 | if (report_number == 0x0) {
159 | ++offset;
160 | --length;
161 | skipped_report_id = true;
162 | }
163 |
164 | res = mConnection.controlTransfer(
165 | UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
166 | 0x09/*HID set_report*/,
167 | (3/*HID feature*/ << 8) | report_number,
168 | mInterface,
169 | report, offset, length,
170 | 1000/*timeout millis*/);
171 |
172 | if (res < 0) {
173 | Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
174 | return -1;
175 | }
176 |
177 | if (skipped_report_id) {
178 | ++length;
179 | }
180 | return length;
181 | }
182 |
183 | @Override
184 | public int sendOutputReport(byte[] report) {
185 | int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
186 | if (r != report.length) {
187 | Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
188 | }
189 | return r;
190 | }
191 |
192 | @Override
193 | public boolean getFeatureReport(byte[] report) {
194 | int res = -1;
195 | int offset = 0;
196 | int length = report.length;
197 | boolean skipped_report_id = false;
198 | byte report_number = report[0];
199 |
200 | if (report_number == 0x0) {
201 | /* Offset the return buffer by 1, so that the report ID
202 | will remain in byte 0. */
203 | ++offset;
204 | --length;
205 | skipped_report_id = true;
206 | }
207 |
208 | res = mConnection.controlTransfer(
209 | UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
210 | 0x01/*HID get_report*/,
211 | (3/*HID feature*/ << 8) | report_number,
212 | mInterface,
213 | report, offset, length,
214 | 1000/*timeout millis*/);
215 |
216 | if (res < 0) {
217 | Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
218 | return false;
219 | }
220 |
221 | if (skipped_report_id) {
222 | ++res;
223 | ++length;
224 | }
225 |
226 | byte[] data;
227 | if (res == length) {
228 | data = report;
229 | } else {
230 | data = Arrays.copyOfRange(report, 0, res);
231 | }
232 | mManager.HIDDeviceFeatureReport(mDeviceId, data);
233 |
234 | return true;
235 | }
236 |
237 | @Override
238 | public void close() {
239 | mRunning = false;
240 | if (mInputThread != null) {
241 | while (mInputThread.isAlive()) {
242 | mInputThread.interrupt();
243 | try {
244 | mInputThread.join();
245 | } catch (InterruptedException e) {
246 | // Keep trying until we're done
247 | }
248 | }
249 | mInputThread = null;
250 | }
251 | if (mConnection != null) {
252 | UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
253 | mConnection.releaseInterface(iface);
254 | mConnection.close();
255 | mConnection = null;
256 | }
257 | }
258 |
259 | @Override
260 | public void shutdown() {
261 | close();
262 | mManager = null;
263 | }
264 |
265 | @Override
266 | public void setFrozen(boolean frozen) {
267 | mFrozen = frozen;
268 | }
269 |
270 | protected class InputThread extends Thread {
271 | @Override
272 | public void run() {
273 | int packetSize = mInputEndpoint.getMaxPacketSize();
274 | byte[] packet = new byte[packetSize];
275 | while (mRunning) {
276 | int r;
277 | try
278 | {
279 | r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
280 | }
281 | catch (Exception e)
282 | {
283 | Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
284 | break;
285 | }
286 | if (r < 0) {
287 | // Could be a timeout or an I/O error
288 | }
289 | if (r > 0) {
290 | byte[] data;
291 | if (r == packetSize) {
292 | data = packet;
293 | } else {
294 | data = Arrays.copyOfRange(packet, 0, r);
295 | }
296 |
297 | if (!mFrozen) {
298 | mManager.HIDDeviceInputReport(mDeviceId, data);
299 | }
300 | }
301 | }
302 | }
303 | }
304 | }
305 |
--------------------------------------------------------------------------------
/android/app/src/main/java/org/libsdl/app/SDL.java:
--------------------------------------------------------------------------------
1 | package org.libsdl.app;
2 |
3 | import android.content.Context;
4 |
5 | import java.lang.reflect.*;
6 |
7 | /**
8 | SDL library initialization
9 | */
10 | public class SDL {
11 |
12 | // This function should be called first and sets up the native code
13 | // so it can call into the Java classes
14 | public static void setupJNI() {
15 | SDLActivity.nativeSetupJNI();
16 | SDLAudioManager.nativeSetupJNI();
17 | SDLControllerManager.nativeSetupJNI();
18 | }
19 |
20 | // This function should be called each time the activity is started
21 | public static void initialize() {
22 | setContext(null);
23 |
24 | SDLActivity.initialize();
25 | SDLAudioManager.initialize();
26 | SDLControllerManager.initialize();
27 | }
28 |
29 | // This function stores the current activity (SDL or not)
30 | public static void setContext(Context context) {
31 | mContext = context;
32 | }
33 |
34 | public static Context getContext() {
35 | return mContext;
36 | }
37 |
38 | public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
39 |
40 | if (libraryName == null) {
41 | throw new NullPointerException("No library name provided.");
42 | }
43 |
44 | try {
45 | // Let's see if we have ReLinker available in the project. This is necessary for
46 | // some projects that have huge numbers of local libraries bundled, and thus may
47 | // trip a bug in Android's native library loader which ReLinker works around. (If
48 | // loadLibrary works properly, ReLinker will simply use the normal Android method
49 | // internally.)
50 | //
51 | // To use ReLinker, just add it as a dependency. For more information, see
52 | // https://github.com/KeepSafe/ReLinker for ReLinker's repository.
53 | //
54 | Class relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
55 | Class relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
56 | Class contextClass = mContext.getClassLoader().loadClass("android.content.Context");
57 | Class stringClass = mContext.getClassLoader().loadClass("java.lang.String");
58 |
59 | // Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if
60 | // they've changed during updates.
61 | Method forceMethod = relinkClass.getDeclaredMethod("force");
62 | Object relinkInstance = forceMethod.invoke(null);
63 | Class relinkInstanceClass = relinkInstance.getClass();
64 |
65 | // Actually load the library!
66 | Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
67 | loadMethod.invoke(relinkInstance, mContext, libraryName, null, null);
68 | }
69 | catch (final Throwable e) {
70 | // Fall back
71 | try {
72 | System.loadLibrary(libraryName);
73 | }
74 | catch (final UnsatisfiedLinkError ule) {
75 | throw ule;
76 | }
77 | catch (final SecurityException se) {
78 | throw se;
79 | }
80 | }
81 | }
82 |
83 | protected static Context mContext;
84 | }
85 |
--------------------------------------------------------------------------------
/android/app/src/main/java/org/libsdl/app/SDLAudioManager.java:
--------------------------------------------------------------------------------
1 | package org.libsdl.app;
2 |
3 | import android.media.*;
4 | import android.os.Build;
5 | import android.util.Log;
6 |
7 | public class SDLAudioManager
8 | {
9 | protected static final String TAG = "SDLAudio";
10 |
11 | protected static AudioTrack mAudioTrack;
12 | protected static AudioRecord mAudioRecord;
13 |
14 | public static void initialize() {
15 | mAudioTrack = null;
16 | mAudioRecord = null;
17 | }
18 |
19 | // Audio
20 |
21 | protected static String getAudioFormatString(int audioFormat) {
22 | switch (audioFormat) {
23 | case AudioFormat.ENCODING_PCM_8BIT:
24 | return "8-bit";
25 | case AudioFormat.ENCODING_PCM_16BIT:
26 | return "16-bit";
27 | case AudioFormat.ENCODING_PCM_FLOAT:
28 | return "float";
29 | default:
30 | return Integer.toString(audioFormat);
31 | }
32 | }
33 |
34 | protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
35 | int channelConfig;
36 | int sampleSize;
37 | int frameSize;
38 |
39 | Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", requested " + desiredFrames + " frames of " + desiredChannels + " channel " + getAudioFormatString(audioFormat) + " audio at " + sampleRate + " Hz");
40 |
41 | /* On older devices let's use known good settings */
42 | if (Build.VERSION.SDK_INT < 21) {
43 | if (desiredChannels > 2) {
44 | desiredChannels = 2;
45 | }
46 | if (sampleRate < 8000) {
47 | sampleRate = 8000;
48 | } else if (sampleRate > 48000) {
49 | sampleRate = 48000;
50 | }
51 | }
52 |
53 | if (audioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
54 | int minSDKVersion = (isCapture ? 23 : 21);
55 | if (Build.VERSION.SDK_INT < minSDKVersion) {
56 | audioFormat = AudioFormat.ENCODING_PCM_16BIT;
57 | }
58 | }
59 | switch (audioFormat)
60 | {
61 | case AudioFormat.ENCODING_PCM_8BIT:
62 | sampleSize = 1;
63 | break;
64 | case AudioFormat.ENCODING_PCM_16BIT:
65 | sampleSize = 2;
66 | break;
67 | case AudioFormat.ENCODING_PCM_FLOAT:
68 | sampleSize = 4;
69 | break;
70 | default:
71 | Log.v(TAG, "Requested format " + audioFormat + ", getting ENCODING_PCM_16BIT");
72 | audioFormat = AudioFormat.ENCODING_PCM_16BIT;
73 | sampleSize = 2;
74 | break;
75 | }
76 |
77 | if (isCapture) {
78 | switch (desiredChannels) {
79 | case 1:
80 | channelConfig = AudioFormat.CHANNEL_IN_MONO;
81 | break;
82 | case 2:
83 | channelConfig = AudioFormat.CHANNEL_IN_STEREO;
84 | break;
85 | default:
86 | Log.v(TAG, "Requested " + desiredChannels + " channels, getting stereo");
87 | desiredChannels = 2;
88 | channelConfig = AudioFormat.CHANNEL_IN_STEREO;
89 | break;
90 | }
91 | } else {
92 | switch (desiredChannels) {
93 | case 1:
94 | channelConfig = AudioFormat.CHANNEL_OUT_MONO;
95 | break;
96 | case 2:
97 | channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
98 | break;
99 | case 3:
100 | channelConfig = AudioFormat.CHANNEL_OUT_STEREO | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
101 | break;
102 | case 4:
103 | channelConfig = AudioFormat.CHANNEL_OUT_QUAD;
104 | break;
105 | case 5:
106 | channelConfig = AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
107 | break;
108 | case 6:
109 | channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
110 | break;
111 | case 7:
112 | channelConfig = AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER;
113 | break;
114 | case 8:
115 | if (Build.VERSION.SDK_INT >= 23) {
116 | channelConfig = AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
117 | } else {
118 | Log.v(TAG, "Requested " + desiredChannels + " channels, getting 5.1 surround");
119 | desiredChannels = 6;
120 | channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
121 | }
122 | break;
123 | default:
124 | Log.v(TAG, "Requested " + desiredChannels + " channels, getting stereo");
125 | desiredChannels = 2;
126 | channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
127 | break;
128 | }
129 |
130 | /*
131 | Log.v(TAG, "Speaker configuration (and order of channels):");
132 |
133 | if ((channelConfig & 0x00000004) != 0) {
134 | Log.v(TAG, " CHANNEL_OUT_FRONT_LEFT");
135 | }
136 | if ((channelConfig & 0x00000008) != 0) {
137 | Log.v(TAG, " CHANNEL_OUT_FRONT_RIGHT");
138 | }
139 | if ((channelConfig & 0x00000010) != 0) {
140 | Log.v(TAG, " CHANNEL_OUT_FRONT_CENTER");
141 | }
142 | if ((channelConfig & 0x00000020) != 0) {
143 | Log.v(TAG, " CHANNEL_OUT_LOW_FREQUENCY");
144 | }
145 | if ((channelConfig & 0x00000040) != 0) {
146 | Log.v(TAG, " CHANNEL_OUT_BACK_LEFT");
147 | }
148 | if ((channelConfig & 0x00000080) != 0) {
149 | Log.v(TAG, " CHANNEL_OUT_BACK_RIGHT");
150 | }
151 | if ((channelConfig & 0x00000100) != 0) {
152 | Log.v(TAG, " CHANNEL_OUT_FRONT_LEFT_OF_CENTER");
153 | }
154 | if ((channelConfig & 0x00000200) != 0) {
155 | Log.v(TAG, " CHANNEL_OUT_FRONT_RIGHT_OF_CENTER");
156 | }
157 | if ((channelConfig & 0x00000400) != 0) {
158 | Log.v(TAG, " CHANNEL_OUT_BACK_CENTER");
159 | }
160 | if ((channelConfig & 0x00000800) != 0) {
161 | Log.v(TAG, " CHANNEL_OUT_SIDE_LEFT");
162 | }
163 | if ((channelConfig & 0x00001000) != 0) {
164 | Log.v(TAG, " CHANNEL_OUT_SIDE_RIGHT");
165 | }
166 | */
167 | }
168 | frameSize = (sampleSize * desiredChannels);
169 |
170 | // Let the user pick a larger buffer if they really want -- but ye
171 | // gods they probably shouldn't, the minimums are horrifyingly high
172 | // latency already
173 | int minBufferSize;
174 | if (isCapture) {
175 | minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
176 | } else {
177 | minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
178 | }
179 | desiredFrames = Math.max(desiredFrames, (minBufferSize + frameSize - 1) / frameSize);
180 |
181 | int[] results = new int[4];
182 |
183 | if (isCapture) {
184 | if (mAudioRecord == null) {
185 | mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
186 | channelConfig, audioFormat, desiredFrames * frameSize);
187 |
188 | // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
189 | if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
190 | Log.e(TAG, "Failed during initialization of AudioRecord");
191 | mAudioRecord.release();
192 | mAudioRecord = null;
193 | return null;
194 | }
195 |
196 | mAudioRecord.startRecording();
197 | }
198 |
199 | results[0] = mAudioRecord.getSampleRate();
200 | results[1] = mAudioRecord.getAudioFormat();
201 | results[2] = mAudioRecord.getChannelCount();
202 | results[3] = desiredFrames;
203 |
204 | } else {
205 | if (mAudioTrack == null) {
206 | mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
207 |
208 | // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
209 | // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
210 | // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
211 | if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
212 | /* Try again, with safer values */
213 |
214 | Log.e(TAG, "Failed during initialization of Audio Track");
215 | mAudioTrack.release();
216 | mAudioTrack = null;
217 | return null;
218 | }
219 |
220 | mAudioTrack.play();
221 | }
222 |
223 | results[0] = mAudioTrack.getSampleRate();
224 | results[1] = mAudioTrack.getAudioFormat();
225 | results[2] = mAudioTrack.getChannelCount();
226 | results[3] = desiredFrames;
227 | }
228 |
229 | Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", got " + results[3] + " frames of " + results[2] + " channel " + getAudioFormatString(results[1]) + " audio at " + results[0] + " Hz");
230 |
231 | return results;
232 | }
233 |
234 | /**
235 | * This method is called by SDL using JNI.
236 | */
237 | public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
238 | return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames);
239 | }
240 |
241 | /**
242 | * This method is called by SDL using JNI.
243 | */
244 | public static void audioWriteFloatBuffer(float[] buffer) {
245 | if (mAudioTrack == null) {
246 | Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
247 | return;
248 | }
249 |
250 | for (int i = 0; i < buffer.length;) {
251 | int result = mAudioTrack.write(buffer, i, buffer.length - i, AudioTrack.WRITE_BLOCKING);
252 | if (result > 0) {
253 | i += result;
254 | } else if (result == 0) {
255 | try {
256 | Thread.sleep(1);
257 | } catch(InterruptedException e) {
258 | // Nom nom
259 | }
260 | } else {
261 | Log.w(TAG, "SDL audio: error return from write(float)");
262 | return;
263 | }
264 | }
265 | }
266 |
267 | /**
268 | * This method is called by SDL using JNI.
269 | */
270 | public static void audioWriteShortBuffer(short[] buffer) {
271 | if (mAudioTrack == null) {
272 | Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
273 | return;
274 | }
275 |
276 | for (int i = 0; i < buffer.length;) {
277 | int result = mAudioTrack.write(buffer, i, buffer.length - i);
278 | if (result > 0) {
279 | i += result;
280 | } else if (result == 0) {
281 | try {
282 | Thread.sleep(1);
283 | } catch(InterruptedException e) {
284 | // Nom nom
285 | }
286 | } else {
287 | Log.w(TAG, "SDL audio: error return from write(short)");
288 | return;
289 | }
290 | }
291 | }
292 |
293 | /**
294 | * This method is called by SDL using JNI.
295 | */
296 | public static void audioWriteByteBuffer(byte[] buffer) {
297 | if (mAudioTrack == null) {
298 | Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
299 | return;
300 | }
301 |
302 | for (int i = 0; i < buffer.length; ) {
303 | int result = mAudioTrack.write(buffer, i, buffer.length - i);
304 | if (result > 0) {
305 | i += result;
306 | } else if (result == 0) {
307 | try {
308 | Thread.sleep(1);
309 | } catch(InterruptedException e) {
310 | // Nom nom
311 | }
312 | } else {
313 | Log.w(TAG, "SDL audio: error return from write(byte)");
314 | return;
315 | }
316 | }
317 | }
318 |
319 | /**
320 | * This method is called by SDL using JNI.
321 | */
322 | public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
323 | return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames);
324 | }
325 |
326 | /** This method is called by SDL using JNI. */
327 | public static int captureReadFloatBuffer(float[] buffer, boolean blocking) {
328 | return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
329 | }
330 |
331 | /** This method is called by SDL using JNI. */
332 | public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
333 | if (Build.VERSION.SDK_INT < 23) {
334 | return mAudioRecord.read(buffer, 0, buffer.length);
335 | } else {
336 | return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
337 | }
338 | }
339 |
340 | /** This method is called by SDL using JNI. */
341 | public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
342 | if (Build.VERSION.SDK_INT < 23) {
343 | return mAudioRecord.read(buffer, 0, buffer.length);
344 | } else {
345 | return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
346 | }
347 | }
348 |
349 | /** This method is called by SDL using JNI. */
350 | public static void audioClose() {
351 | if (mAudioTrack != null) {
352 | mAudioTrack.stop();
353 | mAudioTrack.release();
354 | mAudioTrack = null;
355 | }
356 | }
357 |
358 | /** This method is called by SDL using JNI. */
359 | public static void captureClose() {
360 | if (mAudioRecord != null) {
361 | mAudioRecord.stop();
362 | mAudioRecord.release();
363 | mAudioRecord = null;
364 | }
365 | }
366 |
367 | /** This method is called by SDL using JNI. */
368 | public static void audioSetThreadPriority(boolean iscapture, int device_id) {
369 | try {
370 |
371 | /* Set thread name */
372 | if (iscapture) {
373 | Thread.currentThread().setName("SDLAudioC" + device_id);
374 | } else {
375 | Thread.currentThread().setName("SDLAudioP" + device_id);
376 | }
377 |
378 | /* Set thread priority */
379 | android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
380 |
381 | } catch (Exception e) {
382 | Log.v(TAG, "modify thread properties failed " + e.toString());
383 | }
384 | }
385 |
386 | public static native int nativeSetupJNI();
387 | }
388 |
--------------------------------------------------------------------------------
/android/app/src/main/java/org/tildearrow/soundtracker/soundtrackerActivity.java:
--------------------------------------------------------------------------------
1 | package org.tildearrow.soundtracker;
2 |
3 | import org.libsdl.app.SDLActivity;
4 |
5 | public class soundtrackerActivity extends SDLActivity
6 | {
7 | }
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | soundtracker
3 |
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.2.0'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | google()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Oct 23 13:51:26 PDT 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/igfd/ImGuiFileDialogConfig.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // uncomment and modify defines under for customize ImGuiFileDialog
4 |
5 | //this options need c++17
6 | //#define USE_STD_FILESYSTEM
7 |
8 | //#define MAX_FILE_DIALOG_NAME_BUFFER 1024
9 | //#define MAX_PATH_BUFFER_SIZE 1024
10 |
11 | //#define USE_THUMBNAILS
12 | //the thumbnail generation use the stb_image and stb_resize lib who need to define the implementation
13 | //btw if you already use them in your app, you can have compiler error due to "implemntation found in double"
14 | //so uncomment these line for prevent the creation of implementation of these libs again
15 | //#define DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION
16 | //#define DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION
17 | //#define IMGUI_RADIO_BUTTON RadioButton
18 | //#define DisplayMode_ThumbailsList_ImageHeight 32.0f
19 | //#define tableHeaderFileThumbnailsString "Thumbnails"
20 | //#define DisplayMode_FilesList_ButtonString "FL"
21 | //#define DisplayMode_FilesList_ButtonHelp "File List"
22 | //#define DisplayMode_ThumbailsList_ButtonString "TL"
23 | //#define DisplayMode_ThumbailsList_ButtonHelp "Thumbnails List"
24 | // todo
25 | //#define DisplayMode_ThumbailsGrid_ButtonString "TG"
26 | //#define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid"
27 |
28 |
29 | //#define USE_EXPLORATION_BY_KEYS
30 | // this mapping by default is for GLFW but you can use another
31 | //#include
32 | // Up key for explore to the top
33 | //#define IGFD_KEY_UP GLFW_KEY_UP
34 | // Down key for explore to the bottom
35 | //#define IGFD_KEY_DOWN GLFW_KEY_DOWN
36 | // Enter key for open directory
37 | //#define IGFD_KEY_ENTER GLFW_KEY_ENTER
38 | // BackSpace for comming back to the last directory
39 | //#define IGFD_KEY_BACKSPACE GLFW_KEY_BACKSPACE
40 |
41 | // by ex you can quit the dialog by pressing the key excape
42 | //#define USE_DIALOG_EXIT_WITH_KEY
43 | //#define IGFD_EXIT_KEY GLFW_KEY_ESCAPE
44 |
45 | // widget
46 | // filter combobox width
47 | //#define FILTER_COMBO_WIDTH 120.0f
48 | // button widget use for compose path
49 | //#define IMGUI_PATH_BUTTON ImGui::Button
50 | // standard button
51 | //#define IMGUI_BUTTON ImGui::Button
52 |
53 | // locales string
54 | //#define createDirButtonString "+"
55 | //#define okButtonString " OK"
56 | //#define cancelButtonString " Cancel"
57 | //#define resetButtonString "R"
58 | //#define drivesButtonString "Drives"
59 | //#define editPathButtonString "E"
60 | //#define searchString "Search"
61 | //#define dirEntryString "[DIR] "
62 | //#define linkEntryString "[LINK] "
63 | //#define fileEntryString "[FILE] "
64 | //#define fileNameString "File Name : "
65 | //#define dirNameString "Directory Path :"
66 | //#define buttonResetSearchString "Reset search"
67 | //#define buttonDriveString "Drives"
68 | //#define buttonEditPathString "Edit path\nYou can also right click on path buttons"
69 | //#define buttonResetPathString "Reset to current directory"
70 | //#define buttonCreateDirString "Create Directory"
71 | //#define OverWriteDialogTitleString "The file Already Exist !"
72 | //#define OverWriteDialogMessageString "Would you like to OverWrite it ?"
73 | //#define OverWriteDialogConfirmButtonString "Confirm"
74 | //#define OverWriteDialogCancelButtonString "Cancel"
75 |
76 | // DateTimeFormat
77 | // see strftime functionin for customize
78 | // "%Y/%m/%d %H:%M" give 2021:01:22 11:47
79 | // "%Y/%m/%d %i:%M%p" give 2021:01:22 11:45PM
80 | //#define DateTimeFormat "%Y/%m/%d %i:%M%p"
81 |
82 | // theses icons will appear in table headers
83 | //#define USE_CUSTOM_SORTING_ICON
84 | //#define tableHeaderAscendingIcon "A|"
85 | //#define tableHeaderDescendingIcon "D|"
86 | //#define tableHeaderFileNameString " File name"
87 | //#define tableHeaderFileTypeString " Type"
88 | //#define tableHeaderFileSizeString " Size"
89 | //#define tableHeaderFileDateTimeString " Date"
90 |
91 | //#define USE_BOOKMARK
92 | //#define bookmarkPaneWith 150.0f
93 | //#define IMGUI_TOGGLE_BUTTON ToggleButton
94 | //#define bookmarksButtonString "Bookmark"
95 | //#define bookmarksButtonHelpString "Bookmark"
96 | //#define addBookmarkButtonString "+"
97 | //#define removeBookmarkButtonString "-"
98 |
--------------------------------------------------------------------------------
/igfd/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2020 Stephane Cuillerdier (aka Aiekick)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/igfd/dirent/ChangeLog:
--------------------------------------------------------------------------------
1 | 2018-05-08 Toni Rönkkö
2 |
3 | * Version 1.23.2: fixes bad scandir prototype.
4 |
5 | 2017-08-27 Toni Rönkkö
6 |
7 | * Version 1.23: support readdir_r and scandir functions.
8 |
9 | 2017-07-18 Toni Rönkkö
10 |
11 | * Created release branches v1.22 and v1.21 to Git. Published version
12 | 1.22 at softagalleria.net.
13 |
14 | 2016-09-11 Toni Rönkkö
15 |
16 | * Version 1.22: added support for CMake. Thanks to Paul Fultz II.
17 |
18 | 2014-09-25 Toni Rönkkö
19 |
20 | * Version 1.21: compiles correctly under Open Watcom. Thanks to
21 | Virgil Banowetz for a patch!
22 |
23 | 2014-04-07 Toni Rönkkö
24 |
25 | * Version 1.20.1: the zip file from the previous version did not open
26 | correctly with Microsoft's compressed folders. Thanks to Alexandre
27 | for info!
28 |
29 | 2014-03-17 Toni Ronkko
30 |
31 | * Version 1.20: dirent.h compiles correctly in 64-bit architecture.
32 | Thanks to Aaron Simmons!
33 |
34 | 2014-03-03 Toni Ronkko
35 |
36 | * Version 1.13.2: define DT_LNK for compatibility with Unix
37 | programs. Thanks to Joel Bruick for suggestion!
38 |
39 | 2013-01-27 Toni Ronkko
40 |
41 | * Version 1.13.1: patch from Edward Berner fixes set_errno() on
42 | Windows NT 4.0.
43 |
44 | * Revised wcstombs() and mbstowcs() wrappers to make sure that they do
45 | not write past their target string.
46 |
47 | * PATH_MAX from windows.h includes zero terminator so there is no
48 | need to add one extra byte to variables and structures.
49 |
50 | 2012-12-12 Toni Ronkko
51 |
52 | * Version 1.13: use the traditional 8+3 file naming scheme if a file
53 | name cannot be represented in the default ANSI code page. Now
54 | compiles again with MSVC 6.0. Thanks to Konstantin Khomoutov for
55 | testing.
56 |
57 | 2012-10-01 Toni Ronkko
58 |
59 | * Version 1.12.1: renamed wide-character DIR structure _wDIR to
60 | _WDIR (with capital W) in order to maintain compatibility with MingW.
61 |
62 | 2012-09-30 Toni Ronkko
63 |
64 | * Version 1.12: define PATH_MAX and NAME_MAX. Added wide-character
65 | variants _wDIR, _wdirent, _wopendir(), _wreaddir(), _wclosedir() and
66 | _wrewinddir(). Thanks to Edgar Buerkle and Jan Nijtmans for ideas
67 | and code.
68 |
69 | * Now avoiding windows.h. This allows dirent.h to be integrated
70 | more easily into programs using winsock. Thanks to Fernando
71 | Azaldegui.
72 |
73 | 2011-03-15 Toni Ronkko
74 |
75 | * Version 1.11: defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
76 |
77 | 2010-08-11 Toni Ronkko
78 |
79 | * Version 1.10: added d_type and d_namlen fields to dirent structure.
80 | The former is especially useful for determining whether directory
81 | entry represents a file or a directory. For more information, see
82 | http://www.delorie.com/gnu/docs/glibc/libc_270.html
83 |
84 | * Improved conformance to the standards. For example, errno is now
85 | set properly on failure and assert() is never used. Thanks to Peter
86 | Brockam for suggestions.
87 |
88 | * Fixed a bug in rewinddir(): when using relative directory names,
89 | change of working directory no longer causes rewinddir() to fail.
90 |
91 | 2009-12-15 John Cunningham
92 |
93 | * Version 1.9: added rewinddir member function
94 |
95 | 2008-01-18 Toni Ronkko
96 |
97 | * Version 1.8: Using FindFirstFileA and WIN32_FIND_DATAA to avoid
98 | converting string between multi-byte and unicode representations.
99 | This makes the code simpler and also allows the code to be compiled
100 | under MingW. Thanks to Azriel Fasten for the suggestion.
101 |
102 | 2007-03-04 Toni Ronkko
103 |
104 | * Bug fix: due to the strncpy_s() function this file only compiled in
105 | Visual Studio 2005. Using the new string functions only when the
106 | compiler version allows.
107 |
108 | 2006-11-02 Toni Ronkko
109 |
110 | * Major update: removed support for Watcom C, MS-DOS and Turbo C to
111 | simplify the file, updated the code to compile cleanly on Visual
112 | Studio 2005 with both unicode and multi-byte character strings,
113 | removed rewinddir() as it had a bug.
114 |
115 | 2006-08-20 Toni Ronkko
116 |
117 | * Removed all remarks about MSVC 1.0, which is antiqued now.
118 | Simplified comments by removing SGML tags.
119 |
120 | 2002-05-14 Toni Ronkko
121 |
122 | * Embedded the function definitions directly to the header so that no
123 | source modules need to be included in the Visual Studio project.
124 | Removed all the dependencies to other projects so that this header
125 | file can be used independently.
126 |
127 | 1998-05-28 Toni Ronkko
128 |
129 | * First version.
130 |
--------------------------------------------------------------------------------
/igfd/dirent/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 1998-2019 Toni Ronkko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/igfd/dirent/README.md:
--------------------------------------------------------------------------------
1 | # Dirent
2 | Dirent is a C/C++ programming interface that allows programmers to retrieve
3 | information about files and directories under Linux/UNIX. This project
4 | provides Linux compatible Dirent interface for Microsoft Windows.
5 |
6 |
7 | # Installation
8 |
9 | Download the latest Dirent installation package from
10 | [GitHub](https://github.com/tronkko/dirent/releases) and
11 | unpack the installation file with 7-zip, for example. The installation
12 | package contains dirent.h file as well as a few example programs and
13 | tests.
14 |
15 |
16 | ## Install Dirent for All Programs
17 |
18 | To make dirent.h available for all C/C++ programs, simply copy the
19 | ``include/dirent.h`` file to the system include directory. System include
20 | directory contains header files such as assert.h and windows.h. In Visual
21 | Studio 2008, for example, the system include may be found at
22 | ``C:\Program Files\Microsoft Visual Studio 9.0\VC\include``.
23 |
24 | Everything you need is included in the single dirent.h file, and you can
25 | start using Dirent immediately -- there is no need to add files to your
26 | Visual Studio project.
27 |
28 |
29 | ## Embed Dirent into Your Own Project
30 |
31 | If you wish to distribute dirent.h alongside with your own source code, then
32 | copy ``include/dirent.h`` file to a new sub-directory within your project and
33 | add that directory to include path on Windows while omitting the directory
34 | under Linux/UNIX. This allows your project to be compiled against native
35 | dirent.h on Linux/UNIX while substituting the functionality on Microsoft
36 | Windows.
37 |
38 |
39 | ## Examples
40 |
41 | The installation package contains four example programs:
42 |
43 | Program | Purpose
44 | -------- | -----------------------------------------------------------------
45 | ls | List files in a directory, e.g. ls "c:\Program Files"
46 | find | Find files in subdirectories, e.g. find "c:\Program Files\CMake"
47 | updatedb | Build database of files in a drive, e.g. updatedb c:\
48 | locate | Locate a file from database, e.g. locate notepad.exe
49 |
50 | To build the example programs, first install [CMake](https://cmake.org/).
51 | Then, with CMake installed, open command prompt and create a temporary
52 | directory ``c:\temp\dirent`` for the build files as
53 |
54 | ```
55 | c:\
56 | mkdir temp
57 | mkdir temp\dirent
58 | cd temp\dirent
59 | ```
60 |
61 | Generate build files as
62 |
63 | ```
64 | cmake d:\dirent
65 | ```
66 |
67 | where ``d:\dirent`` is the root directory of the Dirent package (containing
68 | this README.md and LICENSE file).
69 |
70 | Once CMake is finished, open Visual Studio, load the generated dirent.sln file
71 | from the build directory and build the solution. Once the build completes, run
72 | the example programs from the command prompt as
73 |
74 | ```
75 | cd Debug
76 | ls .
77 | find .
78 | updatedb c:\
79 | locate cmd.exe
80 | ```
81 |
82 |
83 | # Copying
84 |
85 | Dirent may be freely distributed under the MIT license. See the
86 | [LICENSE](LICENSE) file for details.
87 |
88 |
89 | # Alternatives to Dirent
90 |
91 | I ported Dirent to Microsoft Windows in 1998 when only a few alternatives
92 | were available. However, the situation has changed since then and nowadays
93 | both [Cygwin](http://www.cygwin.com) and [MingW](http://www.mingw.org)
94 | allow you to compile a great number of UNIX programs in Microsoft Windows.
95 | They both provide a full dirent API as well as many other UNIX APIs. MingW
96 | can even be used for commercial applications!
97 |
--------------------------------------------------------------------------------
/igfd/stb/LICENSE:
--------------------------------------------------------------------------------
1 | This software is available under 2 licenses -- choose whichever you prefer.
2 | ------------------------------------------------------------------------------
3 | ALTERNATIVE A - MIT License
4 | Copyright (c) 2017 Sean Barrett
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | so, subject to the following conditions:
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ------------------------------------------------------------------------------
21 | ALTERNATIVE B - Public Domain (www.unlicense.org)
22 | This is free and unencumbered software released into the public domain.
23 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
24 | software, either in source code form or as a compiled binary, for any purpose,
25 | commercial or non-commercial, and by any means.
26 | In jurisdictions that recognize copyright laws, the author or authors of this
27 | software dedicate any and all copyright interest in the software to the public
28 | domain. We make this dedication for the benefit of the public at large and to
29 | the detriment of our heirs and successors. We intend this dedication to be an
30 | overt act of relinquishment in perpetuity of all present and future rights to
31 | this software under copyright law.
32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
36 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 |
--------------------------------------------------------------------------------
/igfd/stb/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | stb
4 | ===
5 |
6 | single-file public domain (or MIT licensed) libraries for C/C++
7 |
8 | Noteworthy:
9 |
10 | * image loader: [stb_image.h](stb_image.h)
11 | * image writer: [stb_image_write.h](stb_image_write.h)
12 | * image resizer: [stb_image_resize.h](stb_image_resize.h)
13 | * font text rasterizer: [stb_truetype.h](stb_truetype.h)
14 | * typesafe containers: [stb_ds.h](stb_ds.h)
15 |
16 | Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
17 | by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
18 |
19 |
20 |
21 | library | lastest version | category | LoC | description
22 | --------------------- | ---- | -------- | --- | --------------------------------
23 | **[stb_vorbis.c](stb_vorbis.c)** | 1.20 | audio | 5563 | decode ogg vorbis files from file/memory to float/16-bit signed output
24 | **[stb_image.h](stb_image.h)** | 2.26 | graphics | 7762 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
25 | **[stb_truetype.h](stb_truetype.h)** | 1.24 | graphics | 5011 | parse, decode, and rasterize characters from truetype fonts
26 | **[stb_image_write.h](stb_image_write.h)** | 1.15 | graphics | 1690 | image writing to disk: PNG, TGA, BMP
27 | **[stb_image_resize.h](stb_image_resize.h)** | 0.96 | graphics | 2631 | resize images larger/smaller with good quality
28 | **[stb_rect_pack.h](stb_rect_pack.h)** | 1.00 | graphics | 628 | simple 2D rectangle packer with decent quality
29 | **[stb_ds.h](stb_ds.h)** | 0.65 | utility | 1880 | typesafe dynamic array and hash tables for C, will compile in C++
30 | **[stb_sprintf.h](stb_sprintf.h)** | 1.09 | utility | 1879 | fast sprintf, snprintf for C/C++
31 | **[stretchy_buffer.h](stretchy_buffer.h)** | 1.04 | utility | 263 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
32 | **[stb_textedit.h](stb_textedit.h)** | 1.13 | user interface | 1404 | guts of a text editor for games etc implementing them from scratch
33 | **[stb_voxel_render.h](stb_voxel_render.h)** | 0.89 | 3D graphics | 3807 | Minecraft-esque voxel rendering "engine" with many more features
34 | **[stb_dxt.h](stb_dxt.h)** | 1.10 | 3D graphics | 753 | Fabian "ryg" Giesen's real-time DXT compressor
35 | **[stb_perlin.h](stb_perlin.h)** | 0.5 | 3D graphics | 428 | revised Perlin noise (3D input, 1D output)
36 | **[stb_easy_font.h](stb_easy_font.h)** | 1.1 | 3D graphics | 305 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
37 | **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.41 | game dev | 4161 | embeddable tilemap editor
38 | **[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.7 | game dev | 1221 | herringbone Wang tile map generator
39 | **[stb_c_lexer.h](stb_c_lexer.h)** | 0.11 | parsing | 966 | simplify writing parsers for C-like languages
40 | **[stb_divide.h](stb_divide.h)** | 0.93 | math | 430 | more useful 32-bit modulus e.g. "euclidean divide"
41 | **[stb_connected_comp...](stb_connected_components.h)** | 0.96 | misc | 1049 | incrementally compute reachability on grids
42 | **[stb.h](stb.h)** | 2.37 | misc | 14454 | helper functions for C, mostly redundant in C++; basically author's personal stuff
43 | **[stb_leakcheck.h](stb_leakcheck.h)** | 0.6 | misc | 194 | quick-and-dirty malloc/free leak-checking
44 | **[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL
45 |
46 | Total libraries: 22
47 | Total lines of C code: 56774
48 |
49 |
50 | FAQ
51 | ---
52 |
53 | #### What's the license?
54 |
55 | These libraries are in the public domain. You can do anything you
56 | want with them. You have no legal obligation
57 | to do anything else, although I appreciate attribution.
58 |
59 | They are also licensed under the MIT open source license, if you have lawyers
60 | who are unhappy with public domain. Every source file includes an explicit
61 | dual-license for you to choose from.
62 |
63 | #### Are there other single-file public-domain/open source libraries with minimal dependencies out there?
64 |
65 | [Yes.](https://github.com/nothings/single_file_libs)
66 |
67 | #### If I wrap an stb library in a new library, does the new library have to be public domain/MIT?
68 |
69 | No, because it's public domain you can freely relicense it to whatever license your new
70 | library wants to be.
71 |
72 | #### What's the deal with SSE support in GCC-based compilers?
73 |
74 | stb_image will either use SSE2 (if you compile with -msse2) or
75 | will not use any SIMD at all, rather than trying to detect the
76 | processor at runtime and handle it correctly. As I understand it,
77 | the approved path in GCC for runtime-detection require
78 | you to use multiple source files, one for each CPU configuration.
79 | Because stb_image is a header-file library that compiles in only
80 | one source file, there's no approved way to build both an
81 | SSE-enabled and a non-SSE-enabled variation.
82 |
83 | While we've tried to work around it, we've had multiple issues over
84 | the years due to specific versions of gcc breaking what we're doing,
85 | so we've given up on it. See https://github.com/nothings/stb/issues/280
86 | and https://github.com/nothings/stb/issues/410 for examples.
87 |
88 | #### Some of these libraries seem redundant to existing open source libraries. Are they better somehow?
89 |
90 | Generally they're only better in that they're easier to integrate,
91 | easier to use, and easier to release (single file; good API; no
92 | attribution requirement). They may be less featureful, slower,
93 | and/or use more memory. If you're already using an equivalent
94 | library, there's probably no good reason to switch.
95 |
96 | #### Can I link directly to the table of stb libraries?
97 |
98 | You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list.
99 |
100 | #### Why do you list "lines of code"? It's a terrible metric.
101 |
102 | Just to give you some idea of the internal complexity of the library,
103 | to help you manage your expectations, or to let you know what you're
104 | getting into. While not all the libraries are written in the same
105 | style, they're certainly similar styles, and so comparisons between
106 | the libraries are probably still meaningful.
107 |
108 | Note though that the lines do include both the implementation, the
109 | part that corresponds to a header file, and the documentation.
110 |
111 | #### Why single-file headers?
112 |
113 | Windows doesn't have standard directories where libraries
114 | live. That makes deploying libraries in Windows a lot more
115 | painful than open source developers on Unix-derivates generally
116 | realize. (It also makes library dependencies a lot worse in Windows.)
117 |
118 | There's also a common problem in Windows where a library was built
119 | against a different version of the runtime library, which causes
120 | link conflicts and confusion. Shipping the libs as headers means
121 | you normally just compile them straight into your project without
122 | making libraries, thus sidestepping that problem.
123 |
124 | Making them a single file makes it very easy to just
125 | drop them into a project that needs them. (Of course you can
126 | still put them in a proper shared library tree if you want.)
127 |
128 | Why not two files, one a header and one an implementation?
129 | The difference between 10 files and 9 files is not a big deal,
130 | but the difference between 2 files and 1 file is a big deal.
131 | You don't need to zip or tar the files up, you don't have to
132 | remember to attach *two* files, etc.
133 |
134 | #### Why "stb"? Is this something to do with Set-Top Boxes?
135 |
136 | No, they are just the initials for my name, Sean T. Barrett.
137 | This was not chosen out of egomania, but as a moderately sane
138 | way of namespacing the filenames and source function names.
139 |
140 | #### Will you add more image types to stb_image.h?
141 |
142 | No. As stb_image use has grown, it has become more important
143 | for us to focus on security of the codebase. Adding new image
144 | formats increases the amount of code we need to secure, so it
145 | is no longer worth adding new formats.
146 |
147 | #### Do you have any advice on how to create my own single-file library?
148 |
149 | Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
150 |
151 | #### Why public domain?
152 |
153 | I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons.
154 | Some of them are listed here:
155 | https://github.com/nothings/stb/blob/master/docs/why_public_domain.md
156 |
157 | #### Why C?
158 |
159 | Primarily, because I use C, not C++. But it does also make it easier
160 | for other people to use them from other languages.
161 |
162 | #### Why not C99? stdint.h, declare-anywhere, etc.
163 |
164 | I still use MSVC 6 (1998) as my IDE because it has better human factors
165 | for me than later versions of MSVC.
166 |
--------------------------------------------------------------------------------
/papers/format.md:
--------------------------------------------------------------------------------
1 | ─ │ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼
2 | # ---TRACKER'S FILE FORMAT SPECIFICATION---
3 |
4 | this document should help you read the soundtracker file format.
5 |
6 | ## Header, 384 bytes
7 | ---- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -A- -B- -C- -D- -E- -F-
8 | ┌───┬───┬───┬───┬───┬───┬───┬───┬───────┬───┬───┬───┬───┬───┬───┐
9 | 00│ T │ R │ A │ C │ K │ 8 │ B │ T │Version│Ins│Pat│Ord│Spd│Seq│Tmp│
10 | ├───┴───┴───┴───┴───┴───┴───┴───┴───────┴───┴───┴───┴───┴───┴───┤
11 | 10│ song name, 32 chars max, padded with 0x00s │
12 | ├───┬───┬───────┬───┬───┬───────────────┬───────────────┬───┬───┤
13 | 30│DFM│#CH│ flags │gvl│gpn│ PCM pointer │Comment pointer│DFA│Len│
14 | ├───┴───┴───────┴───┴───┴───────────────┴───────────────┴───┴───┤
15 | 40│ default volume per channel, 32 bytes │
16 | ├───────────────────────────────────────────────────────────────┤
17 | 60│ default panning per channel, 32 bytes │
18 | ├───────────────────────────────────────────────────────────────┤
19 | 80│ order list, 256 bytes │
20 | ├───────────────────────────────────────────────────────────────┤
21 | 180│ pointers to instruments, 4 bytes per pointer │
22 | ├───────────────────────────────────────────────────────────────┤
23 | xxxx│ pointers to macros or sequence tables (pre-r152), 4 bytes/ptr │
24 | ├───────────────────────────────────────────────────────────────┤
25 | xxxx│ pointers to patterns, 4 bytes per pointer │
26 | └───────────────────────────────────────────────────────────────┘
27 | Note: DFA: detune
28 | Flags: bit 0: NTSC
29 | bit 1: NTSC50
30 | bit 2: noise compatibility mode
31 | if set then noise frequency is divided by 4.
32 |
33 | ## Macros, new format
34 | read macros like this:
35 |
36 | 1. read the macro length (4 bytes).
37 | 2. read the "jump on release" position (4 bytes).
38 | * if this is -1, then it is "don't jump".
39 | 3. read the macro intended use (1 byte):
40 | - 0: generic
41 | - 1: shape
42 | - 2: pitch
43 | - 3: panning
44 | - 4: volume sweep
45 | - 5: other sweep
46 | 3. skip 7 bytes (reserved section).
47 | 4. read the type. then switch based on it:
48 | - 0: end of macro.
49 | - 1: set. read four bytes for value.
50 | - 2: wait. read four bytes for length.
51 | - 3: wait for release.
52 | - 4: loop. read the position (4 bytes).
53 | - 5: loop until release. read the position (4 bytes).
54 | - 6: add. read four bytes for value.
55 | - 7: subtract. read four bytes for value.
56 | * if bit 7 is set, then it means end of tick (ignored on wait).
57 |
58 | ## Sequence tables, legacy (pre-r152) format, 2048 bytes each
59 | ---- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -A- -B- -C- -D- -E- -F-
60 | ┌───────────────────────────────────────────────────────────────┐
61 | 00│ main sequence, 253 bytes │
62 | ├───────────────────────────────────────────────────┬───┬───┬───┤
63 | F0│ │Len│Lps│Rps│
64 | └───────────────────────────────────────────────────┴───┴───┴───┘
65 |
66 | read 8 times to get the tables in this order:
67 | - 0: volume
68 | - 1: cutoff
69 | - 2: resonance
70 | - 3: duty
71 | - 4: shape
72 | - 5: pitch
73 | - 6: fine pitch
74 | - 7: panning
75 |
76 | ## Instruments, new format, 96 bytes each
77 | ---- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -A- -B- -C- -D- -E- -F-
78 | ┌───────────────────────────────────────────────────────────────┐
79 | 00│ instrument name, 32 bytes, padded with 0x00s │
80 | ├───┬───┬───────┬───────┬───────┬───────┬───┬───┬───┬───┬───┬───┤
81 | 20│Ins│???│volumeM│cutoffM│resonaM│pitchM │???│Off│FPt│FPR│DFM│LFO│
82 | ├───┼───┼───────┼───────┼───┬───┴───┬───┴───┼───┼───┴───┼───┼───┤
83 | 30│Vol│Pit│PCMSlen│FilterH│Res│FTm│PCMSptr│PCMloop│Version│flg│RMF│
84 | ├───┴───┼───────┼───────┼───┴───┬───┴───┬───┴───┼───────┼───┴───┤
85 | 40│finepiM│shapeM │ dutyM │ panM │filterM│volswpM│frqswpM│cutswpM│
86 | ├───────┼───────┴───────┴───────┴───────┴───────┴───────┴───────┤
87 | 50│pcmposM│ r e s e r v e d │
88 | └───────┴───────────────────────────────────────────────────────┘
89 |
90 | NOTE: Instrument files start with a header which is 8 bytes long and reads "TRACKINS".
91 | Also, instrument files don't require the envelope IDs as they're saved along with the file.
92 | NOTE: If (DFM&8) then it's a PCM instrument.
93 | If (DFM&16) then enable ring modulation and LFO sets the ring modulation frequency.
94 | RMF sets the ring modulator flags:
95 | (RMF&7): waveform
96 | the rest of bits: duty
97 | Also, (DFM&128) will be used for the MSB of PCMSptr and (DFM&64) the MSB of PCMloop.
98 | Also, (DFM&32) enables looping.
99 | PCm: PCM multiplier. Max value is 127.
100 | PCm&128: MSB of length
101 | flg: other flags:
102 | bit 0: reset oscillator on new note
103 | bit 1: MSB of duty
104 | bit 2: reset filter on new note
105 | bit 3: reset RM oscillator on new note
106 | bit 4: sync modulation
107 | bit 5: PCM loop enabled
108 | bit 6-7: auto-cut
109 |
110 | ## Instruments, legacy (pre-r152) format, 64 bytes each
111 | ---- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -A- -B- -C- -D- -E- -F-
112 | ┌───────────────────────────────────────────────────────────────┐
113 | 00│ instrument name, 32 bytes, padded with 0x00s │
114 | ├───┬───┬───┬───────────────────────────────┬───┬───┬───┬───┬───┤
115 | 20│Ins│PCm│Env│vol cut res dty shp pit hpi pan│Off│FPt│FPR│DFM│LFO│
116 | ├───┼───┼───┴───┬───────┬───┬───────┬───────┼───┼───┴───┼───┼───┤
117 | 30│Vol│Pit│PCMSlen│FilterH│Res│PCMSptr│PCMloop│FTm│Version│flg│RMF│
118 | └───┴───┴───────┴───────┴───┴───────┴───────┴───┴───────┴───┴───┘
119 |
120 | NOTE: Instrument files start with a header which is 8 bytes long and reads "TRACKINS".
121 | Also, instrument files don't require the envelope IDs as they're saved along with the file.
122 | NOTE: If (DFM&8) then it's a PCM instrument.
123 | If (DFM&16) then enable ring modulation and LFO sets the ring modulation frequency.
124 | RMF sets the ring modulator flags:
125 | (RMF&7): waveform
126 | the rest of bits: duty
127 | Also, (DFM&128) will be used for the MSB of PCMSptr and (DFM&64) the MSB of PCMloop.
128 | Also, (DFM&32) enables looping.
129 | PCm: PCM multiplier. Max value is 127.
130 | PCm&128: MSB of length
131 | flg: other flags:
132 | bit 0: reset oscillator on new note
133 | bit 1: MSB of duty
134 | bit 2: reset filter on new note
135 | bit 3: reset RM oscillator on new note
136 | bit 4: sync modulation
137 | bit 5: PCM loop enabled
138 | bit 6-7: auto-cut
139 |
140 | ## Patterns, 16 byte header
141 | ---- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -A- -B- -C- -D- -E- -F-
142 | ┌───────────────────────────────────────────────────────────────┐
143 | 00│PID│ Length |Siz| Reserved, 11 bytes |
144 | ├───────────────────────────────────────────────────────────────┤
145 | 10│ Pattern data │
146 | └───────────────────────────────────────────────────────────────┘
147 |
148 | Pattern data is organized like this:
149 | NOTE INST VOLU FXID FXVL
150 | NOTE: channel's note, high nibble is octave, low nibble:
151 | -0: no note
152 | -1-12: notes from C to B
153 | -13: note off
154 | -14: note fade
155 | -15: note cut
156 | INST: channel's instrument
157 | VOLU: channel's volume value:
158 | -0: nothing
159 | -1-63: panning (1-63)
160 | -64-127: volume, overrides instrument's default volume
161 | -128-137: fine volume slide up
162 | -138-147: fine volume slide down
163 | -160-175: volume slide up
164 | -176-183: volume slide down
165 | -184-193: pitch slide down
166 | -194-203: pitch slide up
167 | -204-213: portamento
168 | -214-223: vibrato depth
169 | -224-239: high offset
170 | -240: panning (0)
171 | -241: panning (64)
172 | -242-248: panning slide left (0-7)\*2
173 | -249-255: panning slide right (0-7)\*2
174 | FXID: channel's effect number
175 | FXVL: channel's effect value
176 |
177 | please note that the patterns are also compressed,
178 | in a way pretty similar to how ST3 does.
179 |
180 | in case you don't know how ST3 "packs" patterns, here it is:
181 | 1. read maskbyte in seek position
182 | 2. if (maskbyte==0) then row is done
183 | 3. channel=maskbyte%32
184 | 4. if (maskbyte&32) then read NOTE and INSTRUMENT
185 | 5. if (maskbyte&64) then read VOLUME
186 | 6. if (maskbyte&128) then read EFFECT and EFFECTVALUE
187 | 7. repeat until pattern is done or `seek>size`
188 |
189 | ## Sound effect structure (perhaps legacy, I don't remember)
190 | ---- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -A- -B- -C- -D- -E- -F-
191 | ┌───────────────────────────────────────────────────────────────┐
192 | 00│ Packed effect data |
193 | └───────────────────────────────────────────────────────────────┘
194 |
195 | and this is how soundtracker packs sound effects:
196 | 1. read maskbyte in seek position
197 | 2. if (maskbyte==0) then effect is done
198 | 3. if (maskbyte&1) then PERIOD (hl) and VOLUME follows
199 | 4. if (maskbyte&2) then PAN follows
200 | 3. if (maskbyte&4) then DUTY and SHAPE follows
201 | 4. if (maskbyte&8) then RM, RMPERIOD (hl), RMSHAPE and RMDUTY follows
202 | 5. if (maskbyte&16) then PCMpos, PCMbound and PCMloop follow
203 | 6. if (maskbyte&32) then FILTERMODE, CUTOFF and RESONANCE follow
204 |
--------------------------------------------------------------------------------
/papers/help.txt:
--------------------------------------------------------------------------------
1 | (100 columns)
2 | ---SOUNDTRACKER HELP---
3 | table of contents:
4 | 1. what's soundtracker?
5 | 2.
6 | 3. user interface
7 | 3.1. header
8 | 3.2. pattern view
9 | 3.3. instrument view
10 | 3.4. song view
11 | 3.5. mixer view
12 | 3.6. diskop view
13 | 3.7. config view
14 | 4. reference
15 | 4.1. keyboard reference
16 | 4.2. effect reference
17 | 4.3. volume column reference
18 | 4.4. Zxx reference
19 | 4.5. compatibility reference
20 | 4.6. in-depth effect information
21 | 4.7. chip's technical information
22 |
23 | 1. what's soundtracker?
24 | soundtracker (not going to be the final name!) is a tool for creating 8-bit chiptunes
25 | using the basis of trackers.
26 | Unlike similar 8-bit trackers, this tracker is designed to be more IT-friendly.
27 |
28 | 2.
29 |
30 | 3. user interface
31 |
32 | 3.1.
33 |
34 | 3.2. pattern view
35 | use left and right to move the cursor
36 | use up and down to scroll between rows
37 | use the keyboard like a piano to put a note (volume and instrument values are also set)
38 | you can set the current effect by going there
39 | NOTE|INSTRUMENT|VOLUME|EFFECT
40 | ... .. ... ... -> C-5 01 v40 G00
41 |
42 | 3.3. instrument view
43 | (I'll write more later)
44 | -INSXX^v: current instrument to be edited
45 | -Save: saves this instrument
46 | -Load: load an instrument
47 | -RelNote: sets relative note for this instrument
48 | -Name: sets the name of this instrument (max 32 chars)
49 | -Filter: sets the filter mode for this channel (won't be active if cutoff envelope is not active)
50 |
51 |
52 |
53 | (Sequence Editor)
54 | -ON/NO: toggles if this envelope will be used
55 | -SeqXX^v: sets the sequence to be used
56 | -NF: finds the next free envelope and assigns it to this instrument
57 | -X: clears the current envelope (no warnings!)
58 | -Loop: loop point for this sequence
59 | -Release: release point for this sequence
60 | -Length: length of this sequence
61 |
62 | 4. reference
63 |
64 | 4.1. keyboard reference
65 |
66 | 4.2. effect reference
67 | The effect set used by soundtracker is the same used in Impulse Tracker.
68 | [effect] [action]
69 | Axx Sets the speed to XX. Effect is ignored if A00.
70 | Bxx Jumps to pattern XX.
71 | Cxx Pattern break. Jumps to next pattern at position XX.
72 | Dxx Volume slide. 0X for a down slide and X0 for a up slide.
73 | Exx Pitch slide down.
74 | Fxx Pitch slide up.
75 | Gxx Tone portamento. XX is speed.
76 | Hxy Vibrato.
77 | Ixy Tremor.
78 | Jxy Arpeggio.
79 | Kxx Volume slide + Vibrato.
80 | Lxx Volume slide + Tone Portamento.
81 | Mxx Sets channel volume.
82 | Nxx Channel volume slide.
83 | Oxx Start all envelopes at position XX.
84 | Pxx Panning slide. 0X for a right slide and X0 for a left slide.
85 | Qxy Retriggers all envelopes.
86 | Rxy Tremolo.
87 | Sxy Special commands.
88 | Txx Set tempo.
89 | Uxy Fine vibrato.
90 | Vxx Set master volume.
91 | Wxx Master volume slide.
92 | Xxx Set panning.
93 | Yxy Panning tremolo.
94 | Zxx Tracker command.
95 |
96 | 4.3. volume column reference
97 |
98 | 4.4. Zxx reference
99 | *** NOTE: This is not implemented yet! ***
100 | The Zxx effect allows controlling the chip's registers and some tracker variables directly.
101 | Values from 00-7f change the current variable's value.
102 | Values from 80-ff allow setting up the current variable.
103 | [value] [action]
104 | $80 Do nothing.
105 | $81 Enable smooth value changes.
106 | $82 Disable smooth value changes.
107 | $90-$97 Enable envelopes for this channel.
108 | $98-$9f Disable envelopes for this channel.
109 | $a0-$a7 Set filter mode for unfiltered notes on this channel.
110 | $a8-$af Force filters on this channel.
111 | $b0 Cutoff handling.
112 | $b1 Resonance handling.
113 | $b2 Toggle forcing ring modulator.
114 | $b3 Ring modulator (note) handling.
115 | $b4 Ring modulator (sweep) handling.
116 | $b5 Ring modulator (relative note) handling.
117 | $b6 Ring modulator (multiplier) handling.
118 | $b7 Ring modulator pulse width handling.
119 | $b8-$bf Set ring modulator shape.
120 | $c0 Pulse width handling.
121 | $c1 Pulse width (sweep) handling.
122 | $c8-$cf Force a shape under non-shaped notes on this channel.
123 | $d0 Force ADSR volume on this channel.
124 | $d1 Force ADSR cutoff on this channel.
125 | $d2-$d5 Volume ADSR parameter handling.
126 | $d6-$d9 Cutoff ADSR parameter handling.
127 | $e0-$e7 Toggle forcing another envelope on this channel.
128 | $e8-$ef Forced envelope handling.
129 | $f0 Force oscillator.
130 | $f1 Force PCM sampler.
131 | $f2 Toggle forcing oscillator sync (self). Use RM parameters.
132 | $f3 Toggle forcing oscillator sync (send).
133 | $f4 Local mode for switches.
134 | $f5 Global mode for switches.
135 | $fb Reset registers.
136 | $fc Reset oscillator.
137 | $fd Reset filter.
138 | $fe Reset RM oscillator.
139 | $ff Reset channel.
140 |
141 | 4.5. compatibility reference
142 | -Gxx behavior:
143 | -IT: share Gxx memory with Exx and Fxx
144 | -original/PT/XM/S3M: don't share memory
145 | -Exx/Fxx memory:
146 | -IT: there is E/F memory
147 | -original/PT/XM/S3M: nothing
148 | -Arpeggios:
149 | -original/IT/PT/S3M: normal arpeggios
150 | -XM: reversed arpeggios, and unexpected behavior at speed>16
151 | -Effect values:
152 | -original/IT/PT/XM: zero values don't use the previous effect's value
153 | -S3M: zero values use the previous effect's value
154 | -Note range:
155 | -original/IT/XM/S3M: C-0 to B-9
156 | -PT: C-3 to B-6
157 | -Retrigger with RVCT value 0:
158 | -original/IT/PT/S3M: no change
159 | -XM: previous value
160 | -Tremor:
161 | -original/PT/S3M/XM: clean tremor
162 | -IT: buggy tremor
163 | -Instrument without note:
164 | -original/S3M/XM: reset volume, nothing else
165 | -IT: retrigger note with new instrument
166 | -PT: change instrument but do not retrigger note
167 | -Dxx memory:
168 | -PT: no Dxx memory
169 | -original/IT/S3M/XM: Dxx memory present
170 |
171 | 4.6. in-depth effect information
172 | this is how soundtracker processes effects.
173 | -Axx: Set Speed: sets the speed ONLY in the first tick.
174 | -Bxx: Jump to Row: jumps to order XX after this row.
175 | -Cxx: Jump to Next: jumps to next order after this row, starting at position XX.
176 | -Dxx: Volume Slide: slides the volume either up or down per tick.
177 | -if 0x, then volume-=x; otherwise volume+=x
178 | -if Fx, then previous procedure applies only in the first tick
179 | -Exx: Pitch Slide Down: slides the pitch down per tick.
180 | -if Ex, changes are 4 times more precise
181 | -if Fx, slide is only done in first tick
182 | -Fxx: Pitch Slide Up: same as above but goes up.
183 | -Gxx: Tone Portamento: slides to new note with speed xx.
184 | -if this effect is present do not reset envelopes.
185 | -Hxy: Vibrato: executes a vibrato using a sine wave at speed X and depth Y.
186 | -original pitch is preserved, though.
187 | -Ixy: Tremor: note on for X ticks, and off for Y ticks.
188 | -Jxy: Arpeggio:
189 | (i'll write more later)
190 |
191 | 4.7. chip's technical information
192 | the chip emulated in the tracker is a custom chip. here's its description.
193 | -8 channels
194 | -2 modes per channel: OSCILLATOR, and PCM SAMPLES.
195 | -filters (low, high and band) in all modes.
196 | -ring modulation in ALL modes!
197 | (i'll write more later, sorry)
198 |
--------------------------------------------------------------------------------
/papers/ibm-plex-license.txt:
--------------------------------------------------------------------------------
1 | Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 | -----------------------------------------------------------
8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9 | -----------------------------------------------------------
10 |
11 | PREAMBLE
12 | The goals of the Open Font License (OFL) are to stimulate worldwide
13 | development of collaborative font projects, to support the font creation
14 | efforts of academic and linguistic communities, and to provide a free and
15 | open framework in which fonts may be shared and improved in partnership
16 | with others.
17 |
18 | The OFL allows the licensed fonts to be used, studied, modified and
19 | redistributed freely as long as they are not sold by themselves. The
20 | fonts, including any derivative works, can be bundled, embedded,
21 | redistributed and/or sold with any software provided that any reserved
22 | names are not used by derivative works. The fonts and derivatives,
23 | however, cannot be released under any other type of license. The
24 | requirement for fonts to remain under this license does not apply
25 | to any document created using the fonts or their derivatives.
26 |
27 | DEFINITIONS
28 | "Font Software" refers to the set of files released by the Copyright
29 | Holder(s) under this license and clearly marked as such. This may
30 | include source files, build scripts and documentation.
31 |
32 | "Reserved Font Name" refers to any names specified as such after the
33 | copyright statement(s).
34 |
35 | "Original Version" refers to the collection of Font Software components as
36 | distributed by the Copyright Holder(s).
37 |
38 | "Modified Version" refers to any derivative made by adding to, deleting,
39 | or substituting -- in part or in whole -- any of the components of the
40 | Original Version, by changing formats or by porting the Font Software to a
41 | new environment.
42 |
43 | "Author" refers to any designer, engineer, programmer, technical
44 | writer or other person who contributed to the Font Software.
45 |
46 | PERMISSION & CONDITIONS
47 | Permission is hereby granted, free of charge, to any person obtaining
48 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
49 | redistribute, and sell modified and unmodified copies of the Font
50 | Software, subject to the following conditions:
51 |
52 | 1) Neither the Font Software nor any of its individual components,
53 | in Original or Modified Versions, may be sold by itself.
54 |
55 | 2) Original or Modified Versions of the Font Software may be bundled,
56 | redistributed and/or sold with any software, provided that each copy
57 | contains the above copyright notice and this license. These can be
58 | included either as stand-alone text files, human-readable headers or
59 | in the appropriate machine-readable metadata fields within text or
60 | binary files as long as those fields can be easily viewed by the user.
61 |
62 | 3) No Modified Version of the Font Software may use the Reserved Font
63 | Name(s) unless explicit written permission is granted by the corresponding
64 | Copyright Holder. This restriction only applies to the primary font name as
65 | presented to the users.
66 |
67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68 | Software shall not be used to promote, endorse or advertise any
69 | Modified Version, except to acknowledge the contribution(s) of the
70 | Copyright Holder(s) and the Author(s) or with their explicit written
71 | permission.
72 |
73 | 5) The Font Software, modified or unmodified, in part or in whole,
74 | must be distributed entirely under this license, and must not be
75 | distributed under any other license. The requirement for fonts to
76 | remain under this license does not apply to any document created
77 | using the Font Software.
78 |
79 | TERMINATION
80 | This license becomes null and void if any of the above conditions are
81 | not met.
82 |
83 | DISCLAIMER
84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92 | OTHER DEALINGS IN THE FONT SOFTWARE.
--------------------------------------------------------------------------------
/papers/info.txt:
--------------------------------------------------------------------------------
1 | This is a chiptune tracker.
2 |
3 | ## Features.
4 | - You can work with up to 4 chips at once for a total of 32 channels.
5 | - You can import IT/S3M/MOD files directly into the program.
6 |
7 | ## Tracker's Specifications.
8 | This is a format specification!
9 |
10 |
11 | bytable[8][256][256], allows for setting up the envelope tables, up to 512kb
12 |
13 | bytable[table][indextab][position], where
14 |
15 | table=0-7, 0=volume, 1=pitch, 2=pitch*256, 3=cutoff, 4=resonance-filter-mode, 5=shape, 6=duty
16 |
17 | position=0-255, 0-252=envelope, 253=length, 254=loop-position, 255=release-position
18 |
19 |
20 | pat[256][256][8][5], pattern table, 2560kb
21 |
22 | pat[patid][patpos][channel][bytepos], where
23 |
24 | patid=0-255
25 |
26 | patpos=0-255
27 |
28 | channel=0-7
29 |
30 | bytepos=0-4, 0=note, 1=instrument-reverse, 2=volume-effect, 3=effect, 4=effect-value
31 |
32 | ## Playback.
33 | Playback is done like this:
34 |
35 | ###(Next Tick)
36 | 1. Update all envelope positions.
37 | 2. Apply effects if required.
38 |
39 | ###(Next Row)
40 | 1. Reset the tick counter.
41 | 2. If there is a new note:
42 | 1. Reset all the envelopes, unless there's a Gxx effect in such row.
43 | 2. Change the note value, unless there's a Gxx effect in such row.
44 | 3. If there is a new volume value:
45 | 1. Set note volume.
46 | 4. If there is any effect in the effect column:
47 | 1. Process such effect.
48 |
49 | ###(Next Effect)
50 | - Axx: Change the song speed.
51 | - Bxx: Stop this pattern and go to pattern XX.
52 | - Cxx: Skip to next pattern.
53 | - Dxx: Fade in/out the note's volume, while not in Next Row.
54 | - Exx: Decrease the frequency value and set the portamento memory value for further E00s.
55 | - Fxx: Same as Exx but increase it instead.
56 | - Gxx: Portamento with a note.
57 | - Hxy: Apply vibrato effects.
58 | - Ixy: Apply tremor effects.
59 | - Jxy: Apply arpeggio effects.
60 | - Kxy: Slide+Vibrato.
61 | - Lxy: Slide+Porta.
62 | - Mxx: Set channel volume.
63 | - Nxx: Channel volume slide.
64 | - Oxx: Sets the position for ALL envelopes to XX.
65 | - Pxx: Panning slides.
66 | - Qxy: Apply retrigger effects.
67 | - Rxy: Apply tremolo effects.
68 | - Sxy: Apply any special commands if required.
69 | - Txx: Set tempo (not supported).
70 | - Uxy: Apply fine vibrato effects.
71 | - Vxx:
72 | - Wxx:
73 | - Xxx: Set channel panning.
74 | - Yxy: Panning tremolo.
75 | - Zxx: Apply MIDI macro. However they are not stored in the resulting file.
76 |
77 | ## File Format's Specifications.
78 | check format.md.
79 |
80 | ## Note Periods.
81 | no longer used.
82 |
83 | note| freq | period
84 | ----|-------|------
85 | C-0 | 16,3525| 18346
86 | C#0 | 17,325 | 17316
87 | D-0 | 18,355 | 16344
88 | D#0 | 19,445 | 15428
89 | E-0 | 20,6025| 14561
90 | F-0 | 21,8275| 13744
91 | F#0 | 23,125 | 12973
92 | G-0 | 24,5 | 12245
93 | G#0 | 25,9575| 11557
94 | A-0 | 27,5 | 10909
95 | A#0 | 29,135 | 10297
96 | B-0 | 30,8675| 9719
97 |
98 | # <~>
99 |
--------------------------------------------------------------------------------
/papers/ohplease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/papers/ohplease.png
--------------------------------------------------------------------------------
/papers/ssformat.md:
--------------------------------------------------------------------------------
1 | # soundchip dump format
2 |
3 | the format is very similar to the one used in family BASIC for the play command.
4 |
5 | every property may take a value from a Lisp expression if it contains parentheses (e.g. `f(* 256 4)`.
6 |
7 | ## proper format
8 |
9 | + $: select channel.
10 | + f: set frequency. 4 hexadecimal digits as argument.
11 | + V: volume (0-127).
12 | - P: panning (char).
13 | + Y: duty (0-127).
14 | + S: shape (0-7).
15 | + c: cutoff (short).
16 | + r: resonance (char).
17 | + I: filter flag (0-7).
18 | - O: base octave (0-9).
19 | - e: reset channel.
20 | - g: reset filter.
21 | - h: set ring/sync flags.
22 | + R: finish tick, then rest for a number of ticks.
23 | + ;: finish tick.
24 |
25 | - [#]CDEFGAB: notes. appending a number will add that number of octaves to the base one.
26 |
27 | - M: enable sweep units (0-7).
28 | - v: configure volume sweep.
29 | - l: configure filter sweep.
30 | - k: configure freq sweep.
31 |
32 | - p: enable/configure PCM.
33 |
34 | - T: set sync period.
35 |
36 | - /: go to line.
37 |
38 | - =: execute Lisp expression/ignore value.
39 | - ?: go to line if expression is true.
40 |
41 | ## sweep config format
42 |
43 | - frequency and filter:
44 | - SSSSaabb
45 | - S: speed. a: amount/dir. b: bound.
46 | - volume:
47 | - SSSSaabb
48 | - S: speed. a: amount/dir/loop/loopi. b: bound.
49 |
50 | ## Lisp symbols
51 |
52 | the SSLisp interpreter is minimalistic, and therefore only supports one or two-letter symbol names.
53 |
54 | the following symbols are set by ssinter:
55 |
56 | - `xf`: frequency
57 | - `xv`: volume
58 | - `xc`: cutoff
59 |
60 | - `xl`: current frame
61 |
62 | ## Lisp functions
63 |
64 | - `(note x)`: calculate note frequency for `x`
65 | - `(trans x)`: calculate transpose for `x` semitones
66 |
--------------------------------------------------------------------------------
/papers/ssiasm.md:
--------------------------------------------------------------------------------
1 | # soundtracker instrument assembly
2 |
3 | this is an advanced mode in where a custom program runs to handle the instrument.
4 |
5 | it is based on a stack machine.
6 |
7 | ## details
8 |
9 | - fully stack-oriented instruction set
10 | - stack size is 8 items
11 | - 16-item scratchpad
12 | - works on 32-bit integer and 16-bit fixed-point
13 | - instructions are 64-bit but packed for storage
14 |
15 | ## instruction set
16 |
17 | opcode | sym | desc
18 | -------|-----|----------------------
19 | add | + | add two items
20 | sub | - | subtract two items
21 | mul | * | multiply two items
22 | div | / | divide two items, divisor first
23 | mod | % | remainder of division, divisor first
24 | mulfi | *fi | multiply int with fixed
25 | mulff | *ff | multiply fixed with fixed
26 | divfi | /fi | divide int with fixed
27 | divff | /ff | divide fixed with fixed
28 | and | & | bitwise and
29 | or | | | bitwise or
30 | xor | ^ | bitwise xor
31 | not | ~ | bitwise not
32 | neg | - | negative
33 | sal | << | shift left
34 | sar | >> | shift right
35 | rol | <<. | rotate left
36 | ror | >>. | rotate right
37 | push | < | push value from scratchpad
38 | pushc | < | push value from soundchip
39 | pushi | < | push value immediate
40 | pop | > | pop value to scratchpad
41 | popc | > | pop value to soundchip
42 | drop | > | pop value to nowhere
43 | dup | # | duplicate value
44 | clr | . | empty stack
45 | bra | ^^^ | branch always
46 | beq | ^== | branch if zero
47 | bne | ^!= | branch if not zero
48 | bpl | ^> | branch if positive
49 | bmi | ^< | branch if negative
50 | off | $ | select channel by offset
51 | chan | $ | select channel by index
52 | wait | --- | wait ticks
53 | ret | === | stop execution
54 | brk | !!! | break here
55 | nop | ... | no operation
56 |
57 | ## soundchip variables
58 |
59 | addr | value
60 | -----|-----------
61 | $00 | channel variables (32)
62 | $20 | note frequency
63 | $21 | note in fixed
64 | $22 | unprocessed note
65 | $23 | unprocessed note in fixed
66 | $24 | volume
67 | $25 | unprocessed volume
68 | $26 | panning
69 | $27 | unprocessed panning
70 | $28 | note on
71 | $29 | current tick in pattern
72 | $2a | current tick in song
73 |
74 | # screw this document
75 |
76 | yep, this is a lot of nonsense I wrote the other day.
--------------------------------------------------------------------------------
/papers/tooltips.txt:
--------------------------------------------------------------------------------
1 | Speed (ticks/row)
2 | Playback position
3 | Pattern number for this order
4 | Disk operations
5 | Pattern view
6 | Instrument editor
7 | Song view
8 | Mixer
9 | Settings
10 | Help
11 | Enable pattern editing
12 | Play from cursor
13 | Play from pattern start
14 | Stop
15 | Step playback
16 | Current row
17 | Current pattern
18 | Current tick
19 | Current speed
20 | Orders
21 | Note
22 | Instrument
23 | Volume
24 | Effect
25 | Row number
26 | About
27 | Instrument number
28 | Save instrument
29 | Load instrument
30 | Disable/Enable envelope
31 | Volume envelope
32 | Cutoff envelope
33 | Resonance envelope
34 | Duty envelope
35 | Shape envelope
36 | Pitch envelope
37 | Fine pitch envelope
38 | Panning envelope
39 | Sequence number
40 | Use next free sequence
41 | Clear envelope
42 | Hex mode
43 | Loop position (FF=disabled)
44 | Release position (FF=disabled)
45 | Envelope length
46 | Relative note (transposition)
47 | Filter mode (current: %s)
48 | Low pass
49 | High pass
50 | Band pass
51 | disabled
52 | lowpass
53 | highpass
54 | bandpass
55 | notch
56 | allpass
57 | low+band
58 | high+band
59 | PCM sample mode
60 | Sample offset
61 | Sample length
62 | Sample loop point
63 | PCM speed multiplier
64 | Maximum cutoff frequency
65 | Ring modulation
66 | Ring modulator frequency
67 | Ring modulator shape
68 | Ring modulator duty
69 | Oscillator sync
70 | Reset oscillator on new note
71 | Reset filter on new note
72 | Reset ringmod oscillator on new note
73 | Default volume
74 | Default song speed (ticks/row)
75 | Channel number
76 | Rows per beat
77 | Rows per bar
78 | Song detune (%s)
79 | Song length
80 | Default song tempo
81 | Frequency
82 | Volume
83 | Panning
84 | Duty
85 | Cutoff
86 | Resonance
87 | Filter mode
88 | Shape
89 | PCM
90 | Ring modulation
91 | Oscillator sync
92 | PCM offset
93 | PCM bound
94 | PCM start
95 | PCM multiplier
96 | RM frequency
97 | RM shape
98 | RM duty
99 | Playback mode
100 | Normal playback mode
101 | Impulse Tracker-compatible mode
102 | FastTracker 2-compatible mode
103 | ProTracker-compatible mode
104 | Scream Tracker 3-compatible mode
105 | Share Gxx memory with Exx and Fxx
106 | Double filter frequency limit
107 | Sliding mode
108 | Linear slides
109 | 300KHz-periods mode
110 | Amiga slides
111 | Default channel volume
112 | Default channel panning
113 | Duty (%s%)
114 | Square
115 | Saw
116 | Sine
117 | Triangle
118 | Noise
119 | Duty noise
120 | Shape 6
121 | Shape 7
122 | Frequency (%sHz)
123 | Cutoff
124 | Instrument number
125 | Channel volume
126 | Volume envelope position
127 | Cutoff envelope position
128 | Resonance envelope position
129 | Duty envelope position
130 | Shape envelope position
131 | Pitch envelope position
132 | Fine pitch envelope position
133 | Panning envelope position
134 | Current note (%.2f, %.1fHz)
135 | Portamento note (%.2f, %.1fHz)
136 | New file
137 | Load file
138 | Save file
139 | Import ProTracker module
140 | Import Scream Tracker 3 module
141 | Import Impulse Tracker module
142 | Import FastTracker 2 module
143 | File name
--------------------------------------------------------------------------------
/papers/unifont-license.txt:
--------------------------------------------------------------------------------
1 | LICENSE
2 | -------
3 | The source code for everything except the compiled fonts in this current
4 | release is licensed as follows:
5 |
6 | License for this current distribution of program source
7 | files (i.e., everything except the fonts) is released under
8 | the terms of the GNU General Public License version 2,
9 | or (at your option) a later version.
10 |
11 | See the section below for a copy of the GNU General Public License
12 | version 2.
13 |
14 | The license for the compiled fonts is covered by the above GPL terms
15 | with the GNU font embedding exception, as follows:
16 |
17 | As a special exception, if you create a document which uses this font,
18 | and embed this font or unaltered portions of this font into the document,
19 | this font does not by itself cause the resulting document to be covered
20 | by the GNU General Public License. This exception does not however
21 | invalidate any other reasons why the document might be covered by the
22 | GNU General Public License. If you modify this font, you may extend
23 | this exception to your version of the font, but you are not obligated
24 | to do so. If you do not wish to do so, delete this exception statement
25 | from your version.
26 |
27 | See "http://www.gnu.org/licenses/gpl-faq.html#FontException" for more details.
28 |
29 |
30 | GPL VERSION 2
31 | -------------
32 |
33 | GNU GENERAL PUBLIC LICENSE
34 | Version 2, June 1991
35 |
36 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
37 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
38 | Everyone is permitted to copy and distribute verbatim copies
39 | of this license document, but changing it is not allowed.
40 |
41 | Preamble
42 |
43 | The licenses for most software are designed to take away your
44 | freedom to share and change it. By contrast, the GNU General Public
45 | License is intended to guarantee your freedom to share and change free
46 | software--to make sure the software is free for all its users. This
47 | General Public License applies to most of the Free Software
48 | Foundation's software and to any other program whose authors commit to
49 | using it. (Some other Free Software Foundation software is covered by
50 | the GNU Lesser General Public License instead.) You can apply it to
51 | your programs, too.
52 |
53 | When we speak of free software, we are referring to freedom, not
54 | price. Our General Public Licenses are designed to make sure that you
55 | have the freedom to distribute copies of free software (and charge for
56 | this service if you wish), that you receive source code or can get it
57 | if you want it, that you can change the software or use pieces of it
58 | in new free programs; and that you know you can do these things.
59 |
60 | To protect your rights, we need to make restrictions that forbid
61 | anyone to deny you these rights or to ask you to surrender the rights.
62 | These restrictions translate to certain responsibilities for you if you
63 | distribute copies of the software, or if you modify it.
64 |
65 | For example, if you distribute copies of such a program, whether
66 | gratis or for a fee, you must give the recipients all the rights that
67 | you have. You must make sure that they, too, receive or can get the
68 | source code. And you must show them these terms so they know their
69 | rights.
70 |
71 | We protect your rights with two steps: (1) copyright the software, and
72 | (2) offer you this license which gives you legal permission to copy,
73 | distribute and/or modify the software.
74 |
75 | Also, for each author's protection and ours, we want to make certain
76 | that everyone understands that there is no warranty for this free
77 | software. If the software is modified by someone else and passed on, we
78 | want its recipients to know that what they have is not the original, so
79 | that any problems introduced by others will not reflect on the original
80 | authors' reputations.
81 |
82 | Finally, any free program is threatened constantly by software
83 | patents. We wish to avoid the danger that redistributors of a free
84 | program will individually obtain patent licenses, in effect making the
85 | program proprietary. To prevent this, we have made it clear that any
86 | patent must be licensed for everyone's free use or not licensed at all.
87 |
88 | The precise terms and conditions for copying, distribution and
89 | modification follow.
90 |
91 | GNU GENERAL PUBLIC LICENSE
92 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
93 |
94 | 0. This License applies to any program or other work which contains
95 | a notice placed by the copyright holder saying it may be distributed
96 | under the terms of this General Public License. The "Program", below,
97 | refers to any such program or work, and a "work based on the Program"
98 | means either the Program or any derivative work under copyright law:
99 | that is to say, a work containing the Program or a portion of it,
100 | either verbatim or with modifications and/or translated into another
101 | language. (Hereinafter, translation is included without limitation in
102 | the term "modification".) Each licensee is addressed as "you".
103 |
104 | Activities other than copying, distribution and modification are not
105 | covered by this License; they are outside its scope. The act of
106 | running the Program is not restricted, and the output from the Program
107 | is covered only if its contents constitute a work based on the
108 | Program (independent of having been made by running the Program).
109 | Whether that is true depends on what the Program does.
110 |
111 | 1. You may copy and distribute verbatim copies of the Program's
112 | source code as you receive it, in any medium, provided that you
113 | conspicuously and appropriately publish on each copy an appropriate
114 | copyright notice and disclaimer of warranty; keep intact all the
115 | notices that refer to this License and to the absence of any warranty;
116 | and give any other recipients of the Program a copy of this License
117 | along with the Program.
118 |
119 | You may charge a fee for the physical act of transferring a copy, and
120 | you may at your option offer warranty protection in exchange for a fee.
121 |
122 | 2. You may modify your copy or copies of the Program or any portion
123 | of it, thus forming a work based on the Program, and copy and
124 | distribute such modifications or work under the terms of Section 1
125 | above, provided that you also meet all of these conditions:
126 |
127 | a) You must cause the modified files to carry prominent notices
128 | stating that you changed the files and the date of any change.
129 |
130 | b) You must cause any work that you distribute or publish, that in
131 | whole or in part contains or is derived from the Program or any
132 | part thereof, to be licensed as a whole at no charge to all third
133 | parties under the terms of this License.
134 |
135 | c) If the modified program normally reads commands interactively
136 | when run, you must cause it, when started running for such
137 | interactive use in the most ordinary way, to print or display an
138 | announcement including an appropriate copyright notice and a
139 | notice that there is no warranty (or else, saying that you provide
140 | a warranty) and that users may redistribute the program under
141 | these conditions, and telling the user how to view a copy of this
142 | License. (Exception: if the Program itself is interactive but
143 | does not normally print such an announcement, your work based on
144 | the Program is not required to print an announcement.)
145 |
146 | These requirements apply to the modified work as a whole. If
147 | identifiable sections of that work are not derived from the Program,
148 | and can be reasonably considered independent and separate works in
149 | themselves, then this License, and its terms, do not apply to those
150 | sections when you distribute them as separate works. But when you
151 | distribute the same sections as part of a whole which is a work based
152 | on the Program, the distribution of the whole must be on the terms of
153 | this License, whose permissions for other licensees extend to the
154 | entire whole, and thus to each and every part regardless of who wrote it.
155 |
156 | Thus, it is not the intent of this section to claim rights or contest
157 | your rights to work written entirely by you; rather, the intent is to
158 | exercise the right to control the distribution of derivative or
159 | collective works based on the Program.
160 |
161 | In addition, mere aggregation of another work not based on the Program
162 | with the Program (or with a work based on the Program) on a volume of
163 | a storage or distribution medium does not bring the other work under
164 | the scope of this License.
165 |
166 | 3. You may copy and distribute the Program (or a work based on it,
167 | under Section 2) in object code or executable form under the terms of
168 | Sections 1 and 2 above provided that you also do one of the following:
169 |
170 | a) Accompany it with the complete corresponding machine-readable
171 | source code, which must be distributed under the terms of Sections
172 | 1 and 2 above on a medium customarily used for software interchange; or,
173 |
174 | b) Accompany it with a written offer, valid for at least three
175 | years, to give any third party, for a charge no more than your
176 | cost of physically performing source distribution, a complete
177 | machine-readable copy of the corresponding source code, to be
178 | distributed under the terms of Sections 1 and 2 above on a medium
179 | customarily used for software interchange; or,
180 |
181 | c) Accompany it with the information you received as to the offer
182 | to distribute corresponding source code. (This alternative is
183 | allowed only for noncommercial distribution and only if you
184 | received the program in object code or executable form with such
185 | an offer, in accord with Subsection b above.)
186 |
187 | The source code for a work means the preferred form of the work for
188 | making modifications to it. For an executable work, complete source
189 | code means all the source code for all modules it contains, plus any
190 | associated interface definition files, plus the scripts used to
191 | control compilation and installation of the executable. However, as a
192 | special exception, the source code distributed need not include
193 | anything that is normally distributed (in either source or binary
194 | form) with the major components (compiler, kernel, and so on) of the
195 | operating system on which the executable runs, unless that component
196 | itself accompanies the executable.
197 |
198 | If distribution of executable or object code is made by offering
199 | access to copy from a designated place, then offering equivalent
200 | access to copy the source code from the same place counts as
201 | distribution of the source code, even though third parties are not
202 | compelled to copy the source along with the object code.
203 |
204 | 4. You may not copy, modify, sublicense, or distribute the Program
205 | except as expressly provided under this License. Any attempt
206 | otherwise to copy, modify, sublicense or distribute the Program is
207 | void, and will automatically terminate your rights under this License.
208 | However, parties who have received copies, or rights, from you under
209 | this License will not have their licenses terminated so long as such
210 | parties remain in full compliance.
211 |
212 | 5. You are not required to accept this License, since you have not
213 | signed it. However, nothing else grants you permission to modify or
214 | distribute the Program or its derivative works. These actions are
215 | prohibited by law if you do not accept this License. Therefore, by
216 | modifying or distributing the Program (or any work based on the
217 | Program), you indicate your acceptance of this License to do so, and
218 | all its terms and conditions for copying, distributing or modifying
219 | the Program or works based on it.
220 |
221 | 6. Each time you redistribute the Program (or any work based on the
222 | Program), the recipient automatically receives a license from the
223 | original licensor to copy, distribute or modify the Program subject to
224 | these terms and conditions. You may not impose any further
225 | restrictions on the recipients' exercise of the rights granted herein.
226 | You are not responsible for enforcing compliance by third parties to
227 | this License.
228 |
229 | 7. If, as a consequence of a court judgment or allegation of patent
230 | infringement or for any other reason (not limited to patent issues),
231 | conditions are imposed on you (whether by court order, agreement or
232 | otherwise) that contradict the conditions of this License, they do not
233 | excuse you from the conditions of this License. If you cannot
234 | distribute so as to satisfy simultaneously your obligations under this
235 | License and any other pertinent obligations, then as a consequence you
236 | may not distribute the Program at all. For example, if a patent
237 | license would not permit royalty-free redistribution of the Program by
238 | all those who receive copies directly or indirectly through you, then
239 | the only way you could satisfy both it and this License would be to
240 | refrain entirely from distribution of the Program.
241 |
242 | If any portion of this section is held invalid or unenforceable under
243 | any particular circumstance, the balance of the section is intended to
244 | apply and the section as a whole is intended to apply in other
245 | circumstances.
246 |
247 | It is not the purpose of this section to induce you to infringe any
248 | patents or other property right claims or to contest validity of any
249 | such claims; this section has the sole purpose of protecting the
250 | integrity of the free software distribution system, which is
251 | implemented by public license practices. Many people have made
252 | generous contributions to the wide range of software distributed
253 | through that system in reliance on consistent application of that
254 | system; it is up to the author/donor to decide if he or she is willing
255 | to distribute software through any other system and a licensee cannot
256 | impose that choice.
257 |
258 | This section is intended to make thoroughly clear what is believed to
259 | be a consequence of the rest of this License.
260 |
261 | 8. If the distribution and/or use of the Program is restricted in
262 | certain countries either by patents or by copyrighted interfaces, the
263 | original copyright holder who places the Program under this License
264 | may add an explicit geographical distribution limitation excluding
265 | those countries, so that distribution is permitted only in or among
266 | countries not thus excluded. In such case, this License incorporates
267 | the limitation as if written in the body of this License.
268 |
269 | 9. The Free Software Foundation may publish revised and/or new versions
270 | of the General Public License from time to time. Such new versions will
271 | be similar in spirit to the present version, but may differ in detail to
272 | address new problems or concerns.
273 |
274 | Each version is given a distinguishing version number. If the Program
275 | specifies a version number of this License which applies to it and "any
276 | later version", you have the option of following the terms and conditions
277 | either of that version or of any later version published by the Free
278 | Software Foundation. If the Program does not specify a version number of
279 | this License, you may choose any version ever published by the Free Software
280 | Foundation.
281 |
282 | 10. If you wish to incorporate parts of the Program into other free
283 | programs whose distribution conditions are different, write to the author
284 | to ask for permission. For software which is copyrighted by the Free
285 | Software Foundation, write to the Free Software Foundation; we sometimes
286 | make exceptions for this. Our decision will be guided by the two goals
287 | of preserving the free status of all derivatives of our free software and
288 | of promoting the sharing and reuse of software generally.
289 |
290 | NO WARRANTY
291 |
292 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
293 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
294 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
295 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
296 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
297 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
298 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
299 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
300 | REPAIR OR CORRECTION.
301 |
302 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
303 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
304 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
305 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
306 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
307 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
308 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
309 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
310 | POSSIBILITY OF SUCH DAMAGES.
311 |
312 | END OF TERMS AND CONDITIONS
313 |
314 | How to Apply These Terms to Your New Programs
315 |
316 | If you develop a new program, and you want it to be of the greatest
317 | possible use to the public, the best way to achieve this is to make it
318 | free software which everyone can redistribute and change under these terms.
319 |
320 | To do so, attach the following notices to the program. It is safest
321 | to attach them to the start of each source file to most effectively
322 | convey the exclusion of warranty; and each file should have at least
323 | the "copyright" line and a pointer to where the full notice is found.
324 |
325 |
326 | Copyright (C)
327 |
328 | This program is free software; you can redistribute it and/or modify
329 | it under the terms of the GNU General Public License as published by
330 | the Free Software Foundation; either version 2 of the License, or
331 | (at your option) any later version.
332 |
333 | This program is distributed in the hope that it will be useful,
334 | but WITHOUT ANY WARRANTY; without even the implied warranty of
335 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
336 | GNU General Public License for more details.
337 |
338 | You should have received a copy of the GNU General Public License along
339 | with this program; if not, write to the Free Software Foundation, Inc.,
340 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
341 |
342 | Also add information on how to contact you by electronic and paper mail.
343 |
344 | If the program is interactive, make it output a short notice like this
345 | when it starts in an interactive mode:
346 |
347 | Gnomovision version 69, Copyright (C) year name of author
348 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
349 | This is free software, and you are welcome to redistribute it
350 | under certain conditions; type `show c' for details.
351 |
352 | The hypothetical commands `show w' and `show c' should show the appropriate
353 | parts of the General Public License. Of course, the commands you use may
354 | be called something other than `show w' and `show c'; they could even be
355 | mouse-clicks or menu items--whatever suits your program.
356 |
357 | You should also get your employer (if you work as a programmer) or your
358 | school, if any, to sign a "copyright disclaimer" for the program, if
359 | necessary. Here is a sample; alter the names:
360 |
361 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
362 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
363 |
364 | , 1 April 1989
365 | Ty Coon, President of Vice
366 |
367 | This General Public License does not permit incorporating your program into
368 | proprietary programs. If your program is a subroutine library, you may
369 | consider it more useful to permit linking proprietary applications with the
370 | library. If this is what you want to do, use the GNU Lesser General
371 | Public License instead of this License.
372 |
--------------------------------------------------------------------------------
/soundtracker.kdev4:
--------------------------------------------------------------------------------
1 | [Project]
2 | CreatedFrom=CMakeLists.txt
3 | Manager=KDevCMakeManager
4 | Name=soundtracker
5 |
--------------------------------------------------------------------------------
/src/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 |
5 | LOCAL_MODULE := main
6 |
7 | SDL_PATH := ../SDL
8 |
9 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
10 |
11 | LOCAL_SRC_FILES := blip_buf.c unifontfull.cpp soundchip.cpp hlesoundchip.cpp graphics.cpp ssinter.cpp fextra.cpp main.cpp
12 |
13 | LOCAL_SHARED_LIBRARIES := SDL2
14 |
15 | LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog
16 |
17 | include $(BUILD_SHARED_LIBRARY)
18 |
--------------------------------------------------------------------------------
/src/blip_buf.c:
--------------------------------------------------------------------------------
1 | /* blip_buf $vers. http://www.slack.net/~ant/ */
2 |
3 | #include "blip_buf.h"
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | /* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
11 | you can redistribute it and/or modify it under the terms of the GNU Lesser
12 | General Public License as published by the Free Software Foundation; either
13 | version 2.1 of the License, or (at your option) any later version. This
14 | library is distributed in the hope that it will be useful, but WITHOUT ANY
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 | A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17 | details. You should have received a copy of the GNU Lesser General Public
18 | License along with this module; if not, write to the Free Software Foundation,
19 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
20 |
21 | #if defined (BLARGG_TEST) && BLARGG_TEST
22 | #include "blargg_test.h"
23 | #endif
24 |
25 | /* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
26 | Avoids constants that don't fit in 32 bits. */
27 | #if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
28 | typedef unsigned long fixed_t;
29 | enum { pre_shift = 32 };
30 |
31 | #elif defined(ULLONG_MAX)
32 | typedef unsigned long long fixed_t;
33 | enum { pre_shift = 32 };
34 |
35 | #else
36 | typedef unsigned fixed_t;
37 | enum { pre_shift = 0 };
38 |
39 | #endif
40 |
41 | enum { time_bits = pre_shift + 20 };
42 |
43 | static fixed_t const time_unit = (fixed_t) 1 << time_bits;
44 |
45 | enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
46 | enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
47 |
48 | enum { half_width = 8 };
49 | enum { buf_extra = half_width*2 + end_frame_extra };
50 | enum { phase_bits = 5 };
51 | enum { phase_count = 1 << phase_bits };
52 | enum { delta_bits = 15 };
53 | enum { delta_unit = 1 << delta_bits };
54 | enum { frac_bits = time_bits - pre_shift };
55 |
56 | /* We could eliminate avail and encode whole samples in offset, but that would
57 | limit the total buffered samples to blip_max_frame. That could only be
58 | increased by decreasing time_bits, which would reduce resample ratio accuracy.
59 | */
60 |
61 | /** Sample buffer that resamples to output rate and accumulates samples
62 | until they're read out */
63 | struct blip_t
64 | {
65 | fixed_t factor;
66 | fixed_t offset;
67 | int avail;
68 | int size;
69 | int integrator;
70 | };
71 |
72 | typedef int buf_t;
73 |
74 | /* probably not totally portable */
75 | #define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
76 |
77 | /* Arithmetic (sign-preserving) right shift */
78 | #define ARITH_SHIFT( n, shift ) \
79 | ((n) >> (shift))
80 |
81 | enum { max_sample = +32767 };
82 | enum { min_sample = -32768 };
83 |
84 | #define CLAMP( n ) \
85 | {\
86 | if ( (short) n != n )\
87 | n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
88 | }
89 |
90 | static void check_assumptions( void )
91 | {
92 | int n;
93 |
94 | #if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
95 | #error "int must be at least 32 bits"
96 | #endif
97 |
98 | assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
99 |
100 | n = max_sample * 2;
101 | CLAMP( n );
102 | assert( n == max_sample );
103 |
104 | n = min_sample * 2;
105 | CLAMP( n );
106 | assert( n == min_sample );
107 |
108 | assert( blip_max_ratio <= time_unit );
109 | assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
110 | }
111 |
112 | blip_t* blip_new( int size )
113 | {
114 | blip_t* m;
115 | assert( size >= 0 );
116 |
117 | m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
118 | if ( m )
119 | {
120 | m->factor = time_unit / blip_max_ratio;
121 | m->size = size;
122 | blip_clear( m );
123 | check_assumptions();
124 | }
125 | return m;
126 | }
127 |
128 | void blip_delete( blip_t* m )
129 | {
130 | if ( m != NULL )
131 | {
132 | /* Clear fields in case user tries to use after freeing */
133 | memset( m, 0, sizeof *m );
134 | free( m );
135 | }
136 | }
137 |
138 | void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
139 | {
140 | double factor = time_unit * sample_rate / clock_rate;
141 | m->factor = (fixed_t) factor;
142 |
143 | /* Fails if clock_rate exceeds maximum, relative to sample_rate */
144 | assert( 0 <= factor - m->factor && factor - m->factor < 1 );
145 |
146 | /* Avoid requiring math.h. Equivalent to
147 | m->factor = (int) ceil( factor ) */
148 | if ( m->factor < factor )
149 | m->factor++;
150 |
151 | /* At this point, factor is most likely rounded up, but could still
152 | have been rounded down in the floating-point calculation. */
153 | }
154 |
155 | void blip_clear( blip_t* m )
156 | {
157 | /* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
158 | factor is rounded up. factor-1 is suitable if factor is rounded down.
159 | Since we don't know rounding direction, factor/2 accommodates either,
160 | with the slight loss of showing an error in half the time. Since for
161 | a 64-bit factor this is years, the halving isn't a problem. */
162 |
163 | m->offset = m->factor / 2;
164 | m->avail = 0;
165 | m->integrator = 0;
166 | memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
167 | }
168 |
169 | int blip_clocks_needed( const blip_t* m, int samples )
170 | {
171 | fixed_t needed;
172 |
173 | /* Fails if buffer can't hold that many more samples */
174 | assert( samples >= 0 && m->avail + samples <= m->size );
175 |
176 | needed = (fixed_t) samples * time_unit;
177 | if ( needed < m->offset )
178 | return 0;
179 |
180 | return (needed - m->offset + m->factor - 1) / m->factor;
181 | }
182 |
183 | void blip_end_frame( blip_t* m, unsigned t )
184 | {
185 | fixed_t off = t * m->factor + m->offset;
186 | m->avail += off >> time_bits;
187 | m->offset = off & (time_unit - 1);
188 |
189 | /* Fails if buffer size was exceeded */
190 | assert( m->avail <= m->size );
191 | }
192 |
193 | int blip_samples_avail( const blip_t* m )
194 | {
195 | return m->avail;
196 | }
197 |
198 | static void remove_samples( blip_t* m, int count )
199 | {
200 | buf_t* buf = SAMPLES( m );
201 | int remain = m->avail + buf_extra - count;
202 | m->avail -= count;
203 |
204 | memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
205 | memset( &buf [remain], 0, count * sizeof buf [0] );
206 | }
207 |
208 | int blip_read_samples( blip_t* m, short out [], int count, int stereo )
209 | {
210 | assert( count >= 0 );
211 |
212 | if ( count > m->avail )
213 | count = m->avail;
214 |
215 | if ( count )
216 | {
217 | int const step = stereo ? 2 : 1;
218 | buf_t const* in = SAMPLES( m );
219 | buf_t const* end = in + count;
220 | int sum = m->integrator;
221 | do
222 | {
223 | /* Eliminate fraction */
224 | int s = ARITH_SHIFT( sum, delta_bits );
225 |
226 | sum += *in++;
227 |
228 | CLAMP( s );
229 |
230 | *out = s;
231 | out += step;
232 |
233 | /* High-pass filter */
234 | sum -= s << (delta_bits - bass_shift);
235 | }
236 | while ( in != end );
237 | m->integrator = sum;
238 |
239 | remove_samples( m, count );
240 | }
241 |
242 | return count;
243 | }
244 |
245 | /* Things that didn't help performance on x86:
246 | __attribute__((aligned(128)))
247 | #define short int
248 | restrict
249 | */
250 |
251 | /* Sinc_Generator( 0.9, 0.55, 4.5 ) */
252 | static short const bl_step [phase_count + 1] [half_width] =
253 | {
254 | { 43, -115, 350, -488, 1136, -914, 5861,21022},
255 | { 44, -118, 348, -473, 1076, -799, 5274,21001},
256 | { 45, -121, 344, -454, 1011, -677, 4706,20936},
257 | { 46, -122, 336, -431, 942, -549, 4156,20829},
258 | { 47, -123, 327, -404, 868, -418, 3629,20679},
259 | { 47, -122, 316, -375, 792, -285, 3124,20488},
260 | { 47, -120, 303, -344, 714, -151, 2644,20256},
261 | { 46, -117, 289, -310, 634, -17, 2188,19985},
262 | { 46, -114, 273, -275, 553, 117, 1758,19675},
263 | { 44, -108, 255, -237, 471, 247, 1356,19327},
264 | { 43, -103, 237, -199, 390, 373, 981,18944},
265 | { 42, -98, 218, -160, 310, 495, 633,18527},
266 | { 40, -91, 198, -121, 231, 611, 314,18078},
267 | { 38, -84, 178, -81, 153, 722, 22,17599},
268 | { 36, -76, 157, -43, 80, 824, -241,17092},
269 | { 34, -68, 135, -3, 8, 919, -476,16558},
270 | { 32, -61, 115, 34, -60, 1006, -683,16001},
271 | { 29, -52, 94, 70, -123, 1083, -862,15422},
272 | { 27, -44, 73, 106, -184, 1152,-1015,14824},
273 | { 25, -36, 53, 139, -239, 1211,-1142,14210},
274 | { 22, -27, 34, 170, -290, 1261,-1244,13582},
275 | { 20, -20, 16, 199, -335, 1301,-1322,12942},
276 | { 18, -12, -3, 226, -375, 1331,-1376,12293},
277 | { 15, -4, -19, 250, -410, 1351,-1408,11638},
278 | { 13, 3, -35, 272, -439, 1361,-1419,10979},
279 | { 11, 9, -49, 292, -464, 1362,-1410,10319},
280 | { 9, 16, -63, 309, -483, 1354,-1383, 9660},
281 | { 7, 22, -75, 322, -496, 1337,-1339, 9005},
282 | { 6, 26, -85, 333, -504, 1312,-1280, 8355},
283 | { 4, 31, -94, 341, -507, 1278,-1205, 7713},
284 | { 3, 35, -102, 347, -506, 1238,-1119, 7082},
285 | { 1, 40, -110, 350, -499, 1190,-1021, 6464},
286 | { 0, 43, -115, 350, -488, 1136, -914, 5861}
287 | };
288 |
289 | /* Shifting by pre_shift allows calculation using unsigned int rather than
290 | possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
291 | And by having pre_shift 32, a 32-bit platform can easily do the shift by
292 | simply ignoring the low half. */
293 |
294 | void blip_add_delta( blip_t* m, unsigned time, int delta )
295 | {
296 | unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
297 | buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
298 |
299 | int const phase_shift = frac_bits - phase_bits;
300 | int phase = fixed >> phase_shift & (phase_count - 1);
301 | short const* in = bl_step [phase];
302 | short const* rev = bl_step [phase_count - phase];
303 |
304 | int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
305 | int delta2 = (delta * interp) >> delta_bits;
306 | delta -= delta2;
307 |
308 | /* Fails if buffer size was exceeded */
309 | assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
310 |
311 | out [0] += in[0]*delta + in[half_width+0]*delta2;
312 | out [1] += in[1]*delta + in[half_width+1]*delta2;
313 | out [2] += in[2]*delta + in[half_width+2]*delta2;
314 | out [3] += in[3]*delta + in[half_width+3]*delta2;
315 | out [4] += in[4]*delta + in[half_width+4]*delta2;
316 | out [5] += in[5]*delta + in[half_width+5]*delta2;
317 | out [6] += in[6]*delta + in[half_width+6]*delta2;
318 | out [7] += in[7]*delta + in[half_width+7]*delta2;
319 |
320 | in = rev;
321 | out [ 8] += in[7]*delta + in[7-half_width]*delta2;
322 | out [ 9] += in[6]*delta + in[6-half_width]*delta2;
323 | out [10] += in[5]*delta + in[5-half_width]*delta2;
324 | out [11] += in[4]*delta + in[4-half_width]*delta2;
325 | out [12] += in[3]*delta + in[3-half_width]*delta2;
326 | out [13] += in[2]*delta + in[2-half_width]*delta2;
327 | out [14] += in[1]*delta + in[1-half_width]*delta2;
328 | out [15] += in[0]*delta + in[0-half_width]*delta2;
329 | }
330 |
331 | void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
332 | {
333 | unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
334 | buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
335 |
336 | int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
337 | int delta2 = delta * interp;
338 |
339 | /* Fails if buffer size was exceeded */
340 | assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
341 |
342 | out [7] += delta * delta_unit - delta2;
343 | out [8] += delta2;
344 | }
345 |
--------------------------------------------------------------------------------
/src/blip_buf.h:
--------------------------------------------------------------------------------
1 | /** \file
2 | Sample buffer that resamples from input clock rate to output sample rate */
3 |
4 | /* blip_buf $vers */
5 | #ifndef BLIP_BUF_H
6 | #define BLIP_BUF_H
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | /** First parameter of most functions is blip_t*, or const blip_t* if nothing
13 | is changed. */
14 | typedef struct blip_t blip_t;
15 |
16 | /** Creates new buffer that can hold at most sample_count samples. Sets rates
17 | so that there are blip_max_ratio clocks per sample. Returns pointer to new
18 | buffer, or NULL if insufficient memory. */
19 | blip_t* blip_new( int sample_count );
20 |
21 | /** Sets approximate input clock rate and output sample rate. For every
22 | clock_rate input clocks, approximately sample_rate samples are generated. */
23 | void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
24 |
25 | enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
26 | clock_rate must not be greater than sample_rate*blip_max_ratio. */
27 | blip_max_ratio = 1 << 20 };
28 |
29 | /** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
30 | void blip_clear( blip_t* );
31 |
32 | /** Adds positive/negative delta into buffer at specified clock time. */
33 | void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
34 |
35 | /** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
36 | void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
37 |
38 | /** Length of time frame, in clocks, needed to make sample_count additional
39 | samples available. */
40 | int blip_clocks_needed( const blip_t*, int sample_count );
41 |
42 | enum { /** Maximum number of samples that can be generated from one time frame. */
43 | blip_max_frame = 4000 };
44 |
45 | /** Makes input clocks before clock_duration available for reading as output
46 | samples. Also begins new time frame at clock_duration, so that clock time 0 in
47 | the new time frame specifies the same clock as clock_duration in the old time
48 | frame specified. Deltas can have been added slightly past clock_duration (up to
49 | however many clocks there are in two output samples). */
50 | void blip_end_frame( blip_t*, unsigned int clock_duration );
51 |
52 | /** Number of buffered samples available for reading. */
53 | int blip_samples_avail( const blip_t* );
54 |
55 | /** Reads and removes at most 'count' samples and writes them to 'out'. If
56 | 'stereo' is true, writes output to every other element of 'out', allowing easy
57 | interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
58 | samples. Returns number of samples actually read. */
59 | int blip_read_samples( blip_t*, short out [], int count, int stereo );
60 |
61 | /** Frees buffer. No effect if NULL is passed. */
62 | void blip_delete( blip_t* );
63 |
64 |
65 | /* Deprecated */
66 | typedef blip_t blip_buffer_t;
67 |
68 | #ifdef __cplusplus
69 | }
70 | #endif
71 |
72 | #endif
73 |
--------------------------------------------------------------------------------
/src/blip_buf.txt:
--------------------------------------------------------------------------------
1 | blip_buf $vers
2 | --------------
3 | Author : Shay Green
4 | Website : http://www.slack.net/~ant/
5 | License : GNU Lesser General Public License (LGPL)
6 |
7 |
8 | Contents
9 | --------
10 | * Overview
11 | * Buffer creation
12 | * Waveform generation
13 | * Time frames
14 | * Complex waveforms
15 | * Sample buffering
16 | * Thanks
17 |
18 |
19 | Overview
20 | --------
21 | This library resamples audio waveforms from input clock rate to output
22 | sample rate. Usage follows this general pattern:
23 |
24 | * Create buffer with blip_new().
25 | * Set clock rate and sample rate with blip_set_rates().
26 | * Waveform generation loop:
27 | - Generate several clocks of waveform with blip_add_delta().
28 | - End time frame with blip_end_frame().
29 | - Read samples from buffer with blip_read_samples().
30 | * Free buffer with blip_delete().
31 |
32 |
33 | Buffer creation
34 | ---------------
35 | Before synthesis, a buffer must be created with blip_new(). Its size is
36 | the maximum number of unread samples it can hold. For most uses, this
37 | can be 1/10 the sample rate or less, since samples will usually be read
38 | out immediately after being generated.
39 |
40 | After the buffer is created, the input clock rate and output sample rate
41 | must be set with blip_set_rates(). This determines how many input clocks
42 | there are per second, and how many output samples are generated per
43 | second.
44 |
45 | If the compiler supports a 64-bit integer type, then the input-output
46 | ratio is stored very accurately. If the compiler only supports a 32-bit
47 | integer type, then the ratio is stored with only 20 fraction bits, so
48 | some ratios cannot be represented exactly (for example, sample
49 | rate=48000 and clock rate=48001). The ratio is internally rounded up, so
50 | there will never be fewer than 'sample rate' samples per second. Having
51 | too many per second is generally better than having too few.
52 |
53 |
54 | Waveform generation
55 | -------------------
56 | Waveforms are generated at the input clock rate. Consider a simple
57 | square wave with 8 clocks per cycle (4 clocks high, 4 clocks low):
58 |
59 | |<-- 8 clocks ->|
60 | +5| ._._._._ ._._._._ ._._._._ ._._
61 | | | | | | | | |
62 | Amp 0|._._._._ | | | | | |
63 | | | | | | | |
64 | -5| ._._._._ ._._._._ ._._._._
65 | * . . . * . . . * . . . * . . . * . . . * . . . * . . . * .
66 | Time 0 4 8 12 16 20 24 28
67 |
68 | The wave changes amplitude at time points 0, 4, 8, 12, 16, etc.
69 |
70 | The following generates the amplitude at every clock of above waveform
71 | at the input clock rate:
72 |
73 | int wave [30];
74 |
75 | for ( int i = 4; i < 30; ++i )
76 | {
77 | if ( i % 8 < 4 )
78 | wave [i] = -5;
79 | else
80 | wave [i] = +5;
81 | }
82 |
83 | Without this library, the wave array would then need to be resampled
84 | from the input clock rate to the output sample rate. This library does
85 | this resampling internally, so it won't be discussed further; waveform
86 | generation code can focus entirely on the input clocks.
87 |
88 | Rather than specify the amplitude at every clock, this library merely
89 | needs to know the points where the amplitude CHANGES, referred to as a
90 | delta. The time of a delta is specified with a clock count. The deltas
91 | for this square wave are shown below the time points they occur at:
92 |
93 | +5| ._._._._ ._._._._ ._._._._ ._._
94 | | | | | | | | |
95 | Amp 0|._._._._ | | | | | |
96 | | | | | | | |
97 | -5| ._._._._ ._._._._ ._._._._
98 | * . . . * . . . * . . . * . . . * . . . * . . . * . . . * .
99 | Time 0 4 8 12 16 20 24 28
100 | Delta +5 -10 +10 -10 +10 -10 +10
101 |
102 | The following calls generate the above waveform:
103 |
104 | blip_add_delta( blip, 4, +5 );
105 | blip_add_delta( blip, 8, -10 );
106 | blip_add_delta( blip, 12, +10 );
107 | blip_add_delta( blip, 16, -10 );
108 | blip_add_delta( blip, 20, +10 );
109 | blip_add_delta( blip, 24, -10 );
110 | blip_add_delta( blip, 28, +10 );
111 |
112 | In the examples above, the amplitudes are small for clarity. The 16-bit
113 | sample range is -32768 to +32767, so actual waveform amplitudes would
114 | need to be in the thousands to be audible (for example, -5000 to +5000).
115 |
116 | This library allows waveform generation code to pay NO attention to the
117 | output sample rate. It can focus ENTIRELY on the essence of the
118 | waveform: the points where its amplitude changes. Since these points can
119 | be efficiently generated in a loop, synthesis is efficient. Sound chip
120 | emulation code can be structured to allow full accuracy down to a single
121 | clock, with the emulated CPU being able to simply tell the sound chip to
122 | "emulate from wherever you left off, up to clock time T within the
123 | current time frame".
124 |
125 |
126 | Time frames
127 | -----------
128 | Since time keeps increasing, if left unchecked, at some point it would
129 | overflow the range of an integer. This library's solution to the problem
130 | is to break waveform generation into time frames of moderate length.
131 | Clock counts within a time frame are thus relative to the beginning of
132 | the frame, where 0 is the beginning of the frame. When a time frame of
133 | length T is ended, what was at time T in the old time frame is now at
134 | time 0 in the new time frame. Breaking the above waveform into time
135 | frames of 10 clocks each looks like this:
136 |
137 | +5| ._._._._ ._._._._ ._._._._ ._._
138 | | | | | | | | |
139 | Amp 0|._._._._ | | | | | |
140 | | | | | | | |
141 | -5| ._._._._ ._._._._ ._._._._
142 | * . . . * . . . * . . . * . . . * . . . * . . . * . . . * .
143 | Time |0 4 8 | 2 6 |0 4 8 |
144 | | first time frame | second time frame | third time frame |
145 | |<--- 10 clocks --->|<--- 10 clocks --->|<--- 10 clocks --->|
146 |
147 | The following calls generate the above waveform. After they execute, the
148 | first 30 clocks of the waveform will have been resampled and be
149 | available as output samples for reading with blip_read_samples().
150 |
151 | blip_add_delta( blip, 4, +5 );
152 | blip_add_delta( blip, 8, -10 );
153 | blip_end_frame( blip, 10 );
154 |
155 | blip_add_delta( blip, 2, +10 );
156 | blip_add_delta( blip, 6, -10 );
157 | blip_end_frame( blip, 10 );
158 |
159 | blip_add_delta( blip, 0, +10 );
160 | blip_add_delta( blip, 4, -10 );
161 | blip_add_delta( blip, 8, +10 );
162 | blip_end_frame( blip, 10 );
163 | ...
164 |
165 | Time frames can be a convenient length, and the length can vary from one
166 | frame to the next. Once a time frame is ended, the resulting output
167 | samples become available for reading immediately, and no more deltas can
168 | be added to it.
169 |
170 | There is a limit of about 4000 output samples per time frame. The number
171 | of clocks depends on the clock rate. At common sample rates, this allows
172 | time frames of at least 1/15 second, plenty for most uses. This limit
173 | allows increased resampling ratio accuracy.
174 |
175 | In an emulator, it is usually convenient to have audio time frames
176 | correspond to video frames, where the CPU's clock counter is reset at
177 | the beginning of each video frame and thus can be used directly as the
178 | relative clock counts for audio time frames.
179 |
180 |
181 | Complex waveforms
182 | -----------------
183 | Any sort of waveform can be generated, not just a square wave. For
184 | example, a saw-like wave:
185 |
186 | +5| ._._._._ ._._._._ ._._
187 | | | | | | |
188 | Amp 0|._._._._ | ._._._._ | ._._._._
189 | | | | | |
190 | -5| ._._._._ ._._._._
191 | * . . . * . . . * . . . * . . . * . . . * . . . * . . . * .
192 | Time 0 4 8 12 16 20 24 28
193 | Delta +5 -10 +5 +5 -10 +5 +5
194 |
195 | Code to generate above waveform:
196 |
197 | blip_add_delta( blip, 4, +5 );
198 | blip_add_delta( blip, 8, -10 );
199 | blip_add_delta( blip, 12, +5 );
200 | blip_add_delta( blip, 16, +5 );
201 | blip_add_delta( blip, 20, +10 );
202 | blip_add_delta( blip, 24, +5 );
203 | blip_add_delta( blip, 28, +5 );
204 |
205 | Similarly, multiple waveforms can be added within a time frame without
206 | problem. It doesn't matter what order they're added, because all the
207 | library needs are the deltas. The synthesis code doesn't need to know
208 | all the waveforms at once either; it can calculate and add the deltas
209 | for each waveform individually. Deltas don't need to be added in
210 | chronological order either.
211 |
212 |
213 | Sample buffering
214 | ----------------
215 | Sample buffering is very flexible. Once a time frame is ended, the
216 | resampled waveforms become output samples that are immediately made
217 | available for reading with blip_read_samples(). They don't have to be
218 | read immediately; they can be allowed to accumulate in the buffer, with
219 | each time frame appending more samples to the buffer. When reading, some
220 | or all of the samples in can be read out, with the remaining unread
221 | samples staying in the buffer for later. Usually a program will
222 | immediately read all available samples after ending a time frame and
223 | play them immediately. In some systems, a program needs samples in
224 | fixed-length blocks; in that case, it would keep generating time frames
225 | until some number of samples are available, then read only that many,
226 | even if slightly more were available in the buffer.
227 |
228 | In some systems, one wants to run waveform generation for exactly the
229 | number of clocks necessary to generate some desired number of output
230 | samples, and no more. In that case, use blip_clocks_needed( blip, N ) to
231 | find out how many clocks are needed to generate N additional samples.
232 | Ending a time frame with this value will result in exactly N more
233 | samples becoming available for reading.
234 |
235 |
236 | Thanks
237 | ------
238 | Thanks to Jsr (FamiTracker author), the Mednafen team (multi-system
239 | emulator), ShizZie (Nhes GMB author), Marcel van Tongeren, Luke Molnar
240 | (UberNES author), Fredrick Meunier (Fuse contributor) for using and
241 | giving feedback for another similar library. Thanks to Disch for his
242 | interest and discussions about the synthesis algorithm itself, and for
243 | writing his own implementation of it (Schpune) rather than just using
244 | mine. Thanks to Xodnizel for Festalon, whose sound quality got me
245 | interested in video game sound emulation in the first place, and where I
246 | first came up with the algorithm while optimizing its brute-force
247 | filter.
248 |
249 | --
250 | Shay Green
251 |
--------------------------------------------------------------------------------
/src/fextra.cpp:
--------------------------------------------------------------------------------
1 | #include "fextra.h"
2 |
3 | size_t fsize(FILE* f) {
4 | size_t tell, ret;
5 | tell=ftell(f);
6 | fseek(f,0,SEEK_END);
7 | ret=ftell(f);
8 | fseek(f,tell,SEEK_SET);
9 | return ret;
10 | }
11 |
12 | short fgetsh(FILE* f) {
13 | short ret;
14 | fread(&ret,sizeof(short),1,f);
15 | return ret;
16 | }
17 |
18 | int fgeti(FILE* f) {
19 | int ret;
20 | fread(&ret,sizeof(int),1,f);
21 | return ret;
22 | }
23 |
--------------------------------------------------------------------------------
/src/fextra.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | size_t fsize(FILE* f);
4 |
5 | // READ FUNCTIONS //
6 |
7 | // reading
8 | short fgetsh(FILE* f);
9 | int fgeti(FILE* f);
10 | long long fgetll(FILE* f);
11 |
12 | // reading float/double
13 | float fgetf(FILE* f);
14 | double fgetd(FILE* f);
15 |
16 | // WRITE FUNCTIONS //
17 |
18 | // writing
19 | int fputsh(short c, FILE* f);
20 | int fputi(int c, FILE* f);
21 | int fputll(long long c, FILE* f);
22 |
23 | // writing float/double
24 | int fputf(float c, FILE* f);
25 | int fputd(double c, FILE* f);
26 |
--------------------------------------------------------------------------------
/src/fonts.h:
--------------------------------------------------------------------------------
1 | #ifndef _FONTS_H
2 | #define _FONTS_H
3 | extern const unsigned int defFont_main_compressed_size;
4 | extern const unsigned int defFont_main_compressed_data[];
5 | extern const unsigned int defFont_pat_compressed_size;
6 | extern const unsigned int defFont_pat_compressed_data[];
7 | #endif
--------------------------------------------------------------------------------
/src/hlesoundchip.cpp:
--------------------------------------------------------------------------------
1 | #include "soundchip.h"
2 | #include
3 |
4 | #ifndef M_PI
5 | #define M_PI 3.141592653589793238
6 | #endif
7 |
8 | void HLESoundchip::NextSample(short* l, short* r) {
9 | *l=0;
10 | *r=0;
11 | }
12 |
13 | void HLESoundchip::Init() {
14 | Reset();
15 | for (int i=0; i<65280; i++) {
16 | pcm[i]=0;
17 | }
18 | }
19 |
20 | void HLESoundchip::Reset() {
21 | for (int i=0; i<8; i++) {
22 | }
23 | memset(chan,0,sizeof(channel)*8);
24 | }
25 |
--------------------------------------------------------------------------------
/src/macroStatus.cpp:
--------------------------------------------------------------------------------
1 | #include "tracker.h"
2 |
3 | void MacroStatus::next() {
4 | hasChanged=false;
5 | if (macro==NULL) {
6 | pos=0;
7 | return;
8 | }
9 | if (pos>=(int)macro->cmds.size()) return;
10 | if (--waitTime>0) return;
11 |
12 | bool getOut=false;
13 | int iterations=0;
14 | while (!getOut) {
15 | pos++;
16 | if (pos>=(int)macro->cmds.size()) break;
17 | MacroCommand cmd=macro->cmds[pos];
18 | switch (cmd.type&127) {
19 | case cmdEnd:
20 | pos=macro->cmds.size();
21 | break;
22 | case cmdSet:
23 | hasChanged=true;
24 | value=cmd.value;
25 | break;
26 | case cmdWait:
27 | waitTime=cmd.value;
28 | getOut=true;
29 | break;
30 | case cmdWaitRel:
31 | if (!released) {
32 | getOut=true;
33 | pos--;
34 | }
35 | break;
36 | case cmdLoop:
37 | pos=cmd.value-1;
38 | break;
39 | case cmdLoopRel:
40 | if (!released) pos=cmd.value-1;
41 | break;
42 | case cmdAdd:
43 | hasChanged=true;
44 | value+=cmd.value;
45 | break;
46 | case cmdSub:
47 | hasChanged=true;
48 | if (value16) break;
58 | }
59 | }
60 |
61 | void MacroStatus::release() {
62 | released=true;
63 |
64 | if (macro!=NULL) {
65 | if (macro->jumpRelease>-1) {
66 | pos=macro->jumpRelease-1;
67 | }
68 | }
69 | }
70 |
71 | void MacroStatus::load(Macro* m) {
72 | macro=m;
73 | pos=-1;
74 | waitTime=0;
75 | released=false;
76 | hasChanged=false;
77 | value=0;
78 | }
79 |
80 | MacroStatus::MacroStatus() {
81 | load(NULL);
82 | }
--------------------------------------------------------------------------------
/src/nsstub.h:
--------------------------------------------------------------------------------
1 | double nsStubDPI();
2 | char* nsStubFontPath(const char* name);
3 |
--------------------------------------------------------------------------------
/src/nsstub.m:
--------------------------------------------------------------------------------
1 | #include
2 | #include "nsstub.h"
3 |
4 | // this may need to be replaced
5 | double nsStubDPI() {
6 | CGFloat val;
7 | val=[[NSScreen mainScreen] backingScaleFactor];
8 | return (double)val;
9 | }
10 |
11 | char* nsStubFontPath(const char* name) {
12 | return "";
13 | };
14 |
--------------------------------------------------------------------------------
/src/song.cpp:
--------------------------------------------------------------------------------
1 | #include "tracker.h"
2 |
3 | static Pattern emptyPat;
4 |
5 | Pattern* Song::getPattern(unsigned char num, bool create) {
6 | if (pat[num]==NULL) {
7 | if (!create) return &emptyPat;
8 | //printf("\x1b[1;32mCreating pattern %d.\x1b[m\n",num);
9 | pat[num]=new Pattern;
10 | }
11 | return pat[num];
12 | }
13 |
14 | Song::Song():
15 | version(TRACKER_VER),
16 | insC(0),
17 | patC(0),
18 | orders(0),
19 | speed(6),
20 | flags(0),
21 | tempo(0),
22 | DFM(0),
23 | channels(8),
24 | macrosC(0),
25 | globalVol(128),
26 | globalPan(128),
27 | detune(0),
28 | len(0) {
29 | memcpy(header,"TRACK8BT",8);
30 | memset(name,0,32);
31 | pcmPtr[0]=0; pcmPtr[1]=0;
32 | commentPtr[0]=0; commentPtr[1]=0;
33 | for (int i=0; i<32; i++) {
34 | defaultVol[i]=128;
35 | defaultPan[i]=((i+1)&2)?96:-96;
36 | }
37 | memset(order,0,256);
38 | for (int i=0; i<256; i++) {
39 | ins[i]=new Instrument;
40 | pat[i]=NULL;
41 | }
42 | }
43 |
44 | Song::~Song() {
45 | for (int i=0; i<256; i++) {
46 | if (ins[i]!=NULL) {
47 | delete ins[i];
48 | ins[i]=NULL;
49 | }
50 | if (pat[i]!=NULL) {
51 | //printf("\x1b[1;31mDeleting pattern %d.\x1b[m\n",i);
52 | delete pat[i];
53 | pat[i]=NULL;
54 | }
55 | }
56 | for (Macro* i: macros) {
57 | delete i;
58 | }
59 | macros.clear();
60 | }
61 |
--------------------------------------------------------------------------------
/src/soundchip.cpp:
--------------------------------------------------------------------------------
1 | #include "soundchip.h"
2 | #include
3 |
4 | #ifndef M_PI
5 | #define M_PI 3.141592653589793238
6 | #endif
7 |
8 | #define minval(a,b) (((a)<(b))?(a):(b))
9 | #define maxval(a,b) (((a)>(b))?(a):(b))
10 |
11 | void soundchip::NextSample(short* l, short* r) {
12 | for (int i=0; i<8; i++) {
13 | if (chan[i].vol==0 && !chan[i].flags.swvol) {fns[i]=0; continue;}
14 | if (chan[i].flags.pcm) {
15 | ns[i]=pcm[chan[i].pcmpos];
16 | } else switch (chan[i].flags.shape) {
17 | case 0:
18 | ns[i]=(((cycle[i]>>15)&127)>chan[i].duty)*127;
19 | break;
20 | case 1:
21 | ns[i]=cycle[i]>>14;
22 | break;
23 | case 2:
24 | ns[i]=SCsine[(cycle[i]>>14)&255];
25 | break;
26 | case 3:
27 | ns[i]=SCtriangle[(cycle[i]>>14)&255];
28 | break;
29 | case 4: case 5:
30 | ns[i]=(lfsr[i]&1)*127;
31 | break;
32 | case 6:
33 | ns[i]=((((cycle[i]>>15)&127)>chan[i].duty)*127)^(short)SCsine[(cycle[i]>>14)&255];
34 | break;
35 | case 7:
36 | ns[i]=((((cycle[i]>>15)&127)>chan[i].duty)*127)^(short)SCtriangle[(cycle[i]>>14)&255];
37 | break;
38 | }
39 |
40 | if (chan[i].flags.pcm) {
41 | if (chan[i].freq>0x8000) {
42 | pcmdec[i]+=0x8000;
43 | } else {
44 | pcmdec[i]+=chan[i].freq;
45 | }
46 | if (pcmdec[i]>=32768) {
47 | pcmdec[i]-=32768;
48 | if (chan[i].pcmpos>4)&3) {
65 | case 0:
66 | cycle[i]+=chan[i].freq*1-(chan[i].freq>>3);
67 | break;
68 | case 1:
69 | cycle[i]+=chan[i].freq*2-(chan[i].freq>>3);
70 | break;
71 | case 2:
72 | cycle[i]+=chan[i].freq*4-(chan[i].freq>>3);
73 | break;
74 | case 3:
75 | cycle[i]+=chan[i].freq*8-(chan[i].freq>>3);
76 | break;
77 | }
78 | } else {
79 | cycle[i]+=chan[i].freq;
80 | }
81 | if ((cycle[i]&0xf80000)!=(ocycle[i]&0xf80000)) {
82 | if (chan[i].flags.shape==4) {
83 | lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ^ (lfsr[i] >> 5) ) & 1)<<31);
84 | } else {
85 | switch ((chan[i].duty>>4)&3) {
86 | case 0:
87 | lfsr[i]=(lfsr[i]>>1|(((lfsr[i] >> 3) ^ (lfsr[i] >> 4) ) & 1)<<5);
88 | break;
89 | case 1:
90 | lfsr[i]=(lfsr[i]>>1|(((lfsr[i] >> 2) ^ (lfsr[i] >> 3) ) & 1)<<5);
91 | break;
92 | case 2:
93 | lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ) & 1)<<5);
94 | break;
95 | case 3:
96 | lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ^ (lfsr[i] >> 5) ) & 1)<<5);
97 | break;
98 | }
99 | if ((lfsr[i]&63)==0) {
100 | lfsr[i]=0xaaaa;
101 | }
102 | }
103 | }
104 | if (chan[i].flags.restim) {
105 | if (--rcycle[i]<=0) {
106 | cycle[i]=0;
107 | rcycle[i]=chan[i].restimer;
108 | lfsr[i]=0xaaaa;
109 | }
110 | }
111 | }
112 | //ns[i]=(char)((short)ns[i]*(short)vol[i]/256);
113 | fns[i]=ns[i]*chan[i].vol*2;
114 | if (chan[i].flags.fmode!=0) {
115 | int ff=chan[i].cutoff;
116 | nslow[i]=nslow[i]+(((ff)*nsband[i])>>16);
117 | nshigh[i]=fns[i]-nslow[i]-(((256-chan[i].reson)*nsband[i])>>8);
118 | nsband[i]=(((ff)*nshigh[i])>>16)+nsband[i];
119 | fns[i]=(((chan[i].flags.fmode&1)?(nslow[i]):(0))+((chan[i].flags.fmode&2)?(nshigh[i]):(0))+((chan[i].flags.fmode&4)?(nsband[i]):(0)));
120 | }
121 | nsL[i]=(fns[i]*SCpantabL[(unsigned char)chan[i].pan])>>8;
122 | nsR[i]=(fns[i]*SCpantabR[(unsigned char)chan[i].pan])>>8;
123 | oldfreq[i]=chan[i].freq;
124 | oldflags[i]=chan[i].flags.flags;
125 | if (chan[i].flags.swvol) {
126 | if (--swvolt[i]<=0) {
127 | swvolt[i]=chan[i].swvol.speed;
128 | if (chan[i].swvol.dir) {
129 | chan[i].vol+=chan[i].swvol.amt;
130 | if (chan[i].vol>chan[i].swvol.bound && !chan[i].swvol.loop) {
131 | chan[i].vol=chan[i].swvol.bound;
132 | }
133 | if (chan[i].vol&0x80) {
134 | if (chan[i].swvol.loop) {
135 | if (chan[i].swvol.loopi) {
136 | chan[i].swvol.dir=!chan[i].swvol.dir;
137 | chan[i].vol=0xff-chan[i].vol;
138 | } else {
139 | chan[i].vol&=~0x80;
140 | }
141 | } else {
142 | chan[i].vol=0x7f;
143 | }
144 | }
145 | } else {
146 | chan[i].vol-=chan[i].swvol.amt;
147 | if (chan[i].vol&0x80) {
148 | if (chan[i].swvol.loop) {
149 | if (chan[i].swvol.loopi) {
150 | chan[i].swvol.dir=!chan[i].swvol.dir;
151 | chan[i].vol=-chan[i].vol;
152 | } else {
153 | chan[i].vol&=~0x80;
154 | }
155 | } else {
156 | chan[i].vol=0x0;
157 | }
158 | }
159 | if (chan[i].vol(0xffff-chan[i].swfreq.amt)) {
170 | chan[i].freq=0xffff;
171 | } else {
172 | chan[i].freq=(chan[i].freq*(0x80+chan[i].swfreq.amt))>>7;
173 | if ((chan[i].freq>>8)>chan[i].swfreq.bound) {
174 | chan[i].freq=chan[i].swfreq.bound<<8;
175 | }
176 | }
177 | } else {
178 | if (chan[i].freq>8;
182 | if ((chan[i].freq>>8)(0xffff-chan[i].swcut.amt)) {
194 | chan[i].cutoff=0xffff;
195 | } else {
196 | chan[i].cutoff+=chan[i].swcut.amt;
197 | if ((chan[i].cutoff>>8)>chan[i].swcut.bound) {
198 | chan[i].cutoff=chan[i].swcut.bound<<8;
199 | }
200 | }
201 | } else {
202 | if (chan[i].cutoff>11;
206 | if ((chan[i].cutoff>>8)>2;///256;
221 | tnsR=(nsR[0]+nsR[1]+nsR[2]+nsR[3]+nsR[4]+nsR[5]+nsR[6]+nsR[7])>>2;///256;
222 |
223 | *l=minval(32767,maxval(-32767,tnsL));//(2047*(pnsL+tnsL-ppsL))>>11;
224 | *r=minval(32767,maxval(-32767,tnsR));//(2047*(pnsR+tnsR-ppsR))>>11;
225 | }
226 |
227 | void soundchip::Init() {
228 | Reset();
229 | memset(pcm,0,SOUNDCHIP_PCM_SIZE);
230 | for (int i=0; i<256; i++) {
231 | SCsine[i]=sin((i/128.0f)*M_PI)*127;
232 | SCtriangle[i]=(i>127)?(255-i):(i);
233 | SCpantabL[i]=127;
234 | SCpantabR[i]=127;
235 | }
236 | for (int i=0; i<128; i++) {
237 | SCpantabL[i]=127-i;
238 | SCpantabR[128+i]=i-1;
239 | }
240 | SCpantabR[128]=0;
241 | }
242 |
243 | void soundchip::Reset() {
244 | for (int i=0; i<8; i++) {
245 | cycle[i]=0;
246 | resetfreq[i]=0;
247 | //duty[i]=64;
248 | //pan[i]=0;
249 | //cut[i]=0;
250 | //res[i]=0;
251 | //flags[i]=0;
252 | //postvol[i]=0;
253 | voldcycles[i]=0;
254 | volicycles[i]=0;
255 | fscycles[i]=0;
256 | sweep[i]=0;
257 | ns[i]=0;
258 | swvolt[i]=1;
259 | swfreqt[i]=1;
260 | swcutt[i]=1;
261 | lfsr[i]=0xaaaa;
262 | }
263 | memset(chan,0,sizeof(channel)*8);
264 | }
265 |
266 | soundchip::soundchip() {
267 | Init();
268 | }
269 |
--------------------------------------------------------------------------------
/src/soundchip.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #define SOUNDCHIP_PCM_SIZE 65536
7 |
8 | class soundchip {
9 | signed char SCsine[256];
10 | signed char SCtriangle[256];
11 | signed char SCpantabL[256];
12 | signed char SCpantabR[256];
13 | unsigned int ocycle[8];
14 | unsigned int cycle[8];
15 | int rcycle[8];
16 | unsigned int lfsr[8];
17 | signed char ns[8];
18 | int fns[8];
19 | int nsL[8];
20 | int nsR[8];
21 | int nslow[8];
22 | int nshigh[8];
23 | int nsband[8];
24 | int tnsL, tnsR;
25 | unsigned short oldfreq[8];
26 | unsigned short oldflags[8];
27 | public:
28 | unsigned short resetfreq[8];
29 | //char pan[8];
30 | //unsigned char res[8];
31 | //char postvol[8];
32 | unsigned short voldcycles[8];
33 | unsigned short volicycles[8];
34 | unsigned short fscycles[8];
35 | unsigned char sweep[8];
36 | unsigned short swvolt[8];
37 | unsigned short swfreqt[8];
38 | unsigned short swcutt[8];
39 | //int pcmpos[8];
40 | unsigned short pcmdec[8];
41 | //int pcmend[8];
42 | //int pcmreset[8];
43 | //unsigned char pcmmult[8];
44 | struct channel {
45 | unsigned short freq;
46 | signed char vol;
47 | signed char pan;
48 | union {
49 | unsigned short flags;
50 | struct {
51 | unsigned char shape: 3;
52 | unsigned char pcm: 1;
53 | unsigned char ring: 1;
54 | unsigned char fmode: 3;
55 | unsigned char resosc: 1;
56 | unsigned char resfilt: 1;
57 | unsigned char pcmloop: 1;
58 | unsigned char restim: 1;
59 | unsigned char swfreq: 1;
60 | unsigned char swvol: 1;
61 | unsigned char swcut: 1;
62 | unsigned char padding: 1;
63 | };
64 | } flags;
65 | unsigned short cutoff;
66 | unsigned char duty;
67 | unsigned char reson;
68 | unsigned short pcmpos;
69 | unsigned short pcmbnd;
70 | unsigned short pcmrst;
71 | struct {
72 | unsigned short speed;
73 | unsigned char amt: 7;
74 | unsigned char dir: 1;
75 | unsigned char bound;
76 | } swfreq;
77 | struct {
78 | unsigned short speed;
79 | unsigned char amt: 5;
80 | unsigned char dir: 1;
81 | unsigned char loop: 1;
82 | unsigned char loopi: 1;
83 | unsigned char bound;
84 | } swvol;
85 | struct {
86 | unsigned short speed;
87 | unsigned char amt: 7;
88 | unsigned char dir: 1;
89 | unsigned char bound;
90 | } swcut;
91 | unsigned short wc;
92 | unsigned short restimer;
93 | } chan[8];
94 | signed char pcm[SOUNDCHIP_PCM_SIZE];
95 | void NextSample(short* l, short* r);
96 | void Init();
97 | void Reset();
98 | soundchip();
99 | };
100 |
101 | class HLESoundchip: public soundchip {
102 | public:
103 | void NextSample(short* l, short* r);
104 | void Init();
105 | void Reset();
106 | };
107 |
--------------------------------------------------------------------------------
/src/ssbench.cpp:
--------------------------------------------------------------------------------
1 | // specs2 soundchip sequence interpreter... benchmark!
2 | #include "soundchip.h"
3 | #include "ssinter.h"
4 | #include
5 | #include
6 | #include
7 | #include
8 | #ifdef _WIN32
9 | #else
10 | #include
11 | #endif
12 |
13 | bool quit;
14 |
15 | soundchip sc;
16 |
17 | double targetSR;
18 |
19 | double noProc;
20 |
21 | double procPos;
22 | int ticks, speed;
23 |
24 | FILE* f;
25 | int frame;
26 |
27 | SSInter s;
28 |
29 | size_t fsize;
30 |
31 | float resa0[2], resa1[2];
32 |
33 | #define resaf 0.33631372025095791864295318996109
34 |
35 | std::string str;
36 |
37 | int main(int argc, char** argv) {
38 | int which;
39 | sc.Init();
40 | procPos=0;
41 | frame=0;
42 | ticks=0;
43 | resa0[0]=0; resa0[1]=0;
44 | resa1[0]=0; resa1[1]=0;
45 |
46 | quit=false;
47 |
48 | if (argc<2) {
49 | printf("usage: %s [-n] file\n",argv[0]);
50 | return 1;
51 | }
52 | targetSR=297500; // PAL.
53 | speed=119000; // PAL.
54 | which=1;
55 |
56 | s.init(&sc);
57 |
58 | if (strcmp(argv[1],"-n")==0) {
59 | which=2;
60 | targetSR=309000; // NTSC.
61 | speed=103103; // NTSC. 103000 for no colorburst compensation
62 | }
63 |
64 | if ((f=fopen(argv[which],"rb"))==NULL) {
65 | printf("not exist\n");
66 | return 1;
67 | }
68 |
69 | fseek(f,0,SEEK_END);
70 | fsize=ftell(f);
71 | fseek(f,0,SEEK_SET);
72 |
73 | printf("start!\n");
74 |
75 | for (int i=0; i<8; i++) {
76 | sc.chan[i].pan=0;
77 | sc.chan[i].duty=0x3f;
78 | }
79 |
80 | short temp[2];
81 | int wc;
82 | int writable;
83 | while (!quit) {
84 | ticks-=20; // 20 CPU cycles per sound output cycle
85 | if (ticks<=0) {
86 | str="";
87 | while ((wc=fgetc(f))!=EOF) {
88 | str+=wc;
89 | if (wc=='R') break;
90 | }
91 | if (feof(f)) quit=true;
92 | writable=0;
93 | s.next(str.c_str(),writable,str.size());
94 | ticks+=speed;
95 | frame++;
96 | }
97 | sc.NextSample(&temp[0],&temp[1]);
98 | resa0[0]=resa0[0]+resaf*(temp[0]-resa0[0]);
99 | resa1[0]=resa1[0]+resaf*(resa0[0]-resa1[0]);
100 | resa1[0]=resa1[0]+resaf*(resa0[0]-resa1[0]);
101 | resa1[0]=resa1[0]+resaf*(resa0[0]-resa1[0]);
102 |
103 | resa0[1]=resa0[1]+resaf*(temp[1]-resa0[1]);
104 | resa1[1]=resa1[1]+resaf*(resa0[1]-resa1[1]);
105 | resa1[1]=resa1[1]+resaf*(resa0[1]-resa1[1]);
106 | resa1[1]=resa1[1]+resaf*(resa0[1]-resa1[1]);
107 | }
108 |
109 | printf("end!\n");
110 | return 0;
111 | }
112 |
--------------------------------------------------------------------------------
/src/ssinter.cpp:
--------------------------------------------------------------------------------
1 | // specs2 soundchip sequence interpreter...
2 | #include "soundchip.h"
3 | #include "ssinter.h"
4 |
5 | // maximum permissible notes
6 | unsigned short noteFreqs[12]={
7 | 0x7344,
8 | 0x7a1e,
9 | 0x8161,
10 | 0x8913,
11 | 0x913a,
12 | 0x99dc,
13 | 0xa302,
14 | 0xacb4,
15 | 0xb6f9,
16 | 0xc1da,
17 | 0xcd61,
18 | 0xd998
19 | };
20 |
21 | int decHex(int ch) {
22 | switch (ch) {
23 | case '0':
24 | case '1':
25 | case '2':
26 | case '3':
27 | case '4':
28 | case '5':
29 | case '6':
30 | case '7':
31 | case '8':
32 | case '9':
33 | return ch-'0';
34 | break;
35 | case 'A':
36 | case 'B':
37 | case 'C':
38 | case 'D':
39 | case 'E':
40 | case 'F':
41 | return 10+ch-'A';
42 | break;
43 | case 'a':
44 | case 'b':
45 | case 'c':
46 | case 'd':
47 | case 'e':
48 | case 'f':
49 | return 10+ch-'a';
50 | break;
51 | }
52 | return 0;
53 | }
54 |
55 | int bufchar(const char* buf, size_t tell, size_t bound) {
56 | if (tell>=bound) return EOF;
57 | return buf[tell];
58 | }
59 |
60 | #define _NEXT_ bufchar(buf,set++,size)
61 |
62 | // returns false if end of stream
63 | bool SSInter::next(const char* buf, int& set, size_t size) {
64 | char temp;
65 | int c;
66 | if ((unsigned)set>=size) {
67 | return false;
68 | }
69 | while ((unsigned)setchan[curChan],0,32);
74 | out->chan[curChan].duty=0x3f;
75 | break;
76 | case '$':
77 | temp=_NEXT_;
78 | if (temp=='x') {
79 | curChan=prefChan;
80 | } else {
81 | curChan=(temp-'0')&7;
82 | }
83 | break;
84 | case 'V':
85 | out->chan[curChan].vol=(decHex(_NEXT_)<<4);
86 | out->chan[curChan].vol+=decHex(_NEXT_);
87 | break;
88 | case 'Y':
89 | out->chan[curChan].duty=(decHex(_NEXT_)<<4);
90 | out->chan[curChan].duty+=decHex(_NEXT_);
91 | break;
92 | case 'f':
93 | out->chan[curChan].freq=(decHex(_NEXT_)<<12);
94 | out->chan[curChan].freq+=(decHex(_NEXT_)<<8);
95 | out->chan[curChan].freq+=(decHex(_NEXT_)<<4);
96 | out->chan[curChan].freq+=decHex(_NEXT_);
97 | break;
98 | case 'S':
99 | out->chan[curChan].flags.shape=_NEXT_-'0';
100 | break;
101 | case 'I':
102 | out->chan[curChan].flags.fmode=_NEXT_-'0';
103 | break;
104 | case 'c':
105 | out->chan[curChan].cutoff=(decHex(_NEXT_)<<12);
106 | out->chan[curChan].cutoff+=(decHex(_NEXT_)<<8);
107 | out->chan[curChan].cutoff+=(decHex(_NEXT_)<<4);
108 | out->chan[curChan].cutoff+=decHex(_NEXT_);
109 | break;
110 | case 'r':
111 | out->chan[curChan].reson=(decHex(_NEXT_)<<4);
112 | out->chan[curChan].reson+=decHex(_NEXT_);
113 | break;
114 | case 'M':
115 | temp=(_NEXT_-'0')&7;
116 | out->chan[curChan].flags.swvol=!!(temp&1);
117 | out->chan[curChan].flags.swfreq=!!(temp&2);
118 | out->chan[curChan].flags.swcut=!!(temp&4);
119 | break;
120 | case 'v':
121 | out->chan[curChan].swvol.speed=(decHex(_NEXT_)<<12);
122 | out->chan[curChan].swvol.speed+=(decHex(_NEXT_)<<8);
123 | out->chan[curChan].swvol.speed+=(decHex(_NEXT_)<<4);
124 | out->chan[curChan].swvol.speed+=decHex(_NEXT_);
125 | temp=(decHex(_NEXT_)<<4);
126 | temp+=decHex(_NEXT_);
127 | out->chan[curChan].swvol.amt=temp&0x1f;
128 | out->chan[curChan].swvol.dir=!!(temp&0x20);
129 | out->chan[curChan].swvol.loop=!!(temp&0x40);
130 | out->chan[curChan].swvol.loopi=!!(temp&0x80);
131 | out->chan[curChan].swvol.bound=(decHex(_NEXT_)<<4);
132 | out->chan[curChan].swvol.bound+=decHex(_NEXT_);
133 | break;
134 | case 'k':
135 | out->chan[curChan].swfreq.speed=(decHex(_NEXT_)<<12);
136 | out->chan[curChan].swfreq.speed+=(decHex(_NEXT_)<<8);
137 | out->chan[curChan].swfreq.speed+=(decHex(_NEXT_)<<4);
138 | out->chan[curChan].swfreq.speed+=decHex(_NEXT_);
139 | temp=(decHex(_NEXT_)<<4);
140 | temp+=decHex(_NEXT_);
141 | out->chan[curChan].swfreq.amt=temp&0x7f;
142 | out->chan[curChan].swfreq.dir=!!(temp&0x80);
143 | out->chan[curChan].swfreq.bound=(decHex(_NEXT_)<<4);
144 | out->chan[curChan].swfreq.bound+=decHex(_NEXT_);
145 | break;
146 | case 'l':
147 | out->chan[curChan].swcut.speed=(decHex(_NEXT_)<<12);
148 | out->chan[curChan].swcut.speed+=(decHex(_NEXT_)<<8);
149 | out->chan[curChan].swcut.speed+=(decHex(_NEXT_)<<4);
150 | out->chan[curChan].swcut.speed+=decHex(_NEXT_);
151 | temp=(decHex(_NEXT_)<<4);
152 | temp+=decHex(_NEXT_);
153 | out->chan[curChan].swcut.amt=temp&0x7f;
154 | out->chan[curChan].swcut.dir=!!(temp&0x80);
155 | out->chan[curChan].swcut.bound=(decHex(_NEXT_)<<4);
156 | out->chan[curChan].swcut.bound+=decHex(_NEXT_);
157 | break;
158 | case 'O':
159 | octave=_NEXT_-'0';
160 | if (octave<0) octave=0;
161 | if (octave>7) octave=7;
162 | break;
163 | case 'C':
164 | out->chan[curChan].freq=noteFreqs[0]>>(7-octave);
165 | break;
166 | case 'D':
167 | out->chan[curChan].freq=noteFreqs[2]>>(7-octave);
168 | break;
169 | case 'E':
170 | out->chan[curChan].freq=noteFreqs[4]>>(7-octave);
171 | break;
172 | case 'F':
173 | out->chan[curChan].freq=noteFreqs[5]>>(7-octave);
174 | break;
175 | case 'G':
176 | out->chan[curChan].freq=noteFreqs[7]>>(7-octave);
177 | break;
178 | case 'A':
179 | out->chan[curChan].freq=noteFreqs[9]>>(7-octave);
180 | break;
181 | case 'B':
182 | out->chan[curChan].freq=noteFreqs[11]>>(7-octave);
183 | break;
184 | case '#':
185 | c=_NEXT_;
186 | switch (c) {
187 | case 'C':
188 | out->chan[curChan].freq=noteFreqs[1]>>(7-octave);
189 | break;
190 | case 'D':
191 | out->chan[curChan].freq=noteFreqs[3]>>(7-octave);
192 | break;
193 | case 'F':
194 | out->chan[curChan].freq=noteFreqs[6]>>(7-octave);
195 | break;
196 | case 'G':
197 | out->chan[curChan].freq=noteFreqs[8]>>(7-octave);
198 | break;
199 | case 'A':
200 | out->chan[curChan].freq=noteFreqs[10]>>(7-octave);
201 | break;
202 | }
203 | break;
204 | }
205 | if (c=='R' || c==';') break;
206 | }
207 | return true;
208 | };
209 |
210 | void SSInter::setChan(int ch) {
211 | prefChan=ch;
212 | }
213 |
214 | void SSInter::init(soundchip* where) {
215 | out=where;
216 | }
217 |
--------------------------------------------------------------------------------
/src/ssinter.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | class soundchip;
5 |
6 | class SSInter {
7 | soundchip* out;
8 | int octave;
9 | int curChan;
10 | int prefChan;
11 | public:
12 | bool next(const char* buf, int& set, size_t size);
13 | void setChan(int ch);
14 | void init(soundchip* where);
15 | SSInter(): out(NULL), octave(4), curChan(0), prefChan(0) {}
16 | };
17 |
--------------------------------------------------------------------------------
/src/sslisp.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | // ssinter tiny Lisp interpreter
4 |
--------------------------------------------------------------------------------
/src/ssmain.cpp:
--------------------------------------------------------------------------------
1 | // specs2 soundchip sequence interpreter...
2 | #include "soundchip.h"
3 | #include "ssinter.h"
4 | #include
5 | #include
6 | #include
7 | #include
8 | #ifdef _WIN32
9 | #include
10 | #else
11 | #include
12 | #endif
13 |
14 | #ifdef JACK
15 | #include
16 |
17 | jack_client_t* ac;
18 | jack_port_t* ao[2];
19 | jack_status_t as;
20 | #else
21 | #ifdef HAVE_GUI
22 | #include
23 | #else
24 | #include
25 | #endif
26 | SDL_AudioDeviceID ai;
27 | SDL_AudioSpec ac;
28 | SDL_AudioSpec ar;
29 | #endif
30 |
31 | bool quit, viewMemory;
32 |
33 | int sr;
34 |
35 | soundchip sc;
36 |
37 | double targetSR;
38 |
39 | double noProc;
40 |
41 | double procPos;
42 | int ticks, speed;
43 |
44 | FILE* f;
45 | int frame;
46 |
47 | SSInter s;
48 |
49 | size_t fsize;
50 |
51 | float resa0[2], resa1[2];
52 |
53 | #define resaf 0.33631372025095791864295318996109
54 |
55 | std::string str;
56 |
57 | #ifdef JACK
58 | int process(jack_nframes_t nframes, void* arg) {
59 | #else
60 | static void process(void* userdata, Uint8* stream, int len) {
61 | #endif
62 | float* buf[2];
63 | short temp[2];
64 | int wc;
65 | int writable;
66 | #ifdef JACK
67 | for (int i=0; i<2; i++) {
68 | buf[i]=(float*)jack_port_get_buffer(ao[i],nframes);
69 | }
70 | #else
71 | unsigned int nframes=len/(sizeof(float)*ar.channels);
72 | buf[0]=(float*)stream;
73 | buf[1]=&buf[0][1];
74 | #endif
75 |
76 | for (size_t i=0; i=1) {
134 | procPos-=1;
135 | i++;
136 | }
137 | }
138 | #ifdef JACK
139 | return 0;
140 | #endif
141 | }
142 |
143 | int main(int argc, char** argv) {
144 | int which;
145 | sc.Init();
146 | procPos=0;
147 | frame=0;
148 | ticks=0;
149 | resa0[0]=0; resa0[1]=0;
150 | resa1[0]=0; resa1[1]=0;
151 |
152 | quit=false;
153 | viewMemory=false;
154 |
155 | if (argc<2) {
156 | printf("usage: %s [-n] file\n",argv[0]);
157 | return 1;
158 | }
159 | targetSR=297500; // PAL.
160 | speed=119000; // PAL.
161 | which=1;
162 |
163 | s.init(&sc);
164 |
165 | if (strcmp(argv[1],"-n")==0) {
166 | which=2;
167 | targetSR=309000; // NTSC.
168 | speed=103103; // NTSC. 103000 for no colorburst compensation
169 | }
170 |
171 | if ((f=fopen(argv[which],"rb"))==NULL) {
172 | printf("not exist\n");
173 | return 1;
174 | }
175 |
176 | fseek(f,0,SEEK_END);
177 | fsize=ftell(f);
178 | fseek(f,0,SEEK_SET);
179 |
180 | printf("opening audio\n");
181 |
182 | for (int i=0; i<8; i++) {
183 | sc.chan[i].pan=0;
184 | sc.chan[i].duty=0x3f;
185 | }
186 |
187 | #ifdef JACK
188 | ac=jack_client_open("ssinter",JackNullOption,&as);
189 | if (ac==NULL) return 1;
190 |
191 | sr=jack_get_sample_rate(ac);
192 |
193 | noProc=sr/targetSR;
194 |
195 | jack_set_process_callback(ac,process,NULL);
196 |
197 | ao[0]=jack_port_register(ac,"outL",JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0);
198 | ao[1]=jack_port_register(ac,"outR",JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0);
199 |
200 | jack_activate(ac);
201 |
202 | jack_connect(ac,"ssinter:outL","system:playback_1");
203 | jack_connect(ac,"ssinter:outR","system:playback_2");
204 | #else
205 | SDL_Init(SDL_INIT_AUDIO);
206 |
207 | ac.freq=44100;
208 | ac.format=AUDIO_F32;
209 | ac.channels=2;
210 | ac.samples=1024;
211 | ac.callback=process;
212 | ac.userdata=NULL;
213 | printf("hmm\n");
214 | ai=SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0,0),0,&ac,&ar,SDL_AUDIO_ALLOW_ANY_CHANGE);
215 | printf("works\n");
216 | sr=ar.freq;
217 | noProc=sr/targetSR;
218 |
219 | SDL_PauseAudioDevice(ai,0);
220 | #endif
221 |
222 | while (!quit) {
223 | #ifdef _WIN32
224 | Sleep(50);
225 | #else
226 | usleep(50000);
227 | #endif
228 | }
229 |
230 | #ifdef JACK
231 | jack_deactivate(ac);
232 | #else
233 | SDL_CloseAudioDevice(ai);
234 | #endif
235 | return 0;
236 | }
237 |
238 | #ifdef _WIN32
239 | #include "winMain.cpp"
240 | #endif
241 |
--------------------------------------------------------------------------------
/src/tests/duty:
--------------------------------------------------------------------------------
1 | $0f0800V7fR
2 | R
3 | R
4 | R
5 | R
6 | R
7 | R
8 | R
9 | $0f1000V7fR
10 | R
11 | R
12 | R
13 | R
14 | R
15 | R
16 | R
17 | $0f1800V7fR
18 | R
19 | R
20 | R
21 | R
22 | R
23 | R
24 | R
25 | $0f2000V7fR
26 | R
27 | R
28 | R
29 | R
30 | R
31 | R
32 | R
33 | $0f0800V7fY07R
34 | R
35 | R
36 | R
37 | R
38 | R
39 | R
40 | R
41 | $0f1000V7fY0fR
42 | R
43 | R
44 | R
45 | R
46 | R
47 | R
48 | R
49 | $0f1800V7fY1fR
50 | R
51 | R
52 | R
53 | R
54 | R
55 | R
56 | R
57 | $0f2000V7fY2fR
58 | R
59 | R
60 | R
61 | R
62 | R
63 | R
64 | R
65 |
--------------------------------------------------------------------------------
/src/tests/fdistort:
--------------------------------------------------------------------------------
1 | $0S1f0800V7fR
2 | R
3 | R
4 | R
5 | R
6 | R
7 | R
8 | R
9 | $0f1000V7fR
10 | R
11 | R
12 | R
13 | R
14 | R
15 | R
16 | R
17 | $0f1800V7fR
18 | R
19 | R
20 | R
21 | R
22 | R
23 | R
24 | R
25 | $0f2000V7fR
26 | R
27 | R
28 | R
29 | R
30 | R
31 | R
32 | R
33 | $0f0800V7fI1c8000r00M4l00100110R
34 | R
35 | R
36 | R
37 | R
38 | R
39 | R
40 | R
41 | $0f1000V7fc8000R
42 | R
43 | R
44 | R
45 | R
46 | R
47 | R
48 | R
49 | $0f1800V7fc8000R
50 | R
51 | R
52 | R
53 | R
54 | R
55 | R
56 | R
57 | $0f2000V7fR
58 | R
59 | R
60 | R
61 | R
62 | R
63 | R
64 | R
65 | $0f0800V7fI1c3000rf0M4l00100110R
66 | R
67 | R
68 | R
69 | R
70 | R
71 | R
72 | R
73 | $0f1000V7fc2000R
74 | R
75 | R
76 | R
77 | R
78 | R
79 | R
80 | R
81 | $0f1800V7fc1000R
82 | R
83 | R
84 | R
85 | R
86 | R
87 | R
88 | R
89 | $0f2000V7fc2000R
90 | R
91 | R
92 | R
93 | R
94 | R
95 | R
96 | R
97 |
--------------------------------------------------------------------------------
/src/tests/filter:
--------------------------------------------------------------------------------
1 | $0S4f8000V7f;;;;;;
2 |
--------------------------------------------------------------------------------
/src/tests/fsweep:
--------------------------------------------------------------------------------
1 | $0f0800V7fR
2 | R
3 | R
4 | R
5 | R
6 | R
7 | R
8 | R
9 | $0f1000V7fR
10 | R
11 | R
12 | R
13 | R
14 | R
15 | R
16 | R
17 | $0f1800V7fR
18 | R
19 | R
20 | R
21 | R
22 | R
23 | R
24 | R
25 | $0f2000V7fR
26 | R
27 | R
28 | R
29 | R
30 | R
31 | R
32 | R
33 | $0f0800V7fI1c8000r7fM4l00100110R
34 | R
35 | R
36 | R
37 | R
38 | R
39 | R
40 | R
41 | $0f1000V7fc8000R
42 | R
43 | R
44 | R
45 | R
46 | R
47 | R
48 | R
49 | $0f1800V7fc8000R
50 | R
51 | R
52 | R
53 | R
54 | R
55 | R
56 | R
57 | $0f2000V7fR
58 | R
59 | R
60 | R
61 | R
62 | R
63 | R
64 | R
65 |
--------------------------------------------------------------------------------
/src/tests/fuzzie:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tildearrow/soundtracker/4240845b5e00510128240222ce66d87fbe71daf7/src/tests/fuzzie
--------------------------------------------------------------------------------
/src/tests/psweep:
--------------------------------------------------------------------------------
1 | $0f0800V7fR
2 | R
3 | R
4 | R
5 | R
6 | R
7 | R
8 | R
9 | $0f1000V7fR
10 | R
11 | R
12 | R
13 | R
14 | R
15 | R
16 | R
17 | $0f1800V7fR
18 | R
19 | R
20 | R
21 | R
22 | R
23 | R
24 | R
25 | $0f2000V7fR
26 | R
27 | R
28 | R
29 | R
30 | R
31 | R
32 | R
33 | $0f0800V7fM2k01000006R
34 | R
35 | R
36 | R
37 | R
38 | R
39 | R
40 | R
41 | $0f1000V7fR
42 | R
43 | R
44 | R
45 | R
46 | R
47 | R
48 | R
49 | $0f1800V7fR
50 | R
51 | R
52 | R
53 | R
54 | R
55 | R
56 | R
57 | $0f2000V7fR
58 | R
59 | R
60 | R
61 | R
62 | R
63 | R
64 | R
65 | $0f0800V7fM2k020081ffR
66 | R
67 | R
68 | R
69 | R
70 | R
71 | R
72 | R
73 | $0f1000V7fR
74 | R
75 | R
76 | R
77 | R
78 | R
79 | R
80 | R
81 | $0f1800V7fR
82 | R
83 | R
84 | R
85 | R
86 | R
87 | R
88 | R
89 | $0f2000V7fR
90 | R
91 | R
92 | R
93 | R
94 | R
95 | R
96 | R
97 | $0f0800V7fM2k40007f04R
98 | R
99 | R
100 | R
101 | R
102 | R
103 | R
104 | R
105 | $0f1000V7fR
106 | R
107 | R
108 | R
109 | R
110 | R
111 | R
112 | R
113 | $0f1800V7fR
114 | R
115 | R
116 | R
117 | R
118 | R
119 | R
120 | R
121 | $0f2000V7fR
122 | R
123 | R
124 | R
125 | R
126 | R
127 | R
128 | R
129 |
--------------------------------------------------------------------------------
/src/tests/shape:
--------------------------------------------------------------------------------
1 | $0f0800V7fRRRRRRRR
2 | $0f1000V7fRRRRRRRR
3 | $0f1800V7fRRRRRRRR
4 | $0f2000V7fRRRRRRRR
5 | $0S1f0800V7fRRRRRRRR
6 | $0f1000V7fRRRRRRRR
7 | $0f1800V7fRRRRRRRR
8 | $0f2000V7fRRRRRRRR
9 | $0S2f0800V7fRRRRRRRR
10 | $0f1000V7fRRRRRRRR
11 | $0f1800V7fRRRRRRRR
12 | $0f2000V7fRRRRRRRR
13 | $0S3f0800V7fRRRRRRRR
14 | $0f1000V7fRRRRRRRR
15 | $0f1800V7fRRRRRRRR
16 | $0f2000V7fRRRRRRRR
17 | $0S4f0800V7fRRRRRRRR
18 | $0f1000V7fRRRRRRRR
19 | $0f1800V7fRRRRRRRR
20 | $0f2000V7fRRRRRRRR
21 | $0S5f0800V7fRRRRRRRR
22 | $0f1000V7fRRRRRRRR
23 | $0f1800V7fRRRRRRRR
24 | $0f2000V7fRRRRRRRR
25 | $0Y0ff0800V7fRRRRRRRR
26 | $0f1000V7fRRRRRRRR
27 | $0f1800V7fRRRRRRRR
28 | $0f2000V7fRRRRRRRR
29 | $0Y1ff0400V7fRRRRRRRR
30 | $0f0800V7fRRRRRRRR
31 | $0f0c00V7fRRRRRRRR
32 | $0f1000V7fRRRRRRRR
33 | $0Y2ff0200V7fRRRRRRRR
34 | $0f0400V7fRRRRRRRR
35 | $0f0600V7fRRRRRRRR
36 | $0f0800V7fRRRRRRRR
37 | $0S6f0800V7fRRRRRRRR
38 | $0f1000V7fRRRRRRRR
39 | $0f1800V7fRRRRRRRR
40 | $0f2000V7fRRRRRRRR
41 | $0S7f0800V7fRRRRRRRR
42 | $0f1000V7fRRRRRRRR
43 | $0f1800V7fRRRRRRRR
44 | $0f2000V7fRRRRRRRR
45 |
--------------------------------------------------------------------------------
/src/tests/vsweep:
--------------------------------------------------------------------------------
1 | $0f0800V7fR
2 | R
3 | R
4 | R
5 | R
6 | R
7 | R
8 | R
9 | $0f1000V7fR
10 | R
11 | R
12 | R
13 | R
14 | R
15 | R
16 | R
17 | $0f1800V7fR
18 | R
19 | R
20 | R
21 | R
22 | R
23 | R
24 | R
25 | $0f2000V7fR
26 | R
27 | R
28 | R
29 | R
30 | R
31 | R
32 | R
33 | $0f0800V7fM1v00880100R
34 | R
35 | R
36 | R
37 | R
38 | R
39 | R
40 | R
41 | $0f1000V7fR
42 | R
43 | R
44 | R
45 | R
46 | R
47 | R
48 | R
49 | $0f1800V7fR
50 | R
51 | R
52 | R
53 | R
54 | R
55 | R
56 | R
57 | $0f2000V7fR
58 | R
59 | R
60 | R
61 | R
62 | R
63 | R
64 | R
65 | $0f0800V7fM1v00084100R
66 | R
67 | R
68 | R
69 | R
70 | R
71 | R
72 | R
73 | $0f1000V7fR
74 | R
75 | R
76 | R
77 | R
78 | R
79 | R
80 | R
81 | $0f1800V7fR
82 | R
83 | R
84 | R
85 | R
86 | R
87 | R
88 | R
89 | $0f2000V7fR
90 | R
91 | R
92 | R
93 | R
94 | R
95 | R
96 | R
97 | $0f0400V7fM1v0010c300R
98 | R
99 | R
100 | R
101 | R
102 | R
103 | R
104 | R
105 | R
106 | R
107 | R
108 | R
109 | R
110 | R
111 | R
112 | R
113 | R
114 | R
115 | R
116 | R
117 | R
118 | R
119 | R
120 |
--------------------------------------------------------------------------------
/src/tracker.h:
--------------------------------------------------------------------------------
1 | // new tracker code
2 | #ifndef _TRACKER_H
3 | #define _TRACKER_H
4 | #include
5 | #include
6 | #include
7 |
8 | #ifdef HAVE_GUI
9 | #include
10 | #else
11 | #include
12 | #endif
13 | #ifdef ANDROID
14 | #define ANDRO
15 | #endif
16 | #ifdef _WIN32
17 | #include
18 | #include
19 | #else
20 | #if !defined(__APPLE__) && !defined(ANDROID)
21 | #include
22 | #endif
23 | #include
24 | #include
25 | #endif
26 | #ifdef __APPLE__
27 | extern "C" {
28 | #include "nsstub.h"
29 | }
30 | #endif
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include "fextra.h"
39 | #include "soundchip.h"
40 |
41 | // format version
42 | #define TRACKER_VER 153
43 | // actual version
44 | #define TRACKER_FULLVER "v1.0pre"
45 |
46 | #define minval(a,b) (((a)<(b))?(a):(b)) // for Linux compatibility
47 | #define maxval(a,b) (((a)>(b))?(a):(b)) // for Linux compatibility
48 |
49 | #include "utfutils.h"
50 |
51 | bool PIR(float x1, float y1, float x2, float y2, float checkx, float checky);
52 |
53 | enum SupportedFormats {
54 | FormatUnknown=-1,
55 |
56 | FormatTRACK=0,
57 | FormatTRACKINS,
58 | FormatMOD,
59 | FormatS3M,
60 | FormatIT,
61 | FormatXM,
62 | FormatAudio,
63 | };
64 |
65 | struct Point {
66 | float x, y;
67 | };
68 |
69 | struct Color {
70 | float r, g, b, a;
71 | Color():
72 | r(0),
73 | g(0),
74 | b(0),
75 | a(1) {}
76 | explicit Color(unsigned char re, unsigned char gr, unsigned char bl):
77 | r((float)re/255.0f),
78 | g((float)gr/255.0f),
79 | b((float)bl/255.0f),
80 | a(1.0f) {}
81 | explicit Color(unsigned char re, unsigned char gr, unsigned char bl, unsigned char al):
82 | r((float)re/255.0f),
83 | g((float)gr/255.0f),
84 | b((float)bl/255.0f),
85 | a((float)al/255.0f) {}
86 | explicit Color(float re, float gr, float bl):
87 | r(re),
88 | g(gr),
89 | b(bl),
90 | a(1.0f) {}
91 | explicit Color(float re, float gr, float bl, float al):
92 | r(re),
93 | g(gr),
94 | b(bl),
95 | a(al) {}
96 | };
97 |
98 | struct Texture {
99 | SDL_Texture* actual;
100 | int w, h;
101 | Texture(): actual(NULL), w(0), h(0) {}
102 | };
103 |
104 | enum UIType {
105 | UIClassic=0,
106 | UIModern,
107 | UIMobile
108 | };
109 |
110 | extern int scrW, scrH;
111 |
112 | class PopupBox {
113 | string title;
114 | string content;
115 |
116 | bool show;
117 |
118 | public:
119 | void hide() {
120 | show=false;
121 | }
122 |
123 | bool isVisible() {
124 | return show;
125 | }
126 |
127 | void draw() {
128 | }
129 |
130 | //content("Lorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem.")
131 |
132 | PopupBox(string t, string c):
133 | title(t),
134 | content(c),
135 | show(true) {}
136 |
137 | PopupBox(bool s):
138 | title("Message"),
139 | content("Lorem ipsum, quia dolor sit, amet."),
140 | show(s) {}
141 |
142 |
143 | PopupBox():
144 | title("Message"),
145 | content("Lorem ipsum, quia dolor sit, amet."),
146 | show(true) {}
147 | };
148 |
149 | // NEW STUFF BEGIN //
150 | struct LegacyInstrument {
151 | char name[32];
152 | unsigned char id, pcmMult, activeEnv;
153 | unsigned char env[8];
154 | unsigned char noteOffset;
155 | unsigned char FPt, FPR, DFM, LFO;
156 | unsigned char vol;
157 | signed char pitch;
158 | unsigned short pcmLen, filterH;
159 | unsigned char res;
160 | unsigned char pcmPos[2]; // alignment
161 | unsigned char pcmLoop[2];
162 | unsigned char FTm;
163 | unsigned short ver;
164 | unsigned char flags, RMf;
165 | };
166 |
167 | struct Instrument {
168 | char name[32];
169 | unsigned char id, pcmMult;
170 | short volMacro, cutMacro, resMacro, pitchMacro;
171 | unsigned char unused1, noteOffset;
172 | unsigned char FPt, FPR, filterMode, LFO;
173 | unsigned char vol;
174 | signed char pitch;
175 | unsigned short pcmLen, filterH;
176 | unsigned char res, FTm;
177 | unsigned short pcmPos;
178 | unsigned short pcmLoop;
179 | unsigned short ver;
180 | unsigned char flags, RMf;
181 | short finePitchMacro, shapeMacro, dutyMacro, panMacro, filterModeMacro, volSweepMacro, freqSweepMacro, cutSweepMacro;
182 | short pcmPosMacro;
183 | unsigned short unused2;
184 | unsigned int unused3[3];
185 | Instrument():
186 | id(0),
187 | pcmMult(0),
188 | volMacro(-1), cutMacro(-1), resMacro(-1), pitchMacro(-1),
189 | unused1(0),
190 | noteOffset(48),
191 | FPt(0),
192 | FPR(0),
193 | filterMode(0),
194 | LFO(0),
195 | vol(64),
196 | pitch(0),
197 | pcmLen(0),
198 | filterH(0),
199 | res(0),
200 | FTm(0),
201 | pcmPos(0),
202 | pcmLoop(0),
203 | ver(TRACKER_VER),
204 | flags(0),
205 | RMf(0),
206 | finePitchMacro(-1), shapeMacro(-1), dutyMacro(-1), panMacro(-1),
207 | filterModeMacro(-1), volSweepMacro(-1), freqSweepMacro(-1), cutSweepMacro(-1),
208 | pcmPosMacro(-1), unused2(0) {
209 | memset(name,0,32);
210 | unused3[0]=0;
211 | unused3[1]=0;
212 | unused3[2]=0;
213 | }
214 | };
215 |
216 | enum MacroCommandType {
217 | cmdEnd=0,
218 | cmdSet,
219 | cmdWait,
220 | cmdWaitRel,
221 | cmdLoop,
222 | cmdLoopRel,
223 | cmdAdd,
224 | cmdSub,
225 |
226 | cmdMax
227 | };
228 |
229 | enum MacroIntendedUse {
230 | iuGeneric,
231 | iuShape,
232 | iuPitch,
233 | iuPan,
234 | iuVolSweep,
235 | iuOtherSweep,
236 |
237 | iuMax
238 | };
239 |
240 | struct MacroCommand {
241 | unsigned char type;
242 | unsigned int value;
243 | MacroCommand(unsigned char t, int v, bool endTick):
244 | type(t|(endTick<<7)),
245 | value(v) {}
246 | };
247 |
248 | struct Macro {
249 | int jumpRelease;
250 | unsigned char intendedUse;
251 | std::vector cmds;
252 | Macro():
253 | jumpRelease(-1),
254 | intendedUse(iuGeneric) {}
255 | };
256 |
257 | struct Pattern {
258 | unsigned short length;
259 | unsigned char data[256][32][8];
260 |
261 | Pattern(): length(64) {
262 | memset(data,0,256*32*8);
263 | }
264 | };
265 |
266 | struct Song {
267 | char header[8];
268 | unsigned short version;
269 | unsigned char insC, patC, orders, speed, flags, tempo;
270 | char name[32];
271 | unsigned char DFM, channels;
272 | unsigned short macrosC;
273 | unsigned char globalVol, globalPan;
274 | unsigned short pcmPtr[2];
275 | unsigned short commentPtr[2];
276 | signed char detune;
277 | unsigned char len;
278 | unsigned char defaultVol[32];
279 | signed char defaultPan[32];
280 | unsigned char order[256];
281 | Instrument* ins[256];
282 | Pattern* pat[256];
283 | std::vector macros;
284 |
285 | Pattern* getPattern(unsigned char num, bool create);
286 |
287 | Song();
288 | ~Song();
289 | };
290 |
291 | class Player;
292 |
293 | class MacroStatus {
294 | Macro* macro;
295 | int pos, waitTime;
296 | bool released;
297 | public:
298 | bool hasChanged;
299 | unsigned int value;
300 |
301 | void next();
302 | void release();
303 | void load(Macro* m);
304 | MacroStatus();
305 | };
306 |
307 | struct ChannelStatus {
308 | bool active, noteOn;
309 | float note;
310 | short instr;
311 | short vol, channelVol;
312 | short envVol;
313 | short finePitch;
314 | unsigned char fx, fxVal;
315 | unsigned char arp, arpValue;
316 | unsigned char volSlide;
317 | signed char channelPan;
318 | unsigned char cutTimer, rowDelay;
319 |
320 | bool volChanged, freqChanged, panChanged;
321 |
322 | float slideSpeed;
323 | float portaSpeed, portaTarget;
324 |
325 | unsigned char vibPos, vibSpeed, vibDepth;
326 | float vibValue;
327 |
328 | unsigned char tremPos, tremSpeed, tremDepth;
329 | float tremValue;
330 |
331 | unsigned char panbPos, panbSpeed, panbDepth;
332 | float panbValue;
333 |
334 | MacroStatus macroVol;
335 | MacroStatus macroCut;
336 | MacroStatus macroRes;
337 | MacroStatus macroDuty;
338 | MacroStatus macroShape;
339 | MacroStatus macroPitch;
340 | MacroStatus macroFinePitch;
341 | MacroStatus macroPan;
342 | MacroStatus macroFilterMode;
343 | MacroStatus macroVolSweep;
344 | MacroStatus macroFreqSweep;
345 | MacroStatus macroCutSweep;
346 | MacroStatus macroPCM;
347 |
348 | ChannelStatus():
349 | active(false),
350 | noteOn(false),
351 | note(0),
352 | instr(0),
353 | vol(0),
354 | channelVol(128),
355 | envVol(255),
356 | finePitch(0),
357 | fx(0),
358 | fxVal(0),
359 | arpValue(0),
360 | volSlide(0),
361 | channelPan(0),
362 | cutTimer(0),
363 | rowDelay(0),
364 | volChanged(false),
365 | freqChanged(false),
366 | panChanged(false),
367 | slideSpeed(0),
368 | portaSpeed(0),
369 | portaTarget(0),
370 | vibPos(0),
371 | vibSpeed(0),
372 | vibDepth(0),
373 | vibValue(0),
374 | tremPos(0),
375 | tremSpeed(0),
376 | tremDepth(0),
377 | tremValue(0),
378 | panbPos(0),
379 | panbSpeed(0),
380 | panbDepth(0),
381 | panbValue(0) {}
382 | };
383 |
384 | struct ScheduledNote {
385 | int chan, ins, note;
386 | ScheduledNote(int c, int i, int n):
387 | chan(c),
388 | ins(i),
389 | note(n) {}
390 | };
391 |
392 | class Player {
393 | Song* song;
394 | soundchip* chip;
395 |
396 | std::queue scheduledNotes;
397 |
398 | public:
399 | int pat, step, tick, playMode;
400 | int speed, tempo, nextJump, nextJumpStep;
401 | int patLoopPos, patLoopCount;
402 | bool ntsc;
403 | ChannelStatus chan[32];
404 | bool channelMask[32];
405 |
406 | unsigned int getNoteFreq(float note);
407 | unsigned int getNotePeriod(float note);
408 |
409 | float offsetNote(float note, unsigned char off);
410 |
411 | void testNoteOn(int channel, int ins, int note);
412 | void testNoteOff(int channel);
413 | void noteOn(int channel, int note);
414 | void noteOff(int channel);
415 | void noteCut(int channel);
416 | void noteAftertouch(int channel, int val);
417 | void noteProgramChange(int channel, int val);
418 | void notePanChange(int channel, signed char val);
419 |
420 | void processChanRow(Pattern* pat, int channel);
421 | void nextRow();
422 |
423 | void maskChannel(int channel, bool mask);
424 | void toggleChannel(int channel);
425 |
426 | void update();
427 | void reset();
428 | void panic();
429 | void play();
430 | void stop();
431 |
432 | void setSong(Song* s);
433 | void bindChips(soundchip* s);
434 |
435 | Player();
436 | };
437 |
438 | // NEW STUFF END //
439 | #endif
440 |
--------------------------------------------------------------------------------
/src/unifontfull.h:
--------------------------------------------------------------------------------
1 | extern const unsigned char unifont_bin[2097152];
2 | extern const unsigned char unifont_siz[8192];
3 |
--------------------------------------------------------------------------------
/src/utfutils.cpp:
--------------------------------------------------------------------------------
1 | #include "tracker.h"
2 |
3 | int decodeUTF8(const unsigned char* data, char& len) {
4 | int ret=0xfffd;
5 | if (data[0]<0x80) {
6 | ret=data[0];
7 | len=1;
8 | } else if (data[0]<0xc0) {
9 | ret=0xfffd; // invalid
10 | len=1;
11 | } else if (data[0]<0xe0) {
12 | if (data[1]>=0x80 && data[1]<0xc0) {
13 | len=2;
14 | ret=((data[0]&31)<<6)|
15 | (data[1]&63);
16 | } else len=1;
17 | } else if (data[0]<0xf0) {
18 | if (data[1]>=0x80 && data[1]<0xc0) {
19 | if (data[2]>=0x80 && data[2]<0xc0) {
20 | len=3;
21 | ret=((data[0]&15)<<12)|
22 | ((data[1]&63)<<6)|
23 | (data[2]&63);
24 | } else len=2;
25 | } else len=1;
26 | } else if (data[0]<0xf5) {
27 | if (data[1]>=0x80 && data[1]<0xc0) {
28 | if (data[2]>=0x80 && data[2]<0xc0) {
29 | if (data[3]>=0x80 && data[3]<0xc0) {
30 | len=4;
31 | ret=((data[0]&7)<<18)|
32 | ((data[1]&63)<<12)|
33 | ((data[2]&63)<<6)|
34 | (data[3]&63);
35 | } else len=3;
36 | } else len=2;
37 | } else len=1;
38 | } else {
39 | len=1;
40 | return 0xfffd;
41 | }
42 |
43 | if ((ret>=0xd800 && ret<=0xdfff) || ret>=0x110000) return 0xfffd;
44 | return ret;
45 | }
46 |
47 | size_t utf8len(const char* s) {
48 | size_t p=0;
49 | size_t r=0;
50 | char cl;
51 | while (s[p]!=0) {
52 | r++;
53 | decodeUTF8((const unsigned char*)&s[p],cl);
54 | p+=cl;
55 | }
56 | return r;
57 | }
58 |
59 | char utf8csize(const unsigned char* c) {
60 | char ret;
61 | decodeUTF8(c,ret);
62 | return ret;
63 | }
64 |
65 | wstring utf8To16(const char* s) {
66 | wstring ret;
67 | int ch, p;
68 | char chs;
69 | p=0;
70 | while (s[p]!=0) {
71 | ch=decodeUTF8((const unsigned char*)&s[p],chs);
72 | ret+=(unsigned short)ch;
73 | p+=chs;
74 | }
75 | return ret;
76 | }
77 |
78 | string utf16To8(const wchar_t* s) {
79 | string ret;
80 | for (size_t i=0; i>6)&31));
85 | ret+=(0x80+((s[i])&63));
86 | } else {
87 | ret+=(0xe0+((s[i]>>12)&15));
88 | ret+=(0x80+((s[i]>>6)&63));
89 | ret+=(0x80+((s[i])&63));
90 |
91 | }
92 | }
93 | return ret;
94 | }
95 |
--------------------------------------------------------------------------------
/src/utfutils.h:
--------------------------------------------------------------------------------
1 | #ifndef _UTFUTILS_H
2 | #define _UTFUTILS_H
3 | #include
4 |
5 | typedef std::string string;
6 | typedef std::wstring wstring;
7 | #define S(x) string(x)
8 |
9 | size_t utf8len(const char* s);
10 | size_t utf8clen(const char* s);
11 | size_t utf8pos(const char* s, size_t inpos);
12 | size_t utf8cpos(const char* s, size_t inpos);
13 | size_t utf8findcpos(const char* s, float inpos);
14 | char utf8csize(const unsigned char* c);
15 |
16 | wstring utf8To16(const char* in);
17 | string utf16To8(const wchar_t* in);
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/src/winMain.cpp:
--------------------------------------------------------------------------------
1 | #include "utfutils.h"
2 |
3 | int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, PSTR args, int state) {
4 | int argc=0;
5 | wchar_t** argw=CommandLineToArgvW(GetCommandLineW(),&argc);
6 | char** argv=new char*[argc+1];
7 | argv[argc]=NULL;
8 | for (int i=0; i
2 | #include
3 |
4 | FILE* f;
5 | FILE* out;
6 | FILE* sout;
7 |
8 | char str[256];
9 |
10 | unsigned char glyph[64];
11 | int glyphSize;
12 |
13 | int glyphIndex;
14 |
15 | unsigned char glyphSizes[8192];
16 |
17 | char char2hex(char c) {
18 | if (c>='0' && c<='9') {
19 | return c-'0';
20 | }
21 | if (c>='A' && c<='F') {
22 | return 10+c-'A';
23 | }
24 | if (c>='a' && c<='f') {
25 | return 10+c-'a';
26 | }
27 | return -1;
28 | }
29 |
30 | int main(int argc, char** argv) {
31 | if (argc<4) {
32 | printf("usage: %s in out sizeout\n",argv[0]);
33 | return 1;
34 | }
35 | f=fopen(argv[1],"r");
36 | if (f==NULL) {
37 | perror("in");
38 | return 1;
39 | }
40 |
41 | out=fopen(argv[2],"wb");
42 | if (out==NULL) {
43 | perror("out");
44 | return 1;
45 | }
46 |
47 | sout=fopen(argv[3],"wb");
48 | if (sout==NULL) {
49 | perror("out");
50 | return 1;
51 | }
52 |
53 | memset(glyphSizes,0,8192);
54 |
55 | int h=0;
56 | while (!feof(f)) {
57 | fgets(str,255,f);
58 | glyphIndex=0;
59 | glyphSize=0;
60 | h=0;
61 | do {
62 | if (str[h]==':') break;
63 | glyphIndex<<=4;
64 | glyphIndex|=char2hex(str[h]);
65 | } while (++h);
66 | if (glyphIndex>0xffff) {
67 | break;
68 | }
69 | memset(glyph,0,32);
70 | h++;
71 | do {
72 | if (str[h]=='\n' || str[h]==0) break;
73 | glyph[glyphSize>>1]<<=4;
74 | glyph[glyphSize>>1]|=char2hex(str[h]);
75 | glyphSize++;
76 | } while (++h);
77 | glyphSize>>=1;
78 | // write a 16x16 glyph regardless
79 | fseek(out,glyphIndex*32,SEEK_SET);
80 | if (glyphSize==32) {
81 | fwrite(glyph,1,32,out);
82 | } else {
83 | for (int i=0; i<16; i++) {
84 | fputc(glyph[i],out);
85 | fputc(0,out);
86 | }
87 | }
88 |
89 | if (glyphSize>16) {
90 | glyphSizes[glyphIndex>>3]|=(1<<(glyphIndex&7));
91 | } else {
92 | glyphSizes[glyphIndex>>3]&=~(1<<(glyphIndex&7));
93 | }
94 | }
95 | fseek(out,2097151,SEEK_SET);
96 | fputc(0,out);
97 |
98 | fwrite(glyphSizes,1,8192,sout);
99 |
100 | fclose(f);
101 | fclose(out);
102 | fclose(sout);
103 | return 0;
104 | }
105 |
--------------------------------------------------------------------------------