initial commit
This commit is contained in:
20
BitBoxWin32/BitBoxWin32.sln
Normal file
20
BitBoxWin32/BitBoxWin32.sln
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BitBoxWin32", "BitBoxWin32\BitBoxWin32.vcproj", "{AB70AF1C-0C19-41FC-A6A0-3B89E3EC7868}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AB70AF1C-0C19-41FC-A6A0-3B89E3EC7868}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AB70AF1C-0C19-41FC-A6A0-3B89E3EC7868}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AB70AF1C-0C19-41FC-A6A0-3B89E3EC7868}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{AB70AF1C-0C19-41FC-A6A0-3B89E3EC7868}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
73
BitBoxWin32/BitBoxWin32/3D.h
Normal file
73
BitBoxWin32/BitBoxWin32/3D.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef _3D_H_
|
||||
#define _3D_H_
|
||||
|
||||
#include <nds.h>
|
||||
|
||||
// Commands
|
||||
#define CMTXMODE 0x10
|
||||
#define CMTXPUSH 0x11
|
||||
#define CMTXPOP 0x12
|
||||
#define CMTXIDENTITY 0x15
|
||||
#define CMTXLOAD4x4 0x16
|
||||
#define CMTXLOAD4x3 0x17
|
||||
#define CMTXMULT3x3 0x1A
|
||||
#define CMTXSCALE 0x1B
|
||||
#define CMTXTRANSLATE 0x1C
|
||||
#define CCOLOR 0x20
|
||||
#define CNORMAL 0x21
|
||||
#define CVERTEX 0x24
|
||||
#define CPOLYATTR 0x29
|
||||
#define CDIFAMB 0x30
|
||||
#define CLIGHTVECTOR 0x32
|
||||
#define CLIGHTCOLOR 0x33
|
||||
#define CBEGIN 0x40
|
||||
#define CVIEWPORT 0x60
|
||||
|
||||
// Parameters
|
||||
#define PROJECTION 0
|
||||
#define MODELVIEW 2
|
||||
|
||||
#define QUAD 1
|
||||
|
||||
#define NORMAL(x,y,z) (((x)&0x3FF)|(((y)&0x3FF)<<10)|(((z)&0x3FF)<<20))
|
||||
#define VERTEX(x,y,z) \
|
||||
(((x)&0x3FF)|(((y)&0x3FF)<<10)|(((z)&0x3FF)<<20))
|
||||
|
||||
#define DIFAMB(dif,amb) ((dif)|((amb)<<16))
|
||||
|
||||
#define VIEWPORT(x1,y1,x2,y2) ((x1)|((y1)<<8)|((x2)<<16)|((y2)<<24))
|
||||
|
||||
// Polygon attributes
|
||||
#define LIGHT0 BIT(0)
|
||||
#define POLYFRONT BIT(7)
|
||||
#define POLYBACK BIT(6)
|
||||
#define SOLID (31<<16)
|
||||
#define ALPHA(a) ((a)<<16)
|
||||
#define WIREFRAME (0<<16)
|
||||
|
||||
// GX FIFO command packer
|
||||
#define COMMAND(a,b,c,d) \
|
||||
(((a)&0xFF)|(((b)&0xFF)<<8)|(((c)&0xFF)<<16)|(((d)&0xFF)<<24))
|
||||
|
||||
void call_list(u32 * list, int size);
|
||||
|
||||
#define push() MATRIX_PUSH = 0
|
||||
#define pop() MATRIX_POP = 1
|
||||
#define identity() MATRIX_IDENTITY = 0
|
||||
#define swap() GFX_FLUSH = 0
|
||||
#define translate(x, y, z) \
|
||||
MATRIX_TRANSLATE = x; \
|
||||
MATRIX_TRANSLATE = y; \
|
||||
MATRIX_TRANSLATE = z
|
||||
#define scale(x, y, z) \
|
||||
MATRIX_SCALE = x; \
|
||||
MATRIX_SCALE = y; \
|
||||
MATRIX_SCALE = z
|
||||
|
||||
void rotate(int angle, int v);
|
||||
|
||||
#define rotateX(angle) rotate(angle, 1)
|
||||
#define rotateY(angle) rotate(angle, 2)
|
||||
#define rotateZ(angle) rotate(angle, 3)
|
||||
|
||||
#endif // _3D_H_
|
||||
267
BitBoxWin32/BitBoxWin32/BitBoxWin32.vcproj
Normal file
267
BitBoxWin32/BitBoxWin32/BitBoxWin32.vcproj
Normal file
@@ -0,0 +1,267 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="BitBoxWin32"
|
||||
ProjectGUID="{AB70AF1C-0C19-41FC-A6A0-3B89E3EC7868}"
|
||||
RootNamespace="BitBoxWin32"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\tools\tracker\packages\portaudio\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="opengl32.lib portaudio_x86.lib sdl.lib sdlmain.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="..\..\tools\tracker\packages\portaudio"
|
||||
GenerateManifest="true"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="portaudio\include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="portaudio"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Fichiers sources"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\main.cpp"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Synth"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\channel.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\channel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\midi.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\midi.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\psg.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\psg.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\synth.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\synth.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tune.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tune.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Video"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\3D.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\options.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\trig.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\trig.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Fichiers d'en-t<>te"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Fichiers de ressources"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
36
BitBoxWin32/BitBoxWin32/channel.cpp
Normal file
36
BitBoxWin32/BitBoxWin32/channel.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "channel.h"
|
||||
|
||||
Channel::Channel()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void Channel::reset()
|
||||
{
|
||||
duty = 0;
|
||||
dec = 4;
|
||||
for ( int i = 0 ; i < MAXROWS ; i++ ) {
|
||||
notes[i].volume = 10;
|
||||
notes[i].note = 60;
|
||||
notes[i].active = false;
|
||||
}
|
||||
lastRow = 0;
|
||||
}
|
||||
|
||||
void Channel::setNote(int pos, int volume, int note)
|
||||
{
|
||||
notes[pos].volume = volume;
|
||||
notes[pos].note = note;
|
||||
notes[pos].active = true;
|
||||
|
||||
if ( pos > lastRow )
|
||||
lastRow = pos;
|
||||
}
|
||||
|
||||
void Channel::deleteNote(int pos)
|
||||
{
|
||||
notes[pos].active = false;
|
||||
if ( pos == lastRow )
|
||||
while ( lastRow > 0 && notes[lastRow].active == false )
|
||||
lastRow--;
|
||||
}
|
||||
28
BitBoxWin32/BitBoxWin32/channel.h
Normal file
28
BitBoxWin32/BitBoxWin32/channel.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _CHANNEL_H_
|
||||
#define _CHANNEL_H_
|
||||
|
||||
#define MAXROWS 2048
|
||||
|
||||
struct Note {
|
||||
int volume;
|
||||
int note; // midi note number
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
int duty;
|
||||
int dec;
|
||||
Note notes[MAXROWS];
|
||||
|
||||
int lastRow;
|
||||
|
||||
Channel();
|
||||
|
||||
void reset();
|
||||
|
||||
void setNote(int pos, int volume, int note);
|
||||
void setNote(int pos, Note & note) { setNote(pos, note.volume, note.note); }
|
||||
void deleteNote(int pos);
|
||||
};
|
||||
|
||||
#endif // _CHANNEL_H_
|
||||
8949
BitBoxWin32/BitBoxWin32/glext.h
Normal file
8949
BitBoxWin32/BitBoxWin32/glext.h
Normal file
File diff suppressed because it is too large
Load Diff
692
BitBoxWin32/BitBoxWin32/main.cpp
Normal file
692
BitBoxWin32/BitBoxWin32/main.cpp
Normal file
@@ -0,0 +1,692 @@
|
||||
#include <SDL.h>
|
||||
#include <windows.h>
|
||||
#include <GL/gl.h>
|
||||
#include "trig.h"
|
||||
#include "glext.h"
|
||||
|
||||
#include "tune.h"
|
||||
#include "synth.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define WIDTH 800
|
||||
#define HEIGHT 600
|
||||
|
||||
Uint32 timer(Uint32 interval, void * param)
|
||||
{
|
||||
Synth * synth = (Synth *) param;
|
||||
|
||||
static int lastRow = -42;
|
||||
int currentRow = synth->getCurrentRow();
|
||||
if ( currentRow != lastRow ) {
|
||||
lastRow = currentRow;
|
||||
}
|
||||
|
||||
// Detect end of song and stop synth
|
||||
int end = 0;
|
||||
for ( int i = 0 ; i < 8 ; i++ )
|
||||
if ( currentRow > synth->getTune()->channels[i].lastRow
|
||||
&& synth->getVolume(i) == 0 )
|
||||
end++;
|
||||
else
|
||||
break;
|
||||
if ( end == 8 )
|
||||
synth->stop(false);
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
PFNGLCREATESHADERPROC glCreateShader = 0;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram = 0;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram = 0;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram = 0;
|
||||
PFNGLDETACHSHADERPROC glDetachShader = 0;
|
||||
PFNGLATTACHSHADERPROC glAttachShader = 0;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram = 0;
|
||||
PFNGLDELETESHADERPROC glDeleteShader = 0;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource = 0;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader = 0;
|
||||
GLuint fsh;
|
||||
const GLchar* fshSource = "void main()\
|
||||
{\
|
||||
ivec3 i = ivec3(gl_Color * 63.0);\
|
||||
gl_FragColor = vec4(ivec3(vec3(i/63.0) * 31.0) / 31.0, 1.0);\
|
||||
}";
|
||||
GLuint program;
|
||||
|
||||
void InitVideo()
|
||||
{
|
||||
glClearColor(0, 0, 0, 1.0f);
|
||||
glClearDepth(1.0f);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
//glEnable(GL_POLYGON_SMOOTH);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glPolygonMode(GL_FRONT, GL_FILL);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
float matrix[4*4] =
|
||||
{
|
||||
6587/4096.0f, 0, 0, 0,
|
||||
0, 8783/4096.0f, 0, 0,
|
||||
0, 0, -4116/4096.0f, -4096/4096.0f,
|
||||
0, 0, -821/4096.0f, 0,
|
||||
};
|
||||
glLoadMatrixf(matrix);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
static float diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
|
||||
static float position[] = { 2.0f, 4.0f, 2.0f };
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, position);
|
||||
|
||||
glCreateShader = (PFNGLCREATESHADERPROC) wglGetProcAddress("glCreateShader");
|
||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC) wglGetProcAddress("glCreateProgram");
|
||||
glLinkProgram = (PFNGLLINKPROGRAMPROC) wglGetProcAddress("glLinkProgram");
|
||||
glUseProgram = (PFNGLUSEPROGRAMPROC) wglGetProcAddress("glUseProgram");
|
||||
glDetachShader = (PFNGLDETACHSHADERPROC) wglGetProcAddress("glDetachShader");
|
||||
glAttachShader = (PFNGLATTACHSHADERPROC) wglGetProcAddress("glAttachShader");
|
||||
glDeleteProgram = (PFNGLDELETEPROGRAMPROC) wglGetProcAddress("glDeleteProgram");
|
||||
glDeleteShader = (PFNGLDELETESHADERPROC) wglGetProcAddress("glDeleteShader");
|
||||
glShaderSource = (PFNGLSHADERSOURCEPROC) wglGetProcAddress("glShaderSource");
|
||||
glCompileShader = (PFNGLCOMPILESHADERPROC) wglGetProcAddress("glCompileShader");
|
||||
|
||||
fsh = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fsh, 1, & fshSource, 0);
|
||||
glCompileShader(fsh);
|
||||
program = glCreateProgram();
|
||||
glAttachShader(program, fsh);
|
||||
glLinkProgram(program);
|
||||
}
|
||||
|
||||
int fade_current = 31 << 2; // starts white
|
||||
int fade_target = 16 << 2;
|
||||
|
||||
void cube()
|
||||
{
|
||||
glUseProgram(program);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glColor3f(0.5f, 0.5f, 0.5f);
|
||||
glBegin(GL_QUADS);
|
||||
glNormal3f(0.0f, 0.0f, 1.0f);
|
||||
glVertex3f(-1.0f, -1.0f, 1.0f);
|
||||
glVertex3f( 1.0f, -1.0f, 1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, 1.0f);
|
||||
glVertex3f(-1.0f, 1.0f, 1.0f);
|
||||
|
||||
glNormal3f(0.0f, 0.0f, -1.0f);
|
||||
glVertex3f(-1.0f, -1.0f, -1.0f);
|
||||
glVertex3f(-1.0f, 1.0f, -1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, -1.0f);
|
||||
glVertex3f( 1.0f, -1.0f, -1.0f);
|
||||
|
||||
glNormal3f(0.0f, -1.0f, 0.0f);
|
||||
glVertex3f(-1.0f, -1.0f, -1.0f);
|
||||
glVertex3f( 1.0f, -1.0f, -1.0f);
|
||||
glVertex3f( 1.0f, -1.0f, 1.0f);
|
||||
glVertex3f(-1.0f, -1.0f, 1.0f);
|
||||
|
||||
glNormal3f(0.0f, 1.0f, 0.0f);
|
||||
glVertex3f(-1.0f, 1.0f, -1.0f);
|
||||
glVertex3f(-1.0f, 1.0f, 1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, 1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, -1.0f);
|
||||
|
||||
glNormal3f(-1.0f, 0.0f, 0.0f);
|
||||
glVertex3f(-1.0f, -1.0f, -1.0f);
|
||||
glVertex3f(-1.0f, -1.0f, 1.0f);
|
||||
glVertex3f(-1.0f, 1.0f, 1.0f);
|
||||
glVertex3f(-1.0f, 1.0f, -1.0f);
|
||||
|
||||
glNormal3f(1.0f, 0.0f, 0.0f);
|
||||
glVertex3f( 1.0f, -1.0f, -1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, -1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, 1.0f);
|
||||
glVertex3f( 1.0f, -1.0f, 1.0f);
|
||||
glEnd();
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
#define RGB15(r, g, b) ((r)|((g)<<5)|((b)<<10))
|
||||
#define RED(rgb) ( rgb & 0x1F )
|
||||
#define GREEN(rgb) ((rgb>>5)&0x1F)
|
||||
#define BLUE(rgb) ((rgb>>10)&0x1F)
|
||||
|
||||
#define identity glLoadIdentity
|
||||
#define push glPushMatrix
|
||||
#define pop glPopMatrix
|
||||
#define translate(x, y, z) glTranslatef((x) / 4096.0f, (y) / 4096.0f, (z) / 4096.0f)
|
||||
#define scale(x, y, z) glScalef((x) / 4096.0f, (y) / 4096.0f, (z) / 4096.0f)
|
||||
|
||||
#define rotateX(a) rotate(a, 0)
|
||||
#define rotateY(a) rotate(a, 1)
|
||||
#define rotateZ(a) rotate(a, 2)
|
||||
|
||||
void rotate(int a, int v)
|
||||
{
|
||||
float angle = a / 12867.0f * 180.0f;
|
||||
|
||||
if ( v == 1 )
|
||||
glRotatef(angle, 0, 1, 0);
|
||||
else if ( v == 2 )
|
||||
glRotatef(angle, 0, 0, 1);
|
||||
else
|
||||
glRotatef(angle, 1, 0, 0);
|
||||
}
|
||||
|
||||
int uber_sin(int x)
|
||||
{
|
||||
int ax;
|
||||
x = 4096 - (x & 0x1FFF);
|
||||
ax = x;
|
||||
if ( ax < 0 )
|
||||
ax = -ax;
|
||||
return 4 * x - ((4 * x * ax) >> 12);
|
||||
}
|
||||
|
||||
void arms(int t, int m)
|
||||
{
|
||||
push();
|
||||
// translate(0.24f*m, 0.4f, 0);
|
||||
translate(983*m, 1638, 0);
|
||||
// rotateZ(30<33>*m);
|
||||
rotateZ(2145*m);
|
||||
// rotateX(cos(t)*20<32>+180<38>);
|
||||
rotateX(((cos(t)*1430)>>12)+12868);
|
||||
// translate(0, 0.3, 0);
|
||||
translate(0, 1229, 0);
|
||||
push();
|
||||
// scale(0.1, 0.3, 0.1);
|
||||
scale(410, 1229, 410);
|
||||
cube();
|
||||
pop();
|
||||
|
||||
// translate(0, 0.22, 0);
|
||||
translate(0, 901, 0);
|
||||
// rotateY(abs(cos(t))*16*m);
|
||||
int act = cos(t)*1144;
|
||||
if ( act < 0 )
|
||||
act = -act;
|
||||
rotateY((act>>12)*m);
|
||||
// rotateX(100<30>);
|
||||
rotateX(7149);
|
||||
// rotateZ(165<36>*m);
|
||||
rotateZ(11796*m);
|
||||
// translate(0, 0.21, 0);
|
||||
translate(0, 860, 0);
|
||||
push();
|
||||
// scale(0.09, 0.27, 0.09);
|
||||
scale(369, 1106, 369);
|
||||
cube();
|
||||
pop();
|
||||
pop();
|
||||
}
|
||||
|
||||
void legs(int t, int m)
|
||||
{
|
||||
push();
|
||||
translate(778*m, 0, -61);
|
||||
rotateX(((cos(t)*929)>>12)-228); // 929->1024 = -12 bytes !
|
||||
|
||||
translate(0, -2867, 0);
|
||||
push();
|
||||
scale(410, 1024, 410);
|
||||
cube();
|
||||
pop();
|
||||
|
||||
int d = -cos(t+6434);
|
||||
if ( d < 0 )
|
||||
d = 0;
|
||||
translate(0, ((d*512)>>12)-2130, ((d*61)>>12)-246);
|
||||
rotateX(715);
|
||||
push();
|
||||
scale(410, 1229, 410);
|
||||
cube();
|
||||
pop();
|
||||
|
||||
translate(0, -1229, 410);
|
||||
push();
|
||||
scale(410, 123, 819);
|
||||
cube();
|
||||
pop();
|
||||
pop();
|
||||
}
|
||||
|
||||
void robot(int t, int T)
|
||||
{
|
||||
#define robot_fall_speed 2048
|
||||
#define robot_start 40
|
||||
t *= 402;
|
||||
|
||||
// ast = |sin(t)|
|
||||
int ast = sin(t);
|
||||
if ( ast < 0 )
|
||||
ast = -ast;
|
||||
|
||||
// act = |cos(t)|
|
||||
int act = cos(t);
|
||||
if ( act < 0 )
|
||||
act = -act;
|
||||
|
||||
int fall;
|
||||
|
||||
// head
|
||||
push();
|
||||
// translate(0, 0.71+0.05*abs(sin(t)), 0.04);
|
||||
fall = (robot_start+88)*robot_fall_speed - T*robot_fall_speed;
|
||||
if ( fall < 0 )
|
||||
fall = 0;
|
||||
translate(0, 2908+((ast*204)>>12)+fall, 164);
|
||||
// rotateX(-5<>+10<31>*abs(cos(t)));
|
||||
rotateX((-357+715*act)>>12);
|
||||
// scale(0.2, 0.2, 0.2);
|
||||
scale(819, 819, 819);
|
||||
cube();
|
||||
pop();
|
||||
|
||||
// body
|
||||
push();
|
||||
// translate(0, 0.05*abs(sin(t)), 0);
|
||||
fall = (robot_start+48)*robot_fall_speed - T*robot_fall_speed;
|
||||
if ( fall < 0 )
|
||||
fall = 0;
|
||||
translate(0, ((ast*204)>>12)+fall, 0);
|
||||
// rotateY(2.5<EFBFBD>-5<>*cos(t));
|
||||
rotateY(179-((357*cos(t))>>12));
|
||||
// scale(0.3, 0.5, 0.17);
|
||||
scale(1229, 2048, 696);
|
||||
cube();
|
||||
pop();
|
||||
|
||||
// left side
|
||||
push();
|
||||
fall = (robot_start+56)*robot_fall_speed - T*robot_fall_speed;
|
||||
if ( fall < 0 )
|
||||
fall = 0;
|
||||
translate(0, fall, 0);
|
||||
arms(t, -1);
|
||||
pop();
|
||||
|
||||
push();
|
||||
fall = (robot_start+8)*robot_fall_speed - T*robot_fall_speed;
|
||||
if ( fall < 0 )
|
||||
fall = 0;
|
||||
translate(0, fall, 0);
|
||||
legs(t, -1);
|
||||
pop();
|
||||
|
||||
// right side
|
||||
t += 12868;
|
||||
push();
|
||||
fall = (robot_start+64)*robot_fall_speed - T*robot_fall_speed;
|
||||
if ( fall < 0 )
|
||||
fall = 0;
|
||||
translate(0, fall, 0);
|
||||
arms(t, 1);
|
||||
pop();
|
||||
|
||||
push();
|
||||
fall = (robot_start+24)*robot_fall_speed - T*robot_fall_speed;
|
||||
if ( fall < 0 )
|
||||
fall = 0;
|
||||
translate(0, fall, 0);
|
||||
legs(t, 1);
|
||||
pop();
|
||||
}
|
||||
|
||||
// r * cos((x*pi/2)/r) * cos((y*pi/2)/r) - r
|
||||
// returns a fixed point altitude value in fx.6
|
||||
int f(int x, int y)
|
||||
{
|
||||
const int r = 32;
|
||||
// const int _r = (int)((0.5f/(float)r)*64.0f); // == 1 ...
|
||||
// x = (x*_r);
|
||||
// y = (y*_r);
|
||||
return ((r * (uber_cos(x) * uber_cos(y))>>18)) - (r<<6);
|
||||
}
|
||||
|
||||
void sonic(int t)
|
||||
{
|
||||
int i = 0;
|
||||
int y, x;
|
||||
|
||||
rotateX(-1024);
|
||||
|
||||
if ( t < 256 )
|
||||
t = 0;
|
||||
else
|
||||
t = -(t*2)&127;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for ( y = -7*64+t ; y < 6*64+t ; y += 64 ) {
|
||||
for ( x = -7*64 ; x < 6*64 ; x += 64 ) {
|
||||
if ( i & 1 )
|
||||
glColor3f(29/31.0f, 15/31.0f, 4/31.0f);
|
||||
else
|
||||
glColor3f(4/31.0f, 11/31.0f, 28/31.0f);
|
||||
glVertex3f(x / 64.0f, f(x, y)/64.0f, y / 64.0f);
|
||||
glVertex3f(x / 64.0f, f(x, y+64)/64.0f, y / 64.0f + 1.0f);
|
||||
glVertex3f(x / 64.0f + 1.0f, f(x+64, y+64)/64.0f, y / 64.0f + 1.0f);
|
||||
glVertex3f(x / 64.0f + 1.0f, f(x+64, y)/64.0f, y / 64.0f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void spot(int c1, int c2, int w, int h)
|
||||
{
|
||||
float c1r = RED(c1)/31.0f, c1g = GREEN(c1)/31.0f, c1b = BLUE(c1)/31.0f;
|
||||
float c2r = RED(c2)/31.0f, c2g = GREEN(c2)/31.0f, c2b = BLUE(c2)/31.0f;
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(c1r, c1g, c1b);
|
||||
glVertex3f(-1.0f, h/64.0f, 0.0f);
|
||||
glVertex3f(1.0f, h/64.0f, 0.0f);
|
||||
glColor3f(c2r, c2g, c2b);
|
||||
glVertex3f(1.0f + w / 64.0f, 1.0f, 0.0f);
|
||||
glVertex3f(-1.0f-w/64.0f, 1.0f, 0.0f);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void robot_solo(int t)
|
||||
{
|
||||
int T = t;
|
||||
|
||||
if ( t < 256 ) {
|
||||
// stopped for the intro
|
||||
t = 0;
|
||||
} else if ( t > 1152 ) {
|
||||
// tracted by the flying saucer
|
||||
int y;
|
||||
y = (t-1152)*58;
|
||||
if ( y > 22528 )
|
||||
y = 22528;
|
||||
translate(0, y, 0);
|
||||
y = (8*4096-y)/8;
|
||||
scale(y, y, y);
|
||||
t = 0;
|
||||
}
|
||||
|
||||
robot(t, T);
|
||||
}
|
||||
|
||||
int jump(int t)
|
||||
{
|
||||
if ( t < 512 )
|
||||
return 0;
|
||||
t = t%64;
|
||||
t = t*8-384+128;
|
||||
t = 3072-t*t;
|
||||
if ( t < 0 )
|
||||
return 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
void robot_clone_wars(int t)
|
||||
{
|
||||
#define SPACE_FLOOR 1
|
||||
#define FINAL_WALK_ON 1
|
||||
#define LINES 6
|
||||
#define SPACING 16384
|
||||
int i, j;
|
||||
|
||||
//rotateX(2560);
|
||||
if ( (t & 1) == 0 ) { // different camera for different screens
|
||||
translate(5120, 44032, 20480);
|
||||
rotateZ(1792);
|
||||
} else {
|
||||
rotateX(2560);
|
||||
}
|
||||
|
||||
push();
|
||||
translate(0, -6144, -4096*4);
|
||||
rotateX(-12867/2);
|
||||
scale(4096*16, 4096*10, 4096*10);
|
||||
spot(RGB15(0, 7, 3), RGB15(0, 2, 1), 0, -64);
|
||||
pop();
|
||||
|
||||
int z = t*256-16384;
|
||||
if ( z > 0 )
|
||||
z = 0;
|
||||
|
||||
int lines = (t-192+8)/8;
|
||||
|
||||
if ( lines < 2 )
|
||||
lines = 2;
|
||||
else if ( lines > LINES )
|
||||
lines = LINES;
|
||||
|
||||
for ( i = 1 ; i < lines ; i++ ) {
|
||||
translate(0, 0, -8192);
|
||||
for ( j = 0 ; j < i ; j++ ) {
|
||||
if ( j == 2 && i == 5 )
|
||||
continue;
|
||||
push();
|
||||
translate(j * SPACING - ((i-1)*SPACING)/2, jump(t-i*4)+z, 0);
|
||||
if ( t < 512 )
|
||||
robot(8, 256);
|
||||
else
|
||||
robot(8+t-512, 256);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void background(int t)
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
if ( t == 1536 ) {
|
||||
fade_current = 0;
|
||||
fade_target = 16<<2;
|
||||
}
|
||||
if ( t < 1536 )
|
||||
spot(RGB15(31, 31, 31), RGB15(12, 12, 31), 0, -64);
|
||||
else
|
||||
spot(RGB15(1, 5, 2), RGB15(0, 0, 0), 0, -64);
|
||||
}
|
||||
|
||||
void fs(int t)
|
||||
{
|
||||
static int h[9] = { 64, 58, 51, 32, 26, 19, 10, 1, 0 };
|
||||
static int r[9] = { 0, 819, 1229, 1638, 3276, 4096, 3276, 2048, 0 };
|
||||
|
||||
int y = 1024*32-t*32;
|
||||
if ( y < 0 )
|
||||
y = 0;
|
||||
translate(y, y, -y);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
int i, j;
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(0.5f, 0.5f, 0.5f);
|
||||
for ( i = 0 ; i < 8 ; i++ ) {
|
||||
for ( j = 0 ; j < 8192 ; j += 512 ) {
|
||||
glNormal3f(((uber_cos(j) * r[i])>>18) / 64.0f, h[i]/64.0f, ((uber_sin(j) * r[i])>>18)/64.0f);
|
||||
glVertex3f(((uber_cos(j) * r[i])>>18) / 64.0f, h[i]/64.0f, ((uber_sin(j) * r[i])>>18)/64.0f);
|
||||
glVertex3f(((uber_cos(j+512) * r[i])>>18) / 64.0f, h[i]/64.0f, ((uber_sin(j+512) * r[i])>>18)/64.0f);
|
||||
glVertex3f(((uber_cos(j+512) * r[i+1])>>18) / 64.0f, h[i+1]/64.0f, ((uber_sin(j+512) * r[i+1])>>18)/64.0f);
|
||||
glVertex3f(((uber_cos(j) * r[i+1])>>18) / 64.0f, h[i+1]/64.0f, ((uber_sin(j) * r[i+1])>>18)/64.0f);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
void fs_beam(int t)
|
||||
{
|
||||
int h = 64+8+384-t*4;
|
||||
if ( h < 0 )
|
||||
h = 0;
|
||||
//GFX_POLY_FORMAT = LIGHT0|POLYFRONT|ALPHA(15);
|
||||
glEnable(GL_BLEND);
|
||||
spot(RGB15(0, 31, 4), RGB15(0, 31, 4), -32, h-384);
|
||||
}
|
||||
|
||||
typedef short s16;
|
||||
typedef char s8;
|
||||
|
||||
typedef struct {
|
||||
void (*draw)(int time);
|
||||
s16 start, end;
|
||||
s8 ty, tz;
|
||||
s8 s;
|
||||
} Drawable;
|
||||
|
||||
Drawable demo[] =
|
||||
{
|
||||
// draw start, end ty, tz scale
|
||||
{ robot_solo, 0, 1536, 1, -15, 4 },
|
||||
{ sonic, 0, 1536, -8, -24, 4 },
|
||||
{ fs, 0, 1536, 21, -15, 4 },
|
||||
{ robot_clone_wars, 1536, 2576, -4, -16, 2 },
|
||||
{ background, 0, 2576, 9, -44, 32 },
|
||||
{ fs_beam, 1024, 1536, 18, -13, 4 },
|
||||
};
|
||||
|
||||
int mouseX, mouseY;
|
||||
|
||||
void Render(int t)
|
||||
{
|
||||
if ( t < 2576 ) {
|
||||
if ( fade_current < fade_target )
|
||||
fade_current++;
|
||||
else if ( fade_current > fade_target )
|
||||
fade_current--;
|
||||
|
||||
//int v = 0;
|
||||
//if ( fade_current < (16 << 2) )
|
||||
// v = DARK | (16 - (fade_current >> 2));
|
||||
//else if ( fade_current > (16 << 2) )
|
||||
// v = BRIGHT | ((fade_current >> 2) - 16);
|
||||
|
||||
//REG_MASTER_BRIGHT = v;
|
||||
//REG_MASTER_BRIGHT_SUB = v;
|
||||
|
||||
identity();
|
||||
|
||||
// Dual screen 3D
|
||||
if ( t&1 ) {
|
||||
glViewport(WIDTH/2 - 256/2, HEIGHT/2 - 384/2 - 96/2, 255, 191);
|
||||
} else {
|
||||
translate(0, -5*4096, 0);
|
||||
glViewport(WIDTH/2 - 256/2, HEIGHT/2 - 384/2 + 192 - 96/2 + 96, 255, 191);
|
||||
}
|
||||
|
||||
// Lightweight 3D player -olol
|
||||
int i;
|
||||
for ( i = 0 ; i < sizeof(demo)/sizeof(Drawable) ; i++ ) {
|
||||
if ( t >= demo[i].start && t < demo[i].end ) {
|
||||
push();
|
||||
translate(0, demo[i].ty*1024, demo[i].tz*1024);
|
||||
scale(demo[i].s*1024, demo[i].s*1024, demo[i].s*1024);
|
||||
demo[i].draw(t-demo[i].start);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
SDL_Event event;
|
||||
bool running = true;
|
||||
|
||||
int t = 0;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#ifdef _DEBUG
|
||||
AllocConsole();
|
||||
// freopen("CONOUT$", "wb", stderr);
|
||||
// freopen("CONOUT$", "wb", stdout);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
|
||||
Tune * tune = new Tune();
|
||||
Synth * synth = new Synth(tune);
|
||||
if ( ! SDL_AddTimer(100, timer, synth) )
|
||||
return 42;
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 1);
|
||||
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 2);
|
||||
SDL_Surface * screen = SDL_SetVideoMode(WIDTH, HEIGHT, 16, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_OPENGL);
|
||||
SDL_WM_SetCaption("BitBox - Winport", "BitBox - Winport");
|
||||
InitVideo();
|
||||
|
||||
synth->play();
|
||||
tune->Load("plop");
|
||||
|
||||
Uint32 start = SDL_GetTicks();
|
||||
|
||||
while ( running ) {
|
||||
while ( SDL_PollEvent(& event) )
|
||||
{
|
||||
switch ( event.type ) {
|
||||
case SDL_MOUSEMOTION:
|
||||
mouseX = event.motion.x;
|
||||
mouseY = event.motion.y;
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
running = false;
|
||||
break;
|
||||
case SDL_VIDEORESIZE:
|
||||
case SDL_VIDEOEXPOSE:
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if ( event.key.keysym.sym == SDLK_ESCAPE ) // Quit...
|
||||
running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 now = SDL_GetTicks();
|
||||
|
||||
t = (now - start) / 16;
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
|
||||
|
||||
Render(t);
|
||||
Render(t+1);
|
||||
|
||||
SDL_GL_SwapBuffers();
|
||||
}
|
||||
|
||||
delete synth;
|
||||
delete tune;
|
||||
|
||||
SDL_FreeSurface(screen);
|
||||
SDL_Quit();
|
||||
|
||||
#ifdef __WIN32__
|
||||
#ifdef _DEBUG
|
||||
FreeConsole();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
42
BitBoxWin32/BitBoxWin32/midi.cpp
Normal file
42
BitBoxWin32/BitBoxWin32/midi.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "midi.h"
|
||||
#include "math.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
int round(float f)
|
||||
{
|
||||
return (int) (f + 0.5f);
|
||||
}
|
||||
#endif
|
||||
|
||||
int midiNoteToFrequency(int note)
|
||||
{
|
||||
return (int) (440.0f * pow(2.0f, (note - 69)/12.0f));
|
||||
}
|
||||
|
||||
int midiFrequencyToNote(int freq)
|
||||
{
|
||||
return round(69.0f + log(freq/440.0f)*17.31234f);
|
||||
}
|
||||
|
||||
char * midiNoteName(int note)
|
||||
{
|
||||
static char str[4];
|
||||
|
||||
int l = note % 12;
|
||||
|
||||
str[0] = "CCDDEFFGGAAB"[l];
|
||||
|
||||
if ( l == 1 || l == 3 || l == 6 || l == 8 || l == 10 )
|
||||
str[1] = '#';
|
||||
else
|
||||
str[1] = ' ';
|
||||
|
||||
int octave = (note - 12) / 12;
|
||||
if ( note < 12 )
|
||||
str[2] = '-';
|
||||
else
|
||||
str[2] = '0' + octave;
|
||||
|
||||
return str;
|
||||
}
|
||||
8
BitBoxWin32/BitBoxWin32/midi.h
Normal file
8
BitBoxWin32/BitBoxWin32/midi.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _MIDI_H_
|
||||
#define _MIDI_H_
|
||||
|
||||
int midiFrequencyToNote(int freq);
|
||||
int midiNoteToFrequency(int note);
|
||||
char * midiNoteName(int note);
|
||||
|
||||
#endif // _MIDI_H_
|
||||
8
BitBoxWin32/BitBoxWin32/options.h
Normal file
8
BitBoxWin32/BitBoxWin32/options.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
|
||||
#define STDLIB 0
|
||||
#define CAMERA 0
|
||||
#define SAFE 0
|
||||
|
||||
#endif // _OPTIONS_H_
|
||||
76
BitBoxWin32/BitBoxWin32/psg.cpp
Normal file
76
BitBoxWin32/BitBoxWin32/psg.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "psg.h"
|
||||
|
||||
PSG::PSG()
|
||||
: sample(0), t(0.0f), volume(0), frequency(0), duty(0)
|
||||
{
|
||||
}
|
||||
|
||||
signed short PSG::compute(float time)
|
||||
{
|
||||
t += time;
|
||||
|
||||
if ( t >= 1.0f/(float)frequency ) {
|
||||
sample = generate() * volume / 127;
|
||||
t -= 1.0f/(float)frequency;
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
void PSG::reset()
|
||||
{
|
||||
t = 0.0f;
|
||||
sample = 0;
|
||||
}
|
||||
|
||||
// NDS PSG Noise
|
||||
// X=X SHR 1, IF carry THEN Out=LOW, X=X XOR 6000h ELSE Out=HIGH
|
||||
signed short Noise::generate()
|
||||
{
|
||||
int carry;
|
||||
|
||||
carry = x & 1;
|
||||
x >>= 1;
|
||||
|
||||
if ( carry ) {
|
||||
x = x ^ 0x6000;
|
||||
return -0x7FFF;
|
||||
} else {
|
||||
return 0x7FFF;
|
||||
}
|
||||
}
|
||||
|
||||
void Noise::reset()
|
||||
{
|
||||
x = 0x7FFF;
|
||||
PSG::reset();
|
||||
}
|
||||
|
||||
// NDS Wave Duty
|
||||
// Each duty cycle consists of eight HIGH or LOW samples, so the sound
|
||||
// frequency is 1/8th of the selected sample rate. The duty cycle always
|
||||
// starts at the begin of the LOW period when the sound gets (re-)started.
|
||||
//
|
||||
// 0 12.5% "_______-_______-_______-"
|
||||
// 1 25.0% "______--______--______--"
|
||||
// 2 37.5% "_____---_____---_____---"
|
||||
// 3 50.0% "____----____----____----"
|
||||
// 4 62.5% "___-----___-----___-----"
|
||||
// 5 75.0% "__------__------__------"
|
||||
// 6 87.5% "_-------_-------_-------"
|
||||
// 7 0.0% "________________________"
|
||||
signed short WaveDuty::generate()
|
||||
{
|
||||
x = (x+1)%8;
|
||||
|
||||
if ( x <= duty )
|
||||
return -0x7FFF;
|
||||
else
|
||||
return 0x7FFF;
|
||||
}
|
||||
|
||||
void WaveDuty::reset()
|
||||
{
|
||||
x = 0;
|
||||
PSG::reset();
|
||||
}
|
||||
47
BitBoxWin32/BitBoxWin32/psg.h
Normal file
47
BitBoxWin32/BitBoxWin32/psg.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef _PSG_H_
|
||||
#define _PSG_H_
|
||||
|
||||
class PSG {
|
||||
signed short sample;
|
||||
float t;
|
||||
|
||||
int volume;
|
||||
int frequency;
|
||||
|
||||
protected:
|
||||
int x;
|
||||
int duty;
|
||||
|
||||
virtual signed short generate() = 0;
|
||||
|
||||
public:
|
||||
PSG();
|
||||
|
||||
void setDuty(int d) { duty = d; }
|
||||
void setVolume(int v) { volume = v; }
|
||||
void setFrequency(int f) { frequency = f; t = 0.0f; sample = 0; }
|
||||
|
||||
virtual void reset();
|
||||
|
||||
signed short compute(float time);
|
||||
|
||||
signed short getSample() const { return sample; }
|
||||
};
|
||||
|
||||
class Noise : public PSG {
|
||||
signed short generate();
|
||||
void reset();
|
||||
|
||||
public:
|
||||
Noise() { reset(); }
|
||||
};
|
||||
|
||||
class WaveDuty : public PSG {
|
||||
signed short generate();
|
||||
void reset();
|
||||
|
||||
public:
|
||||
WaveDuty() { reset(); }
|
||||
};
|
||||
|
||||
#endif // _PSG_H_
|
||||
292
BitBoxWin32/BitBoxWin32/synth.cpp
Normal file
292
BitBoxWin32/BitBoxWin32/synth.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
#include "synth.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "midi.h"
|
||||
|
||||
int SynthStreamCallback(const void * in, void * out, unsigned long frames,
|
||||
const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags status,
|
||||
void * user)
|
||||
{
|
||||
Synth * synth = (Synth *) user;
|
||||
synth->synth((signed short *) out, frames);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Synth::Synth(Tune * tune)
|
||||
: stream(0), tune(tune), dRes(0.0f), dRow(0.0f),
|
||||
row(0), initialRow(0), latency(0.0), analyseBufferPosition(0)
|
||||
{
|
||||
// Initialize PortAudio
|
||||
PaError code;
|
||||
|
||||
code = Pa_Initialize();
|
||||
if ( code != paNoError )
|
||||
printf("PortAudio error : %s\n", Pa_GetErrorText(code));
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// Find device with lowest latency
|
||||
const PaDeviceInfo * deviceInfo;
|
||||
PaDeviceIndex device = -1;
|
||||
for ( PaDeviceIndex i = 0 ; i < Pa_GetDeviceCount() ; i++ ) {
|
||||
deviceInfo = Pa_GetDeviceInfo(i);
|
||||
if ( device == -1 ||
|
||||
( deviceInfo->defaultLowOutputLatency < Pa_GetDeviceInfo(device)->defaultLowOutputLatency
|
||||
&& deviceInfo->maxOutputChannels >= 2 ) )
|
||||
device = i;
|
||||
}
|
||||
// Open device
|
||||
PaStreamParameters param;
|
||||
memset(& param, 0, sizeof(PaStreamParameters));
|
||||
param.channelCount = 2;
|
||||
param.device = device;
|
||||
param.hostApiSpecificStreamInfo = 0;
|
||||
param.sampleFormat = paInt16;
|
||||
param.suggestedLatency = Pa_GetDeviceInfo(device)->defaultLowOutputLatency;
|
||||
code = Pa_OpenStream(& stream, 0, & param, 44100.0, 512, paNoFlag, SynthStreamCallback, this);
|
||||
if ( code != paNoError )
|
||||
fprintf(stderr, "PortAudio error : %s\n", Pa_GetErrorText(code));
|
||||
#else
|
||||
Pa_OpenDefaultStream(& stream, 0, 2, paInt16, 44100.0, 512,
|
||||
SynthStreamCallback, this);
|
||||
#endif
|
||||
|
||||
if ( ! stream )
|
||||
fprintf(stderr, "Could not init PortAudio\n");
|
||||
|
||||
#ifdef _DEBUG
|
||||
if ( stream )
|
||||
latency = Pa_GetStreamInfo(stream)->outputLatency;
|
||||
fprintf(stderr, "Device latency : %fs.\n", latency);
|
||||
#endif
|
||||
|
||||
// Initialize PSGs
|
||||
for ( int i = 0 ; i < 6 ; i++ ) {
|
||||
channels[i].psg = new WaveDuty();
|
||||
channels[i].volume = 0;
|
||||
channels[i].mute = false;
|
||||
}
|
||||
for ( int i = 6 ; i < 8 ; i++ ) {
|
||||
channels[i].psg = new Noise();
|
||||
channels[i].volume = 0;
|
||||
channels[i].mute = false;
|
||||
}
|
||||
}
|
||||
|
||||
Synth::~Synth()
|
||||
{
|
||||
if ( stream ) {
|
||||
Pa_CloseStream(stream);
|
||||
Pa_Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::readRow()
|
||||
{
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
if ( tune->channels[i].notes[row].active ) {
|
||||
channels[i].volume =
|
||||
tune->channels[i].notes[row].volume << 4;
|
||||
int freq = midiNoteToFrequency(tune->channels[i].notes[row].note);
|
||||
if ( i < 6 )
|
||||
freq *= 8;
|
||||
channels[i].psg->setFrequency(freq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::synth(signed short * buffer, int samples, bool analyse)
|
||||
{
|
||||
int left, right, s;
|
||||
|
||||
for ( int i = samples ; i > 0 ; i-- ) {
|
||||
// Playing
|
||||
if ( row < MAXROWS && dRes > 1.0f/(float)tune->resolution ) {
|
||||
dRow += 1.0f/((float)tune->resolution * 60.0f);
|
||||
if ( dRow > 1.0f/(float)tune->rpm && row < MAXROWS ) {
|
||||
readRow();
|
||||
row++;
|
||||
dRow = 0.0f;
|
||||
}
|
||||
// Linear enveloppe
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
channels[i].volume -= tune->channels[i].dec;
|
||||
if ( channels[i].volume < 0 )
|
||||
channels[i].volume = 0;
|
||||
channels[i].psg->setVolume(channels[i].volume >> 2);
|
||||
}
|
||||
dRes = 0.0f;
|
||||
}
|
||||
|
||||
// Mixing
|
||||
right = 0;
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
s = channels[i].psg->compute(1.0f/44100.0f);
|
||||
if ( ! channels[i].mute )
|
||||
right += s;
|
||||
}
|
||||
|
||||
// Clipping
|
||||
if ( right < -0x7FFF )
|
||||
right = -0x7FFF;
|
||||
else if ( right > 0x7FFF )
|
||||
right = 0x7FFF;
|
||||
|
||||
// Filling
|
||||
left = right;
|
||||
*buffer++ = left;
|
||||
*buffer++ = right;
|
||||
|
||||
dRes += 1.0f/44100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::play()
|
||||
{
|
||||
initialRow = row;
|
||||
if ( stream )
|
||||
Pa_StartStream(stream);
|
||||
}
|
||||
|
||||
void Synth::pause()
|
||||
{
|
||||
if ( stream && Pa_IsStreamActive(stream) )
|
||||
stop();
|
||||
else
|
||||
play();
|
||||
}
|
||||
|
||||
void Synth::stop(bool abort)
|
||||
{
|
||||
if ( stream ) {
|
||||
if ( abort )
|
||||
Pa_AbortStream(stream);
|
||||
else
|
||||
Pa_StopStream(stream);
|
||||
}
|
||||
reset();
|
||||
row -= (unsigned int)(latency / 60.0f * tune->rpm);
|
||||
if ( row < initialRow )
|
||||
row = initialRow;
|
||||
}
|
||||
|
||||
void Synth::setRow(int l)
|
||||
{
|
||||
bool p = stream && Pa_IsStreamActive(stream);
|
||||
|
||||
if ( p )
|
||||
stop();
|
||||
row = l;
|
||||
if ( p )
|
||||
play();
|
||||
}
|
||||
|
||||
void Synth::setChannelDuty(int ch, int duty)
|
||||
{
|
||||
channels[ch].psg->setDuty(duty);
|
||||
}
|
||||
|
||||
unsigned int Synth::getCurrentRow()
|
||||
{
|
||||
if ( stream && Pa_IsStreamActive(stream) ) {
|
||||
int r = (int)(row - latency / 60.0f * tune->rpm);
|
||||
if ( r < (int) initialRow )
|
||||
return initialRow;
|
||||
return r;
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
void Synth::reset()
|
||||
{
|
||||
dRes = dRow = 0.0f;
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
channels[i].psg->setVolume(0);
|
||||
channels[i].psg->setDuty(tune->channels[i].duty);
|
||||
channels[i].psg->reset();
|
||||
channels[i].volume = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Synth::getVolume(int ch)
|
||||
{
|
||||
if ( channels[ch].mute )
|
||||
return 0;
|
||||
|
||||
signed short s = channels[ch].psg->getSample();
|
||||
if ( s < 0 )
|
||||
return -s;
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Synth::waveOut(const char * filename)
|
||||
{
|
||||
FILE * f = fopen(filename, "wb");
|
||||
if ( f == 0 )
|
||||
return false;
|
||||
|
||||
// RIFF header
|
||||
fwrite("RIFF", 1, 4, f);
|
||||
fseek(f, 4, SEEK_CUR); // will write file size after writing data :)
|
||||
fwrite("WAVE", 1, 4, f);
|
||||
|
||||
// FMT header
|
||||
fwrite("fmt ", 1, 4, f);
|
||||
static const int subChunk1Size = 16;
|
||||
fwrite(& subChunk1Size, 4, 1, f);
|
||||
static const short int format = 1; // PCM
|
||||
fwrite(& format, 2, 1, f);
|
||||
static const short int nbChannels = 2;
|
||||
fwrite(& nbChannels, 2, 1, f);
|
||||
static const int sampleRate = 44100;
|
||||
fwrite(& sampleRate, 4, 1, f);
|
||||
static const int byteRate = sampleRate * nbChannels * sizeof(short int);
|
||||
fwrite(& byteRate, 4, 1, f);
|
||||
static const short int blockAlign = nbChannels * sizeof(short int);
|
||||
fwrite(& blockAlign, 2, 1, f);
|
||||
static const short int bitsPerSample = 16;
|
||||
fwrite(& bitsPerSample, 2, 1, f);
|
||||
|
||||
stop();
|
||||
int savedRow = row;
|
||||
row = 0;
|
||||
|
||||
// DATA
|
||||
fwrite("data", 1, 4, f);
|
||||
fseek(f, 4, SEEK_CUR); // will write data size after writing data :)
|
||||
|
||||
int dataSize = 0;
|
||||
bool finished = false;
|
||||
static signed short buffer[2048];
|
||||
while ( ! finished ) {
|
||||
synth(buffer, 2048, false);
|
||||
fwrite(buffer, 2, 2048 * nbChannels, f);
|
||||
dataSize += 2048 * nbChannels * sizeof(short);
|
||||
|
||||
int end = 0;
|
||||
while ( end < 8 &&
|
||||
(row > tune->channels[end].lastRow && getVolume(end) == 0) )
|
||||
end++;
|
||||
if ( end == 8 )
|
||||
finished = true;
|
||||
}
|
||||
|
||||
// Data size
|
||||
fseek(f, 40, SEEK_SET);
|
||||
fwrite(& dataSize, 4, 1, f);
|
||||
|
||||
// File size
|
||||
dataSize += 36;
|
||||
fseek(f, 4, SEEK_SET);
|
||||
fwrite(& dataSize, 4, 1, f);
|
||||
|
||||
fclose(f);
|
||||
|
||||
row = savedRow;
|
||||
|
||||
return true;
|
||||
}
|
||||
60
BitBoxWin32/BitBoxWin32/synth.h
Normal file
60
BitBoxWin32/BitBoxWin32/synth.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef _SYNTH_H_
|
||||
#define _SYNTH_H_
|
||||
|
||||
#include <portaudio.h>
|
||||
|
||||
#include "tune.h"
|
||||
#include "psg.h"
|
||||
|
||||
class Synth {
|
||||
PaStream * stream;
|
||||
|
||||
Tune * tune;
|
||||
|
||||
struct Channel {
|
||||
PSG * psg;
|
||||
int volume;
|
||||
bool mute;
|
||||
};
|
||||
|
||||
Channel channels[8];
|
||||
float dRes, dRow;
|
||||
unsigned int row, initialRow;
|
||||
PaTime latency;
|
||||
|
||||
void readRow();
|
||||
|
||||
public:
|
||||
static const int analyseBufferSize = 4096;
|
||||
private:
|
||||
int analyseBufferPosition;
|
||||
signed short analyseBuffer[analyseBufferSize];
|
||||
|
||||
public:
|
||||
Synth(Tune * tune);
|
||||
~Synth();
|
||||
|
||||
void play();
|
||||
void stop(bool abort = true);
|
||||
void pause();
|
||||
|
||||
bool toggleMute(int channel)
|
||||
{ return channels[channel].mute = ! channels[channel].mute; }
|
||||
void setRow(int l);
|
||||
void setChannelDuty(int channel, int duty);
|
||||
|
||||
unsigned int getCurrentRow();
|
||||
unsigned int getVolume(int channel);
|
||||
|
||||
void synth(signed short * samples, int count, bool analyse = true);
|
||||
|
||||
signed short * getAnalyseBuffer() { return analyseBuffer; }
|
||||
|
||||
void reset();
|
||||
|
||||
Tune * getTune() { return tune; }
|
||||
|
||||
bool waveOut(const char * filename);
|
||||
};
|
||||
|
||||
#endif // _SYNTH_H_
|
||||
11
BitBoxWin32/BitBoxWin32/trig.c
Normal file
11
BitBoxWin32/BitBoxWin32/trig.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "trig.h"
|
||||
|
||||
//int uber_sin(int x)
|
||||
//{
|
||||
// int ax;
|
||||
// x = 4096 - (x & 0x1FFF);
|
||||
// ax = x;
|
||||
// if ( ax < 0 )
|
||||
// ax = -ax;
|
||||
// return 4 * x - ((4 * x * ax) >> 12);
|
||||
//}
|
||||
25
BitBoxWin32/BitBoxWin32/trig.h
Normal file
25
BitBoxWin32/BitBoxWin32/trig.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _TRIG_H_
|
||||
#define _TRIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// approximation of sin with pi=4096
|
||||
//
|
||||
// pi-(x mod 2pi) then
|
||||
// 4.x - 4.x.|x|
|
||||
int uber_sin(int x);
|
||||
#define uber_cos(x) uber_sin(x + 0x800)
|
||||
|
||||
// Conversion from old cos/sin to new uber cos/sin
|
||||
// The old was working with real value of pi in fixed point 12 (pi = 12867)
|
||||
// while the new one uses pi = 4096
|
||||
#define sin(x) uber_sin((((x) * 325) >> 10))
|
||||
#define cos(x) uber_cos((((x) * 325) >> 10))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _TRIG_H_
|
||||
249
BitBoxWin32/BitBoxWin32/tune.cpp
Normal file
249
BitBoxWin32/BitBoxWin32/tune.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
#include "tune.h"
|
||||
#include "midi.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct NDSChannel {
|
||||
unsigned int timer;
|
||||
unsigned int volume;
|
||||
unsigned int duty;
|
||||
unsigned int dec;
|
||||
int notes_offset;
|
||||
};
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct NDSNote {
|
||||
unsigned int time : 13;
|
||||
unsigned int volume : 5;
|
||||
unsigned int frequency : 14;
|
||||
#ifdef _WINDOWS
|
||||
};
|
||||
#else
|
||||
} __attribute__((packed));
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
void writeNote(int time, int volume, int frequency, FILE * f)
|
||||
{
|
||||
NDSNote tmpNote = { time, volume, frequency };
|
||||
fwrite(& tmpNote, sizeof(NDSNote), 1, f);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("N time(%4d) volume(%2d) frequency(%8d)\n", time, volume, frequency);
|
||||
#endif
|
||||
}
|
||||
|
||||
int iceilf(float f)
|
||||
{
|
||||
return (int)f + 1;
|
||||
}
|
||||
|
||||
bool Tune::Export(const char * filename)
|
||||
{
|
||||
assert(sizeof(NDSChannel) == 20);
|
||||
|
||||
NDSChannel tmpChannel;
|
||||
int nbNotes[8];
|
||||
|
||||
int notes_offset = (sizeof(NDSChannel) * 8)/4;
|
||||
|
||||
FILE * file = fopen(filename, "wb");
|
||||
|
||||
if ( file == 0 )
|
||||
return false;
|
||||
|
||||
memset(nbNotes, 0, sizeof(int) * 8);
|
||||
|
||||
// Jump over channels header, will be written after
|
||||
fseek(file, sizeof(NDSChannel) * 8, SEEK_SET);
|
||||
|
||||
#ifdef _DEBUG
|
||||
int dummies = 0;
|
||||
#endif
|
||||
|
||||
int framesPerRow = iceilf(1.0f/((float)rpm/60.0f/(float)resolution));
|
||||
|
||||
// Write notes
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
int rows = 0;
|
||||
for ( int j = 0 ; j < MAXROWS ; j++ ) {
|
||||
if ( channels[i].notes[j].active ) {
|
||||
int time = rows * framesPerRow;
|
||||
while ( time > 8191 ) { // output dummy notes to avoid overflows
|
||||
writeNote(8191, 0, 1, file);
|
||||
time -= 8191;
|
||||
nbNotes[i]++;
|
||||
#ifdef _DEBUG
|
||||
dummies++;
|
||||
#endif
|
||||
}
|
||||
writeNote(time, channels[i].notes[j].volume,
|
||||
midiNoteToFrequency(channels[i].notes[j].note), file);
|
||||
nbNotes[i]++;
|
||||
rows = 0;
|
||||
}
|
||||
rows++;
|
||||
}
|
||||
// End of track note
|
||||
writeNote(0, 0, 0, file);
|
||||
nbNotes[i]++;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("Exporting '%s' created %d dummy notes.\n", filename, dummies);
|
||||
#endif
|
||||
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// Write channels (header)
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
tmpChannel.timer = 0;
|
||||
tmpChannel.volume = 0;
|
||||
tmpChannel.duty = channels[i].duty<<24;
|
||||
tmpChannel.dec = channels[i].dec;
|
||||
tmpChannel.notes_offset = notes_offset;
|
||||
fwrite(& tmpChannel, sizeof(NDSChannel), 1, file);
|
||||
|
||||
notes_offset += nbNotes[i];
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tune::Import(const char * filename)
|
||||
{
|
||||
// XXX //
|
||||
return false;
|
||||
// XXX //
|
||||
|
||||
NDSChannel tmpChannel;
|
||||
NDSNote tmpNote;
|
||||
|
||||
FILE * file = fopen(filename, "rb");
|
||||
|
||||
if ( file == 0 )
|
||||
return false;
|
||||
|
||||
fread(& resolution, 2, 1, file);
|
||||
fread(& rpm, 2, 1, file);
|
||||
|
||||
// Reset everything and read channels
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
channels[i].reset();
|
||||
fread(& tmpChannel, sizeof(NDSChannel), 1, file);
|
||||
channels[i].duty = tmpChannel.duty;
|
||||
channels[i].dec = tmpChannel.dec;
|
||||
}
|
||||
|
||||
// Read notes
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
int row = 0;
|
||||
do {
|
||||
fread(& tmpNote, sizeof(NDSNote), 1, file);
|
||||
if ( tmpNote.time != 0 ) {
|
||||
row += (int)((float)(tmpNote.time - 1) / (float)resolution
|
||||
/ 60.0f * (float)rpm);
|
||||
if ( tmpNote.frequency != 0 )
|
||||
channels[i].notes[row].active = true;
|
||||
channels[i].notes[row].volume = tmpNote.volume;
|
||||
channels[i].notes[row].note
|
||||
= midiFrequencyToNote(tmpNote.frequency);
|
||||
channels[i].lastRow = row;
|
||||
row++;
|
||||
}
|
||||
} while ( tmpNote.time != 0 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tune::Save(const char * filename)
|
||||
{
|
||||
char _filename[256];
|
||||
strcpy(_filename, filename);
|
||||
strcat(_filename, ".txt");
|
||||
|
||||
FILE * f = fopen(_filename, "wb");
|
||||
|
||||
if ( f == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(f, "%d\n", rpm);
|
||||
|
||||
for ( int i = 0 ; i < 8 ; i++ )
|
||||
fprintf(f, "%d %d\n", channels[i].duty, channels[i].dec);
|
||||
|
||||
for ( int i = 0 ; i < 8 ; i++ ) {
|
||||
for ( int j = 0 ; j < MAXROWS ; j++ ) {
|
||||
if ( channels[i].notes[j].active ) {
|
||||
fprintf(f, "%d %d %d %d\n", i, j,
|
||||
channels[i].notes[j].volume,
|
||||
channels[i].notes[j].note);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tune::Load(const char * filename)
|
||||
{
|
||||
char _filename[256];
|
||||
strcpy(_filename, filename);
|
||||
strcat(_filename, ".txt");
|
||||
|
||||
FILE * f = fopen(_filename, "rb");
|
||||
|
||||
clear();
|
||||
|
||||
if ( f == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( fscanf(f, "%d\n", &rpm) != 1 )
|
||||
goto error;
|
||||
|
||||
int framesPerRow = iceilf(1.0f/((float)rpm/60.0f/(float)resolution));
|
||||
rpm = framesPerRow * 60;
|
||||
|
||||
for ( int i = 0 ; i < 8 ; i++ )
|
||||
if ( fscanf(f, "%d %d\n", &(channels[i].duty), &(channels[i].dec)) != 2 )
|
||||
goto error;
|
||||
|
||||
int c, r, v, n;
|
||||
while ( fscanf(f, "%d %d %d %d\n", &c, &r, &v, &n) == 4 ) {
|
||||
channels[c].notes[r].volume = v;
|
||||
channels[c].notes[r].note = n;
|
||||
channels[c].notes[r].active = true;
|
||||
if ( channels[c].lastRow < r )
|
||||
channels[c].lastRow = r;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Tune::clear()
|
||||
{
|
||||
resolution = 60;
|
||||
rpm = 280;
|
||||
for ( int i = 0 ; i < 8 ; i++ )
|
||||
channels[i].reset();
|
||||
}
|
||||
25
BitBoxWin32/BitBoxWin32/tune.h
Normal file
25
BitBoxWin32/BitBoxWin32/tune.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _TUNE_H_
|
||||
#define _TUNE_H_
|
||||
|
||||
#include "channel.h"
|
||||
|
||||
struct Tune {
|
||||
Channel channels[8];
|
||||
int resolution;
|
||||
int rpm; // rows per minute
|
||||
|
||||
Tune() { clear(); }
|
||||
|
||||
// To text format used by the tracker
|
||||
bool Save(const char * filename);
|
||||
bool Load(const char * filename);
|
||||
|
||||
// To binary format used by the NDS player
|
||||
// XXX FUCKED UP ! XXX
|
||||
bool Export(const char * filename);
|
||||
bool Import(const char * filename);
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
#endif // _TUNE_H_
|
||||
Reference in New Issue
Block a user