player/client: port to C
Make sure that all code included in the player and client is pure C. This helps on portability.
This commit is contained in:
parent
dc1ab70976
commit
decf843c04
@ -179,11 +179,7 @@
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\sync\data.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sync\network.cpp"
|
||||
RelativePath="..\sync\data.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -199,7 +195,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sync\track.cpp"
|
||||
RelativePath="..\sync\track.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -237,6 +233,10 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sync\sync.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\syncdocument.h"
|
||||
>
|
||||
</File>
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
#include "syncdocument.h"
|
||||
#include <string>
|
||||
#include <tchar.h>
|
||||
|
||||
SyncDocument::~SyncDocument()
|
||||
{
|
||||
sync_data_deinit(this);
|
||||
clearUndoStack();
|
||||
clearRedoStack();
|
||||
}
|
||||
@ -31,11 +34,11 @@ bool SyncDocument::load(const std::string &fileName)
|
||||
MSXML2::IXMLDOMNamedNodeMapPtr attribs = trackNode->Getattributes();
|
||||
|
||||
std::string name = attribs->getNamedItem("name")->Gettext();
|
||||
|
||||
|
||||
// look up track-name, create it if it doesn't exist
|
||||
int trackIndex = getTrackIndex(name);
|
||||
int trackIndex = sync_find_track(this, name.c_str());
|
||||
if (0 > trackIndex) trackIndex = int(createTrack(name));
|
||||
|
||||
|
||||
MSXML2::IXMLDOMNodeListPtr rowNodes = trackNode->GetchildNodes();
|
||||
for (int i = 0; i < rowNodes->Getlength(); ++i)
|
||||
{
|
||||
@ -47,20 +50,12 @@ bool SyncDocument::load(const std::string &fileName)
|
||||
std::string rowString = rowAttribs->getNamedItem("row")->Gettext();
|
||||
std::string valueString = rowAttribs->getNamedItem("value")->Gettext();
|
||||
std::string interpolationString = rowAttribs->getNamedItem("interpolation")->Gettext();
|
||||
|
||||
sync::Track::KeyFrame keyFrame(
|
||||
float(atof(valueString.c_str())),
|
||||
sync::Track::KeyFrame::InterpolationType(
|
||||
atoi(interpolationString.c_str())
|
||||
)
|
||||
);
|
||||
multiCmd->addCommand(
|
||||
new InsertCommand(
|
||||
int(trackIndex),
|
||||
atoi(rowString.c_str()),
|
||||
keyFrame
|
||||
)
|
||||
);
|
||||
|
||||
track_key k;
|
||||
k.row = atoi(rowString.c_str());
|
||||
k.value = float(atof(valueString.c_str()));
|
||||
k.type = key_type(atoi(interpolationString.c_str()));
|
||||
multiCmd->addCommand(new InsertCommand(int(trackIndex), k));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,41 +86,40 @@ bool SyncDocument::save(const std::string &fileName)
|
||||
|
||||
_snprintf(temp, 256, "%d", getRows());
|
||||
rootNode->setAttribute(_T("rows"), temp);
|
||||
|
||||
for (size_t i = 0; i < getTrackCount(); ++i)
|
||||
{
|
||||
const sync::Track &track = getTrack(i);
|
||||
|
||||
|
||||
for (size_t i = 0; i < num_tracks; ++i) {
|
||||
const sync_track *t = tracks[i];
|
||||
|
||||
MSXML2::IXMLDOMElementPtr trackElem = doc->createElement(_T("track"));
|
||||
trackElem->setAttribute(_T("name"), track.getName().c_str());
|
||||
|
||||
trackElem->setAttribute(_T("name"), t->name);
|
||||
|
||||
rootNode->appendChild(doc->createTextNode(_T("\n\t")));
|
||||
rootNode->appendChild(trackElem);
|
||||
|
||||
sync::Track::KeyFrameContainer::const_iterator it;
|
||||
for (it = track.keyFramesBegin(); it != track.keyFramesEnd(); ++it)
|
||||
{
|
||||
size_t row = it->first;
|
||||
float value = it->second.value;
|
||||
char interpolationType = char(it->second.interpolationType);
|
||||
|
||||
|
||||
for (int i = 0; i < (int)t->num_keys; ++i) {
|
||||
size_t row = t->keys[i].row;
|
||||
float value = t->keys[i].value;
|
||||
char interpolationType = char(t->keys[i].type);
|
||||
|
||||
MSXML2::IXMLDOMElementPtr keyElem = doc->createElement(_T("key"));
|
||||
|
||||
_snprintf(temp, 256, _T("%d"), row);
|
||||
keyElem->setAttribute(_T("row"), temp);
|
||||
|
||||
|
||||
_snprintf(temp, 256, _T("%f"), value);
|
||||
keyElem->setAttribute(_T("value"), temp);
|
||||
|
||||
|
||||
_snprintf(temp, 256, _T("%d"), interpolationType);
|
||||
keyElem->setAttribute(_T("interpolation"), temp);
|
||||
|
||||
|
||||
trackElem->appendChild(doc->createTextNode(_T("\n\t\t")));
|
||||
trackElem->appendChild(keyElem);
|
||||
}
|
||||
if (0 != track.getKeyFrameCount()) trackElem->appendChild(doc->createTextNode(_T("\n\t")));
|
||||
if (t->num_keys)
|
||||
trackElem->appendChild(doc->createTextNode(_T("\n\t")));
|
||||
}
|
||||
if (0 != getTrackCount()) rootNode->appendChild(doc->createTextNode(_T("\n")));
|
||||
if (0 != num_tracks)
|
||||
rootNode->appendChild(doc->createTextNode(_T("\n")));
|
||||
|
||||
doc->save(fileName.c_str());
|
||||
|
||||
|
||||
@ -10,32 +10,92 @@
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
class SyncDocument : public sync::Data
|
||||
class NetworkSocket
|
||||
{
|
||||
public:
|
||||
SyncDocument() : sync::Data(), clientPaused(true), rows(128), savePointDelta(0), savePointUnreachable(true) {}
|
||||
NetworkSocket() : socket(INVALID_SOCKET) {}
|
||||
explicit NetworkSocket(SOCKET socket) : socket(socket) {}
|
||||
|
||||
bool connected() const
|
||||
{
|
||||
return INVALID_SOCKET != socket;
|
||||
}
|
||||
|
||||
void disconnect()
|
||||
{
|
||||
closesocket(socket);
|
||||
socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
bool recv(char *buffer, size_t length, int flags)
|
||||
{
|
||||
if (!connected())
|
||||
return false;
|
||||
int ret = ::recv(socket, buffer, int(length), flags);
|
||||
if (ret != length) {
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send(const char *buffer, size_t length, int flags)
|
||||
{
|
||||
if (!connected())
|
||||
return false;
|
||||
int ret = ::send(socket, buffer, int(length), flags);
|
||||
if (ret != length) {
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pollRead()
|
||||
{
|
||||
if (!connected())
|
||||
return false;
|
||||
return !!socket_poll(socket);
|
||||
}
|
||||
|
||||
private:
|
||||
SOCKET socket;
|
||||
};
|
||||
|
||||
class SyncDocument : public sync_data
|
||||
{
|
||||
public:
|
||||
SyncDocument() : clientPaused(true), rows(128), savePointDelta(0), savePointUnreachable(true)
|
||||
{
|
||||
this->tracks = NULL;
|
||||
this->num_tracks = 0;
|
||||
}
|
||||
|
||||
~SyncDocument();
|
||||
|
||||
size_t createTrack(const std::basic_string<TCHAR> &name)
|
||||
{
|
||||
size_t index = sync::Data::createTrack(name);
|
||||
size_t index = sync_create_track(this, name.c_str());
|
||||
trackOrder.push_back(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
void sendSetKeyCommand(int track, int row, const sync::Track::KeyFrame &key)
|
||||
void sendSetKeyCommand(int track, const struct track_key &key)
|
||||
{
|
||||
if (!clientSocket.connected()) return;
|
||||
if (clientRemap.count(track) == 0) return;
|
||||
track = int(clientRemap[track]);
|
||||
|
||||
|
||||
assert(key.type < KEY_TYPE_COUNT);
|
||||
|
||||
unsigned char cmd = SET_KEY;
|
||||
clientSocket.send((char*)&cmd, 1, 0);
|
||||
clientSocket.send((char*)&track, sizeof(int), 0);
|
||||
clientSocket.send((char*)&row, sizeof(int), 0);
|
||||
clientSocket.send((char*)&key.row, sizeof(int), 0);
|
||||
clientSocket.send((char*)&key.value, sizeof(float), 0);
|
||||
clientSocket.send((char*)&key.interpolationType, 1, 0);
|
||||
clientSocket.send((char*)&key.type, 1, 0);
|
||||
}
|
||||
|
||||
void sendDeleteKeyCommand(int track, int row)
|
||||
@ -86,29 +146,28 @@ public:
|
||||
class InsertCommand : public Command
|
||||
{
|
||||
public:
|
||||
InsertCommand(int track, int row, const sync::Track::KeyFrame &key) : track(track), row(row), key(key) {}
|
||||
InsertCommand(int track, const track_key &key) : track(track), key(key) {}
|
||||
~InsertCommand() {}
|
||||
|
||||
void exec(SyncDocument *data)
|
||||
{
|
||||
sync::Track &t = data->getTrack(this->track);
|
||||
assert(!t.isKeyFrame(row));
|
||||
t.setKeyFrame(row, key);
|
||||
data->sendSetKeyCommand(track, row, key); // update clients
|
||||
sync_track *t = data->tracks[track];
|
||||
assert(!is_key_frame(t, key.row));
|
||||
sync_set_key(t, &key);
|
||||
data->sendSetKeyCommand(track, key); // update clients
|
||||
}
|
||||
|
||||
void undo(SyncDocument *data)
|
||||
{
|
||||
sync::Track &t = data->getTrack(this->track);
|
||||
assert(t.isKeyFrame(row));
|
||||
t.deleteKeyFrame(row);
|
||||
|
||||
data->sendDeleteKeyCommand(track, row); // update clients
|
||||
sync_track *t = data->tracks[track];
|
||||
assert(is_key_frame(t, key.row));
|
||||
sync_del_key(t, key.row);
|
||||
data->sendDeleteKeyCommand(track, key.row); // update clients
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int track, row;
|
||||
sync::Track::KeyFrame key;
|
||||
int track;
|
||||
track_key key;
|
||||
};
|
||||
|
||||
class DeleteCommand : public Command
|
||||
@ -119,62 +178,55 @@ public:
|
||||
|
||||
void exec(SyncDocument *data)
|
||||
{
|
||||
sync::Track &t = data->getTrack(this->track);
|
||||
assert(t.isKeyFrame(row));
|
||||
oldKey = *t.getKeyFrame(row);
|
||||
t.deleteKeyFrame(row);
|
||||
|
||||
sync_track *t = data->tracks[track];
|
||||
int idx = sync_find_key(t, row);
|
||||
assert(idx >= 0);
|
||||
oldKey = t->keys[idx];
|
||||
sync_del_key(t, row);
|
||||
data->sendDeleteKeyCommand(track, row); // update clients
|
||||
}
|
||||
|
||||
void undo(SyncDocument *data)
|
||||
{
|
||||
sync::Track &t = data->getTrack(this->track);
|
||||
assert(!t.isKeyFrame(row));
|
||||
t.setKeyFrame(row, oldKey);
|
||||
|
||||
data->sendSetKeyCommand(track, row, oldKey); // update clients
|
||||
sync_track *t = data->tracks[track];
|
||||
assert(!is_key_frame(t, row));
|
||||
sync_set_key(t, &oldKey);
|
||||
data->sendSetKeyCommand(track, oldKey); // update clients
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int track, row;
|
||||
sync::Track::KeyFrame oldKey;
|
||||
struct track_key oldKey;
|
||||
};
|
||||
|
||||
|
||||
class EditCommand : public Command
|
||||
{
|
||||
public:
|
||||
EditCommand(int track, int row, const sync::Track::KeyFrame &key) : track(track), row(row), key(key) {}
|
||||
EditCommand(int track, const track_key &key) : track(track), key(key) {}
|
||||
~EditCommand() {}
|
||||
|
||||
|
||||
void exec(SyncDocument *data)
|
||||
{
|
||||
sync::Track &t = data->getTrack(this->track);
|
||||
|
||||
// store old key
|
||||
assert(t.isKeyFrame(row));
|
||||
oldKey = *t.getKeyFrame(row);
|
||||
|
||||
// update
|
||||
t.setKeyFrame(row, key);
|
||||
|
||||
data->sendSetKeyCommand(track, row, key); // update clients
|
||||
sync_track *t = data->tracks[track];
|
||||
int idx = sync_find_key(t, key.row);
|
||||
assert(idx >= 0);
|
||||
oldKey = t->keys[idx];
|
||||
sync_set_key(t, &key);
|
||||
data->sendSetKeyCommand(track, key); // update clients
|
||||
}
|
||||
|
||||
|
||||
void undo(SyncDocument *data)
|
||||
{
|
||||
sync::Track &t = data->getTrack(this->track);
|
||||
|
||||
assert(t.isKeyFrame(row));
|
||||
t.setKeyFrame(row, oldKey);
|
||||
|
||||
data->sendSetKeyCommand(track, row, oldKey); // update clients
|
||||
sync_track *t = data->tracks[track];
|
||||
assert(is_key_frame(t, key.row));
|
||||
sync_set_key(t, &oldKey);
|
||||
data->sendSetKeyCommand(track, oldKey); // update clients
|
||||
}
|
||||
|
||||
private:
|
||||
int track, row;
|
||||
sync::Track::KeyFrame oldKey, key;
|
||||
int track;
|
||||
track_key oldKey, key;
|
||||
};
|
||||
|
||||
class MultiCommand : public Command
|
||||
@ -273,12 +325,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
Command *getSetKeyFrameCommand(int track, int row, const sync::Track::KeyFrame &key)
|
||||
Command *getSetKeyFrameCommand(int track, const track_key &key)
|
||||
{
|
||||
sync::Track &t = getTrack(track);
|
||||
sync_track *t = tracks[track];
|
||||
SyncDocument::Command *cmd;
|
||||
if (t.isKeyFrame(row)) cmd = new EditCommand(track, row, key);
|
||||
else cmd = new InsertCommand(track, row, key);
|
||||
if (is_key_frame(t, key.row)) cmd = new EditCommand(track, key);
|
||||
else cmd = new InsertCommand(track, key);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ RecentFiles mruFileList(NULL);
|
||||
#define WM_SETROWS (WM_USER+1)
|
||||
#define WM_BIASSELECTION (WM_USER+2)
|
||||
|
||||
#include "../sync/sync.h"
|
||||
#include "../sync/network.h"
|
||||
|
||||
static LRESULT CALLBACK setRowsDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
@ -168,9 +169,12 @@ std::string fileName;
|
||||
void fileNew()
|
||||
{
|
||||
// document.purgeUnusedTracks();
|
||||
for (size_t i = 0; i < document.getTrackCount(); ++i)
|
||||
for (size_t i = 0; i < document.num_tracks; ++i)
|
||||
{
|
||||
document.getTrack(i).truncate();
|
||||
sync_track *t = document.tracks[i];
|
||||
free(t->keys);
|
||||
t->keys = NULL;
|
||||
t->num_keys = 0;
|
||||
}
|
||||
setWindowFileName("Untitled");
|
||||
fileName.clear();
|
||||
@ -452,8 +456,12 @@ static LRESULT CALLBACK mainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARA
|
||||
case WM_CURRVALDIRTY:
|
||||
{
|
||||
TCHAR temp[256];
|
||||
if (document.getTrackCount() > 0) _sntprintf_s(temp, 256, _T("%f"), document.getTrack(document.getTrackIndexFromPos(trackView->getEditTrack())).getValue(float(trackView->getEditRow())));
|
||||
else _sntprintf_s(temp, 256, _T("---"));
|
||||
if (document.num_tracks > 0) {
|
||||
sync_track *t = document.tracks[document.getTrackIndexFromPos(trackView->getEditTrack())];
|
||||
float row = float(trackView->getEditRow());
|
||||
_sntprintf_s(temp, 256, _T("%f"), sync_get_val(t, row));
|
||||
} else
|
||||
_sntprintf_s(temp, 256, _T("---"));
|
||||
SendMessage(statusBarWin, SB_SETTEXT, 3, (LPARAM)temp);
|
||||
}
|
||||
break;
|
||||
@ -484,13 +492,52 @@ static ATOM registerMainWindowClass(HINSTANCE hInstance)
|
||||
return RegisterClassEx(&wc);
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
void die(const char *fmt, ...)
|
||||
{
|
||||
char temp[4096];
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vfprintf(stderr, fmt, va);
|
||||
vsnprintf(temp, sizeof(temp), fmt, va);
|
||||
va_end(va);
|
||||
|
||||
MessageBox(NULL, temp, mainWindowTitle, MB_OK | MB_ICONERROR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
SOCKET clientConnect(SOCKET serverSocket, sockaddr_in *host)
|
||||
{
|
||||
sockaddr_in hostTemp;
|
||||
int hostSize = sizeof(sockaddr_in);
|
||||
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&hostTemp, &hostSize);
|
||||
if (INVALID_SOCKET == clientSocket) return INVALID_SOCKET;
|
||||
|
||||
const char *expectedGreeting = client_greet;
|
||||
char recievedGreeting[128];
|
||||
|
||||
recv(clientSocket, recievedGreeting, int(strlen(expectedGreeting)), 0);
|
||||
|
||||
if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0)
|
||||
{
|
||||
closesocket(clientSocket);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
const char *greeting = server_greet;
|
||||
send(clientSocket, greeting, int(strlen(greeting)), 0);
|
||||
|
||||
if (NULL != host) *host = hostTemp;
|
||||
return clientSocket;
|
||||
}
|
||||
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
|
||||
/* _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); */
|
||||
// _CrtSetBreakAlloc(254);
|
||||
#endif
|
||||
|
||||
@ -510,41 +557,32 @@ int _tmain(int argc, _TCHAR* argv[])
|
||||
printf("%x\n", test2);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (false == initNetwork())
|
||||
{
|
||||
fputs("Failed to init WinSock", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SOCKET serverSocket = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
|
||||
|
||||
if (!init_network())
|
||||
die("Failed to init network");
|
||||
|
||||
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
struct sockaddr_in sin;
|
||||
memset( &sin, 0, sizeof sin );
|
||||
|
||||
memset(&sin, 0, sizeof sin);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
sin.sin_port = htons( 1338 );
|
||||
|
||||
|
||||
puts("binding...");
|
||||
if (SOCKET_ERROR == bind( serverSocket, (struct sockaddr *)&sin, sizeof(sin)))
|
||||
{
|
||||
MessageBox(NULL, _T("Could not start server"), mainWindowTitle, MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
|
||||
fputs("Coult not start server", stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
die("Could not start server");
|
||||
|
||||
puts("listening...");
|
||||
while ( listen( serverSocket, SOMAXCONN ) == SOCKET_ERROR );
|
||||
|
||||
while (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR)
|
||||
; /* nothing */
|
||||
|
||||
ATOM mainClass = registerMainWindowClass(hInstance);
|
||||
ATOM trackViewClass = registerTrackViewWindowClass(hInstance);
|
||||
if (!mainClass || !trackViewClass)
|
||||
{
|
||||
MessageBox(NULL, _T("Window Registration Failed!"), mainWindowTitle, MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
|
||||
return -1;
|
||||
}
|
||||
|
||||
die("Window Registration Failed!");
|
||||
|
||||
trackView = new TrackView();
|
||||
trackView->setDocument(&document);
|
||||
|
||||
@ -557,13 +595,10 @@ int _tmain(int argc, _TCHAR* argv[])
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, // width, height
|
||||
NULL, NULL, hInstance, NULL
|
||||
);
|
||||
|
||||
|
||||
if (NULL == hwnd)
|
||||
{
|
||||
MessageBox(NULL, _T("Window Creation Failed!"), mainWindowTitle, MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||
return -1;
|
||||
}
|
||||
|
||||
die("Window Creation Failed!");
|
||||
|
||||
fileNew();
|
||||
|
||||
HACCEL accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR));
|
||||
@ -634,22 +669,16 @@ int _tmain(int argc, _TCHAR* argv[])
|
||||
clientSocket.recv(&trackName[0], str_len, 0);
|
||||
|
||||
// find track
|
||||
int serverIndex = document.getTrackIndex(trackName);
|
||||
int serverIndex = sync_find_track(&document, trackName.c_str());
|
||||
if (0 > serverIndex) serverIndex = int(document.createTrack(trackName));
|
||||
|
||||
// setup remap
|
||||
document.clientRemap[serverIndex] = clientIndex;
|
||||
|
||||
const sync::Track &track = document.getTrack(serverIndex);
|
||||
|
||||
sync::Track::KeyFrameContainer::const_iterator it;
|
||||
for (it = track.keyFramesBegin(); it != track.keyFramesEnd(); ++it)
|
||||
{
|
||||
int row = int(it->first);
|
||||
const sync::Track::KeyFrame &key = it->second;
|
||||
document.sendSetKeyCommand(int(serverIndex), row, key);
|
||||
}
|
||||
|
||||
|
||||
const sync_track *t = document.tracks[serverIndex];
|
||||
for (int i = 0; i < (int)t->num_keys; ++i)
|
||||
document.sendSetKeyCommand(int(serverIndex), t->keys[i]);
|
||||
|
||||
InvalidateRect(trackViewWin, NULL, FALSE);
|
||||
}
|
||||
break;
|
||||
@ -685,13 +714,13 @@ int _tmain(int argc, _TCHAR* argv[])
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
|
||||
closesocket(serverSocket);
|
||||
closeNetwork();
|
||||
|
||||
close_network();
|
||||
|
||||
delete trackView;
|
||||
trackView = NULL;
|
||||
|
||||
|
||||
UnregisterClass(mainWindowClassName, hInstance);
|
||||
return int(msg.wParam);
|
||||
}
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "trackview.h"
|
||||
#include <vector>
|
||||
#include <tchar.h>
|
||||
|
||||
static const TCHAR *trackViewWindowClassName = _T("TrackView");
|
||||
|
||||
@ -149,37 +150,31 @@ void TrackView::paintTopMargin(HDC hdc, RECT rcTracks)
|
||||
|
||||
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
||||
|
||||
for (int track = startTrack; track < endTrack; ++track)
|
||||
{
|
||||
for (int track = startTrack; track < endTrack; ++track) {
|
||||
size_t index = doc->getTrackIndexFromPos(track);
|
||||
const sync::Track &t = doc->getTrack(index);
|
||||
|
||||
const sync_track *t = doc->tracks[index];
|
||||
|
||||
RECT topMargin;
|
||||
|
||||
topMargin.top = 0;
|
||||
topMargin.bottom = topMarginHeight;
|
||||
|
||||
topMargin.left = getScreenX(track);
|
||||
topMargin.right = topMargin.left + trackWidth;
|
||||
|
||||
if (!RectVisible(hdc, &topMargin)) continue;
|
||||
|
||||
|
||||
if (!RectVisible(hdc, &topMargin))
|
||||
continue;
|
||||
|
||||
RECT fillRect = topMargin;
|
||||
|
||||
|
||||
HBRUSH bgBrush = GetSysColorBrush(COLOR_3DFACE);
|
||||
if (track == editTrack) bgBrush = editBrush;
|
||||
|
||||
if (track == editTrack)
|
||||
bgBrush = editBrush;
|
||||
|
||||
DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_LEFT | BF_RIGHT | BF_BOTTOM);
|
||||
FillRect(hdc, &fillRect, bgBrush);
|
||||
|
||||
const std::basic_string<TCHAR> &trackName = t.getName();
|
||||
|
||||
|
||||
if (doc->clientRemap.count(doc->getTrackIndexFromPos(track)) == 0) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
|
||||
else SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
||||
TextOut(hdc,
|
||||
fillRect.left, 0,
|
||||
trackName.data(), int(trackName.length())
|
||||
);
|
||||
TextOut(hdc, fillRect.left, 0, t->name, int(strlen(t->name)));
|
||||
}
|
||||
|
||||
RECT topRightMargin;
|
||||
@ -252,23 +247,23 @@ void TrackView::paintTracks(HDC hdc, RECT rcTracks)
|
||||
int startTrack = scrollPosX / trackWidth;
|
||||
int endTrack = min(startTrack + windowTracks + 1, int(getTrackCount()));
|
||||
|
||||
for (int track = startTrack; track < endTrack; ++track)
|
||||
{
|
||||
const sync::Track &t = doc->getTrack(doc->getTrackIndexFromPos(track));
|
||||
|
||||
for (int row = firstRow; row <= lastRow; ++row)
|
||||
{
|
||||
for (int track = startTrack; track < endTrack; ++track) {
|
||||
const sync_track *t = doc->tracks[doc->getTrackIndexFromPos(track)];
|
||||
for (int row = firstRow; row <= lastRow; ++row) {
|
||||
RECT patternDataRect;
|
||||
patternDataRect.left = getScreenX(track);
|
||||
patternDataRect.right = patternDataRect.left + trackWidth;
|
||||
patternDataRect.top = getScreenY(row);
|
||||
patternDataRect.bottom = patternDataRect.top + rowHeight;
|
||||
|
||||
if (!RectVisible(hdc, &patternDataRect)) continue;
|
||||
|
||||
sync::Track::KeyFrame::InterpolationType interpolationType = t.getInterpolationType(row);
|
||||
if (!RectVisible(hdc, &patternDataRect))
|
||||
continue;
|
||||
|
||||
int idx = sync_find_key(t, row);
|
||||
int fidx = idx >= 0 ? idx : -idx - 2;
|
||||
key_type interpolationType = (fidx >= 0) ? t->keys[fidx].type : KEY_STEP;
|
||||
bool selected = (track >= selectLeft && track <= selectRight) && (row >= selectTop && row <= selectBottom);
|
||||
|
||||
|
||||
HBRUSH baseBrush = bgBaseBrush;
|
||||
HBRUSH darkBrush = bgDarkBrush;
|
||||
if (selected)
|
||||
@ -281,56 +276,48 @@ void TrackView::paintTracks(HDC hdc, RECT rcTracks)
|
||||
if (row % 8 == 0) bgBrush = darkBrush;
|
||||
|
||||
RECT fillRect = patternDataRect;
|
||||
// if (row == editRow && track == editTrack) DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_SUNKENOUTER, BF_ADJUST | BF_TOP | BF_BOTTOM | BF_LEFT | BF_RIGHT);
|
||||
FillRect( hdc, &fillRect, bgBrush);
|
||||
if (row % 8 == 0)
|
||||
{
|
||||
if (row % 8 == 0) {
|
||||
MoveToEx(hdc, patternDataRect.left, patternDataRect.top, (LPPOINT) NULL);
|
||||
if (selected) SelectObject(hdc, rowSelectPen);
|
||||
else SelectObject(hdc, rowPen);
|
||||
LineTo(hdc, patternDataRect.right, patternDataRect.top);
|
||||
}
|
||||
|
||||
switch (interpolationType)
|
||||
{
|
||||
case sync::Track::KeyFrame::IT_LERP:
|
||||
switch (interpolationType) {
|
||||
case KEY_STEP:
|
||||
break;
|
||||
case KEY_LINEAR:
|
||||
SelectObject(hdc, lerpPen);
|
||||
break;
|
||||
case sync::Track::KeyFrame::IT_COSINE:
|
||||
case KEY_SMOOTH:
|
||||
SelectObject(hdc, cosinePen);
|
||||
break;
|
||||
case sync::Track::KeyFrame::IT_RAMP:
|
||||
case KEY_RAMP:
|
||||
SelectObject(hdc, rampPen);
|
||||
break;
|
||||
case sync::Track::KeyFrame::IT_STEP:
|
||||
break;
|
||||
}
|
||||
if (interpolationType != sync::Track::KeyFrame::IT_STEP)
|
||||
{
|
||||
if (interpolationType != KEY_STEP) {
|
||||
MoveToEx(hdc, patternDataRect.right - 1, patternDataRect.top, (LPPOINT) NULL);
|
||||
LineTo(hdc, patternDataRect.right - 1, patternDataRect.bottom);
|
||||
}
|
||||
|
||||
|
||||
bool drawEditString = false;
|
||||
if (row == editRow && track == editTrack)
|
||||
{
|
||||
if (row == editRow && track == editTrack) {
|
||||
FrameRect(hdc, &fillRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||||
// DrawFocusRect(hdc, &fillRect);
|
||||
// Rectangle(hdc, fillRect.left, fillRect.top, fillRect.right, fillRect.bottom);
|
||||
if (editString.size() > 0) drawEditString = true;
|
||||
if (editString.size() > 0)
|
||||
drawEditString = true;
|
||||
}
|
||||
|
||||
bool key = t.isKeyFrame(row);
|
||||
|
||||
/* format the text */
|
||||
if (drawEditString) _sntprintf_s(temp, 256, editString.c_str());
|
||||
else if (!key) _sntprintf_s(temp, 256, _T(" ---"));
|
||||
else
|
||||
{
|
||||
float val = t.getKeyFrame(row)->value;
|
||||
if (drawEditString)
|
||||
_sntprintf_s(temp, 256, editString.c_str());
|
||||
else if (idx < 0)
|
||||
_sntprintf_s(temp, 256, _T(" ---"));
|
||||
else {
|
||||
float val = t->keys[idx].value;
|
||||
_sntprintf_s(temp, 256, _T("% .2f"), val);
|
||||
}
|
||||
|
||||
|
||||
COLORREF oldCol;
|
||||
if (selected) oldCol = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
TextOut(hdc,
|
||||
@ -372,8 +359,8 @@ void TrackView::paintTracks(HDC hdc, RECT rcTracks)
|
||||
|
||||
struct CopyEntry
|
||||
{
|
||||
int track, row;
|
||||
sync::Track::KeyFrame keyFrame;
|
||||
int track;
|
||||
track_key keyFrame;
|
||||
};
|
||||
|
||||
void TrackView::editCopy()
|
||||
@ -404,24 +391,17 @@ void TrackView::editCopy()
|
||||
size_t cells = columns * rows;
|
||||
|
||||
std::vector<struct CopyEntry> copyEntries;
|
||||
for (int track = selectLeft; track <= selectRight; ++track)
|
||||
{
|
||||
for (int track = selectLeft; track <= selectRight; ++track) {
|
||||
const size_t trackIndex = doc->getTrackIndexFromPos(track);
|
||||
const sync::Track &t = doc->getTrack(trackIndex);
|
||||
|
||||
for (int row = selectTop; row <= selectBottom; ++row)
|
||||
{
|
||||
int localRow = row - selectTop;
|
||||
if (t.isKeyFrame(row))
|
||||
{
|
||||
const sync::Track::KeyFrame *keyFrame = t.getKeyFrame(row);
|
||||
assert(NULL != keyFrame);
|
||||
|
||||
const sync_track *t = doc->tracks[trackIndex];
|
||||
|
||||
for (int row = selectTop; row <= selectBottom; ++row) {
|
||||
int idx = sync_find_key(t, row);
|
||||
if (idx >= 0) {
|
||||
CopyEntry ce;
|
||||
ce.track = track - selectLeft;
|
||||
ce.row = localRow;
|
||||
ce.keyFrame = *keyFrame;
|
||||
|
||||
ce.keyFrame = t->keys[idx];
|
||||
ce.keyFrame.row -= selectTop;
|
||||
copyEntries.push_back(ce);
|
||||
}
|
||||
}
|
||||
@ -490,21 +470,16 @@ void TrackView::editPaste()
|
||||
memcpy(&buffer_size, clipbuf + 2 * sizeof(int), sizeof(size_t));
|
||||
|
||||
SyncDocument::MultiCommand *multiCmd = new SyncDocument::MultiCommand();
|
||||
for (int t = 0; t < buffer_width; ++t)
|
||||
{
|
||||
size_t trackPos = editTrack + t;
|
||||
for (int i = 0; i < buffer_width; ++i) {
|
||||
size_t trackPos = editTrack + i;
|
||||
if (trackPos >= getTrackCount()) continue;
|
||||
|
||||
|
||||
size_t trackIndex = doc->getTrackIndexFromPos(trackPos);
|
||||
const sync::Track &track = doc->getTrack(trackIndex);
|
||||
|
||||
for (int r = 0; r < buffer_height; ++r)
|
||||
{
|
||||
int row = editRow + r;
|
||||
if (track.isKeyFrame(row))
|
||||
{
|
||||
const sync_track *t = doc->tracks[trackIndex];
|
||||
for (int j = 0; j < buffer_height; ++j) {
|
||||
int row = editRow + j;
|
||||
if (is_key_frame(t, row))
|
||||
multiCmd->addCommand(new SyncDocument::DeleteCommand(int(trackIndex), row));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,17 +492,18 @@ void TrackView::editPaste()
|
||||
|
||||
assert(ce.track >= 0);
|
||||
assert(ce.track < buffer_width);
|
||||
assert(ce.row >= 0);
|
||||
assert(ce.row < buffer_height);
|
||||
|
||||
assert(ce.keyFrame.row >= 0);
|
||||
assert(ce.keyFrame.row < buffer_height);
|
||||
|
||||
size_t trackPos = editTrack + ce.track;
|
||||
if (trackPos < getTrackCount())
|
||||
{
|
||||
size_t trackIndex = doc->getTrackIndexFromPos(trackPos);
|
||||
size_t row = editRow + ce.row;
|
||||
|
||||
track_key key = ce.keyFrame;
|
||||
key.row += editRow;
|
||||
|
||||
// since we deleted all keyframes in the edit-box already, we can just insert this one.
|
||||
SyncDocument::Command *cmd = new SyncDocument::InsertCommand(int(trackIndex), int(row), ce.keyFrame);
|
||||
SyncDocument::Command *cmd = new SyncDocument::InsertCommand(int(trackIndex), key);
|
||||
multiCmd->addCommand(cmd);
|
||||
}
|
||||
}
|
||||
@ -769,16 +745,20 @@ void TrackView::editEnterValue()
|
||||
if (int(editString.size()) > 0 && editTrack < int(getTrackCount()))
|
||||
{
|
||||
size_t trackIndex = doc->getTrackIndexFromPos(editTrack);
|
||||
sync::Track &t = doc->getTrack(trackIndex);
|
||||
|
||||
sync::Track::KeyFrame newKey;
|
||||
if (t.isKeyFrame(editRow)) newKey = *t.getKeyFrame(editRow); // copy old key
|
||||
const sync_track *t = doc->tracks[trackIndex];
|
||||
|
||||
track_key newKey;
|
||||
newKey.type = KEY_STEP;
|
||||
newKey.row = editRow;
|
||||
int idx = sync_find_key(t, editRow);
|
||||
if (idx >= 0)
|
||||
newKey = t->keys[idx]; // copy old key
|
||||
newKey.value = float(_tstof(editString.c_str())); // modify value
|
||||
editString.clear();
|
||||
|
||||
SyncDocument::Command *cmd = doc->getSetKeyFrameCommand(int(trackIndex), editRow, newKey);
|
||||
|
||||
SyncDocument::Command *cmd = doc->getSetKeyFrameCommand(int(trackIndex), newKey);
|
||||
doc->exec(cmd);
|
||||
|
||||
|
||||
SendMessage(GetParent(getWin()), WM_CURRVALDIRTY, 0, 0);
|
||||
InvalidateRect(getWin(), NULL, FALSE);
|
||||
}
|
||||
@ -790,36 +770,25 @@ void TrackView::editToggleInterpolationType()
|
||||
SyncDocument *doc = getDocument();
|
||||
if (NULL == doc) return;
|
||||
|
||||
if (editTrack < int(getTrackCount()))
|
||||
{
|
||||
if (editTrack < int(getTrackCount())) {
|
||||
size_t trackIndex = doc->getTrackIndexFromPos(editTrack);
|
||||
sync::Track &t = doc->getTrack(trackIndex);
|
||||
|
||||
// search backwards from editRow for the keyframe to modify
|
||||
int row = editRow;
|
||||
for (; row >= 0; --row) if (t.isKeyFrame(row)) break;
|
||||
|
||||
// a negative row means no key was found
|
||||
if (row < 0)
|
||||
{
|
||||
const sync_track *t = doc->tracks[trackIndex];
|
||||
|
||||
int idx = key_idx_floor(t, editRow);
|
||||
if (idx < 0) {
|
||||
MessageBeep(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
// copy old key to new key
|
||||
const sync::Track::KeyFrame *oldKey = t.getKeyFrame(row);
|
||||
assert(NULL != oldKey);
|
||||
sync::Track::KeyFrame newKey(*oldKey);
|
||||
|
||||
// modify interpolation type
|
||||
newKey.interpolationType = sync::Track::KeyFrame::InterpolationType(
|
||||
(int(newKey.interpolationType) + 1) % sync::Track::KeyFrame::IT_COUNT
|
||||
);
|
||||
|
||||
|
||||
// copy and modify
|
||||
track_key newKey = t->keys[idx];
|
||||
newKey.type = (enum key_type)
|
||||
((newKey.type + 1) % KEY_TYPE_COUNT);
|
||||
|
||||
// apply change to data-set
|
||||
SyncDocument::Command *cmd = doc->getSetKeyFrameCommand(int(trackIndex), row, newKey);
|
||||
SyncDocument::Command *cmd = doc->getSetKeyFrameCommand(int(trackIndex), newKey);
|
||||
doc->exec(cmd);
|
||||
|
||||
|
||||
// update user interface
|
||||
SendMessage(GetParent(getWin()), WM_CURRVALDIRTY, 0, 0);
|
||||
InvalidateRect(getWin(), NULL, FALSE);
|
||||
@ -841,15 +810,12 @@ void TrackView::editDelete()
|
||||
assert(selectRight < int(getTrackCount()));
|
||||
|
||||
SyncDocument::MultiCommand *multiCmd = new SyncDocument::MultiCommand();
|
||||
for (int track = selectLeft; track <= selectRight; ++track)
|
||||
{
|
||||
for (int track = selectLeft; track <= selectRight; ++track) {
|
||||
size_t trackIndex = doc->getTrackIndexFromPos(track);
|
||||
sync::Track &t = doc->getTrack(trackIndex);
|
||||
|
||||
for (int row = selectTop; row <= selectBottom; ++row)
|
||||
{
|
||||
if (t.isKeyFrame(row))
|
||||
{
|
||||
const sync_track *t = doc->tracks[trackIndex];
|
||||
|
||||
for (int row = selectTop; row <= selectBottom; ++row) {
|
||||
if (is_key_frame(t, row)) {
|
||||
SyncDocument::Command *cmd = new SyncDocument::DeleteCommand(int(trackIndex), row);
|
||||
multiCmd->addCommand(cmd);
|
||||
}
|
||||
@ -887,21 +853,19 @@ void TrackView::editBiasValue(float amount)
|
||||
}
|
||||
|
||||
SyncDocument::MultiCommand *multiCmd = new SyncDocument::MultiCommand();
|
||||
for (int track = selectLeft; track <= selectRight; ++track)
|
||||
{
|
||||
for (int track = selectLeft; track <= selectRight; ++track) {
|
||||
assert(track < int(getTrackCount()));
|
||||
size_t trackIndex = doc->getTrackIndexFromPos(track);
|
||||
sync::Track &t = doc->getTrack(trackIndex);
|
||||
|
||||
for (int row = selectTop; row <= selectBottom; ++row)
|
||||
{
|
||||
if (t.isKeyFrame(row))
|
||||
{
|
||||
sync::Track::KeyFrame newKey = *t.getKeyFrame(row); // copy old key
|
||||
newKey.value += amount; // modify value
|
||||
|
||||
const sync_track *t = doc->tracks[trackIndex];
|
||||
|
||||
for (int row = selectTop; row <= selectBottom; ++row) {
|
||||
int idx = sync_find_key(t, row);
|
||||
if (idx >= 0) {
|
||||
struct track_key k = t->keys[idx]; // copy old key
|
||||
k.value += amount; // modify value
|
||||
|
||||
// add sub-command
|
||||
SyncDocument::Command *cmd = doc->getSetKeyFrameCommand(int(trackIndex), row, newKey);
|
||||
SyncDocument::Command *cmd = doc->getSetKeyFrameCommand(int(trackIndex), k);
|
||||
multiCmd->addCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,29 +9,70 @@
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <cstdio>
|
||||
#include "../sync/device.h"
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "../sync/sync.h"
|
||||
#include "bass.h"
|
||||
|
||||
class BassTimer : public sync::Timer
|
||||
const float bpm = 150.0f; /* beats per minute */
|
||||
const int rpb = 8; /* rows per beat */
|
||||
const double row_rate = (double(bpm) / 60) * rpb;
|
||||
|
||||
double bass_get_row(HSTREAM h)
|
||||
{
|
||||
public:
|
||||
BassTimer(HSTREAM stream, float bpm, int rowsPerBeat) : stream(stream)
|
||||
{
|
||||
rowRate = (double(bpm) / 60) * rowsPerBeat;
|
||||
}
|
||||
|
||||
// BASS hooks
|
||||
void pause() { BASS_ChannelPause(stream); }
|
||||
void play() { BASS_ChannelPlay(stream, false); }
|
||||
float getTime() { return float(BASS_ChannelBytes2Seconds(stream, BASS_ChannelGetPosition(stream, BASS_POS_BYTE))); }
|
||||
float getRow() { return float(getTime() * rowRate); }
|
||||
void setRow(float row) { BASS_ChannelSetPosition(stream, BASS_ChannelSeconds2Bytes(stream, float(row / rowRate)), BASS_POS_BYTE); }
|
||||
bool isPlaying() { return (BASS_ChannelIsActive(stream) == BASS_ACTIVE_PLAYING); }
|
||||
private:
|
||||
HSTREAM stream;
|
||||
double rowRate;
|
||||
QWORD pos = BASS_ChannelGetPosition(h, BASS_POS_BYTE);
|
||||
double time = BASS_ChannelBytes2Seconds(h, pos);
|
||||
return time * row_rate;
|
||||
}
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
|
||||
void bass_pause(void *d, int flag)
|
||||
{
|
||||
if (flag)
|
||||
BASS_ChannelPause((HSTREAM)d);
|
||||
else
|
||||
BASS_ChannelPlay((HSTREAM)d, false);
|
||||
}
|
||||
|
||||
void bass_set_row(void *d, int row)
|
||||
{
|
||||
QWORD pos = BASS_ChannelSeconds2Bytes((HSTREAM)d, row / row_rate);
|
||||
BASS_ChannelSetPosition((HSTREAM)d, pos, BASS_POS_BYTE);
|
||||
}
|
||||
|
||||
int bass_is_playing(void *d)
|
||||
{
|
||||
return BASS_ChannelIsActive((HSTREAM)d) == BASS_ACTIVE_PLAYING;
|
||||
}
|
||||
|
||||
struct sync_cb bass_cb = {
|
||||
bass_pause,
|
||||
bass_set_row,
|
||||
bass_is_playing
|
||||
};
|
||||
|
||||
#endif /* !defined(SYNC_PLAYER) */
|
||||
|
||||
void die(const char *fmt, ...)
|
||||
{
|
||||
char temp[4096];
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vfprintf(stderr, fmt, va);
|
||||
vsnprintf(temp, sizeof(temp), fmt, va);
|
||||
va_end(va);
|
||||
|
||||
#ifdef _CONSOLE
|
||||
fprintf(stderr, "*** error: %s\n", temp);
|
||||
#else
|
||||
MessageBox(NULL, temp, mainWindowTitle, MB_OK | MB_ICONERROR);
|
||||
#endif
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define WINDOWED 1
|
||||
const unsigned int width = 800;
|
||||
const unsigned int height = 600;
|
||||
@ -61,22 +102,22 @@ int main(int argc, char *argv[])
|
||||
// load tune
|
||||
HSTREAM stream = BASS_StreamCreateFile(false, "tune.ogg", 0, 0, BASS_MP3_SETPOS | ((0 == soundDevice) ? BASS_STREAM_DECODE : 0));
|
||||
if (!stream) throw std::string("failed to open tune");
|
||||
|
||||
// let's just assume 150 BPM (this holds true for the included tune)
|
||||
float bpm = 150.0f;
|
||||
|
||||
// setup timer and construct sync-device
|
||||
BassTimer timer(stream, bpm, 8);
|
||||
std::auto_ptr<sync::Device> syncDevice = std::auto_ptr<sync::Device>(sync::createDevice("sync", timer));
|
||||
if (NULL == syncDevice.get()) throw std::string("something went wrong - failed to connect to host?");
|
||||
|
||||
// get tracks
|
||||
sync::Track &clearRTrack = syncDevice->getTrack("clear.r");
|
||||
sync::Track &clearGTrack = syncDevice->getTrack("clear.g");
|
||||
sync::Track &clearBTrack = syncDevice->getTrack("clear.b");
|
||||
|
||||
sync::Track &camRotTrack = syncDevice->getTrack("cam.rot");
|
||||
sync::Track &camDistTrack = syncDevice->getTrack("cam.dist");
|
||||
sync_device *rocket = sync_create_device("sync");
|
||||
if (!rocket)
|
||||
die("something went wrong - failed to connect to host?");
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
sync_set_callbacks(rocket, &bass_cb, (void *)stream);
|
||||
#endif
|
||||
|
||||
// get tracks
|
||||
struct sync_track
|
||||
*clearRTrack = sync_get_track(rocket, "clear.r"),
|
||||
*clearGTrack = sync_get_track(rocket, "clear.g"),
|
||||
*clearBTrack = sync_get_track(rocket, "clear.b"),
|
||||
*camRotTrack = sync_get_track(rocket, "cam.rot"),
|
||||
*camDistTrack = sync_get_track(rocket, "cam.dist");
|
||||
|
||||
LPD3DXMESH cubeMesh = NULL;
|
||||
if (FAILED(D3DXCreateBox(
|
||||
@ -88,31 +129,31 @@ int main(int argc, char *argv[])
|
||||
|
||||
// let's roll!
|
||||
BASS_Start();
|
||||
timer.play();
|
||||
|
||||
BASS_ChannelPlay(stream, false);
|
||||
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
float row = float(timer.getRow());
|
||||
if (!syncDevice->update(row)) done = true;
|
||||
|
||||
double row = bass_get_row(stream);
|
||||
sync_update(rocket, row);
|
||||
|
||||
// setup clear color
|
||||
D3DXCOLOR clearColor(
|
||||
clearRTrack.getValue(row),
|
||||
clearGTrack.getValue(row),
|
||||
clearBTrack.getValue(row),
|
||||
sync_get_val(clearRTrack, row),
|
||||
sync_get_val(clearGTrack, row),
|
||||
sync_get_val(clearBTrack, row),
|
||||
0.0
|
||||
);
|
||||
|
||||
|
||||
// paint the window
|
||||
device->BeginScene();
|
||||
device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, clearColor, 1.0f, 0);
|
||||
|
||||
|
||||
/* D3DXMATRIX world;
|
||||
device->SetTransform(D3DTS_WORLD, &world); */
|
||||
|
||||
float rot = camRotTrack.getValue(row);
|
||||
float dist = camDistTrack.getValue(row);
|
||||
|
||||
float rot = sync_get_val(camRotTrack, row);
|
||||
float dist = sync_get_val(camDistTrack, row);
|
||||
D3DXVECTOR3 eye(sin(rot) * dist, 0, cos(rot) * dist);
|
||||
D3DXVECTOR3 at(0, 0, 0);
|
||||
D3DXVECTOR3 up(0, 1, 0);
|
||||
@ -147,25 +188,11 @@ int main(int argc, char *argv[])
|
||||
device->Release();
|
||||
d3d->Release();
|
||||
DestroyWindow(hwnd);
|
||||
} catch (const std::exception &e) {
|
||||
die(e.what());
|
||||
} catch (const std::string &str) {
|
||||
die(str.c_str());
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
#ifdef _CONSOLE
|
||||
fprintf(stderr, "*** error: %s\n", e.what());
|
||||
#else
|
||||
MessageBox(NULL, e.what(), NULL, MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
|
||||
#endif
|
||||
ret = -1;
|
||||
}
|
||||
catch (const std::string &str)
|
||||
{
|
||||
#ifdef _CONSOLE
|
||||
fprintf(stderr, "*** error: %s\n", str.c_str());
|
||||
#else
|
||||
MessageBox(NULL, e.what(), NULL, MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
|
||||
#endif
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -117,7 +117,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
@ -191,7 +191,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -267,7 +267,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
|
||||
9
sync/base.h
Normal file
9
sync/base.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef SYNC_BASE_H
|
||||
#define SYNC_BASE_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
|
||||
#endif /* SYNC_BASE_H */
|
||||
34
sync/data.c
Normal file
34
sync/data.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "data.h"
|
||||
#include <assert.h>
|
||||
|
||||
void sync_data_deinit(struct sync_data *d)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (int)d->num_tracks; ++i) {
|
||||
free(d->tracks[i]->name);
|
||||
free(d->tracks[i]->keys);
|
||||
free(d->tracks[i]);
|
||||
}
|
||||
free(d->tracks);
|
||||
}
|
||||
|
||||
int sync_create_track(struct sync_data *d, const char *name)
|
||||
{
|
||||
struct sync_track *t;
|
||||
assert(sync_find_track(d, name) < 0);
|
||||
|
||||
t = malloc(sizeof(*t));
|
||||
t->name = strdup(name);
|
||||
t->keys = NULL;
|
||||
t->num_keys = 0;
|
||||
|
||||
d->num_tracks++;
|
||||
d->tracks = realloc(d->tracks, sizeof(d->tracks[0]) * d->num_tracks);
|
||||
d->tracks[d->num_tracks - 1] = t;
|
||||
|
||||
return (int)d->num_tracks - 1;
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "data.h"
|
||||
using sync::Data;
|
||||
|
||||
Data::~Data()
|
||||
{
|
||||
for (size_t i = 0; i < tracks.size(); ++i) delete tracks[i];
|
||||
}
|
||||
|
||||
size_t Data::createTrack(const std::basic_string<TCHAR> &name)
|
||||
{
|
||||
assert(0 > getTrackIndex(name));
|
||||
|
||||
// insert new track
|
||||
tracks.push_back(new sync::Track(name));
|
||||
|
||||
assert(tracks.size() > 0);
|
||||
return tracks.size() - 1;
|
||||
}
|
||||
|
||||
int Data::getTrackIndex(const std::basic_string<TCHAR> &name)
|
||||
{
|
||||
// search for track
|
||||
for (size_t index = 0; index < tracks.size(); ++index)
|
||||
{
|
||||
if (name == tracks[index]->getName()) return int(index);
|
||||
}
|
||||
|
||||
// not found
|
||||
return -1;
|
||||
}
|
||||
80
sync/data.h
80
sync/data.h
@ -1,61 +1,35 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
/* Copyright (C) 2007-2010 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <exception>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#define TCHAR char
|
||||
#endif
|
||||
#ifndef SYNC_DATA_H
|
||||
#define SYNC_DATA_H
|
||||
|
||||
#include "track.h"
|
||||
|
||||
namespace sync
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sync_data {
|
||||
struct sync_track **tracks;
|
||||
size_t num_tracks;
|
||||
};
|
||||
|
||||
static inline int sync_find_track(struct sync_data *data, const char *name)
|
||||
{
|
||||
class Data
|
||||
{
|
||||
public:
|
||||
~Data();
|
||||
|
||||
int
|
||||
getTrackIndex(const std::basic_string<TCHAR> &name);
|
||||
|
||||
size_t
|
||||
createTrack(const std::basic_string<TCHAR> &name);
|
||||
|
||||
Track &
|
||||
getTrack(size_t track)
|
||||
{
|
||||
assert(track < tracks.size());
|
||||
assert(NULL != tracks[track]);
|
||||
return *tracks[track];
|
||||
}
|
||||
|
||||
const Track &
|
||||
getTrack(size_t track) const
|
||||
{
|
||||
assert(track < tracks.size());
|
||||
assert(NULL != tracks[track]);
|
||||
return *tracks[track];
|
||||
}
|
||||
|
||||
size_t
|
||||
getTrackCount() const
|
||||
{
|
||||
return tracks.size();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<Track*> tracks;
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < (int)data->num_tracks; ++i)
|
||||
if (!strcmp(name, data->tracks[i]->name))
|
||||
return i;
|
||||
return -1; /* not found */
|
||||
}
|
||||
|
||||
void sync_data_deinit(struct sync_data *);
|
||||
int sync_create_track(struct sync_data *, const char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SYNC_DATA_H */
|
||||
|
||||
272
sync/device.c
Normal file
272
sync/device.c
Normal file
@ -0,0 +1,272 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include "sync.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
const char *sync_track_path(const char *base, const char *name)
|
||||
{
|
||||
static char temp[FILENAME_MAX];
|
||||
strncpy(temp, base, sizeof(temp));
|
||||
strncat(temp, "_", sizeof(temp));
|
||||
strncat(temp, name, sizeof(temp));
|
||||
strncat(temp, ".track", sizeof(temp));
|
||||
return temp;
|
||||
}
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
|
||||
#ifndef REMOTE_HOST
|
||||
#define REMOTE_HOST "localhost"
|
||||
#endif
|
||||
#define REMOTE_PORT 1338
|
||||
|
||||
static SOCKET server_connect(const char *host, int nport)
|
||||
{
|
||||
struct hostent *he;
|
||||
struct sockaddr_in addr;
|
||||
char greet[128];
|
||||
SOCKET sock;
|
||||
|
||||
if (!init_network())
|
||||
return INVALID_SOCKET;
|
||||
|
||||
he = gethostbyname(host);
|
||||
if (!he)
|
||||
return INVALID_SOCKET;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(nport);
|
||||
addr.sin_addr.s_addr = ((struct in_addr *)(he->h_addr_list[0]))->s_addr;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
|
||||
send(sock, client_greet, (int)strlen(client_greet), 0);
|
||||
|
||||
recv(sock, greet, (int)strlen(server_greet), 0);
|
||||
if (!strncmp(server_greet, greet, strlen(server_greet)))
|
||||
return sock;
|
||||
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct sync_device *sync_create_device(const char *base)
|
||||
{
|
||||
struct sync_device *d = malloc(sizeof(*d));
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
d->base = strdup(base);
|
||||
if (!d->base) {
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->data.tracks = NULL;
|
||||
d->data.num_tracks = 0;
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
d->cb = d->cb_param = NULL;
|
||||
d->row = -1;
|
||||
d->sock = server_connect(REMOTE_HOST, REMOTE_PORT);
|
||||
#endif
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
#ifdef SYNC_PLAYER
|
||||
|
||||
static int load_track_data(struct sync_track *t, const char *path)
|
||||
{
|
||||
int i;
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (!fp)
|
||||
return 1;
|
||||
|
||||
fread(&t->num_keys, sizeof(size_t), 1, fp);
|
||||
t->keys = malloc(sizeof(struct track_key) * t->num_keys);
|
||||
|
||||
for (i = 0; i < (int)t->num_keys; ++i) {
|
||||
struct track_key *key = t->keys + i;
|
||||
char type;
|
||||
fread(&key->row, sizeof(size_t), 1, fp);
|
||||
fread(&key->value, sizeof(float), 1, fp);
|
||||
fread(&type, sizeof(char), 1, fp);
|
||||
key->type = (enum key_type)type;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sync_update(struct sync_device *d, double row)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void sync_set_callbacks(struct sync_device *d, struct sync_cb *cb, void *cb_param)
|
||||
{
|
||||
d->cb = cb;
|
||||
d->cb_param = cb_param;
|
||||
}
|
||||
|
||||
static int save_track(const struct sync_track *t, const char *path)
|
||||
{
|
||||
int i;
|
||||
FILE *fp = fopen(path, "wb");
|
||||
if (!fp)
|
||||
return 1;
|
||||
|
||||
fwrite(&t->num_keys, sizeof(size_t), 1, fp);
|
||||
for (i = 0; i < (int)t->num_keys; ++i) {
|
||||
char type = (char)t->keys[i].type;
|
||||
fwrite(&t->keys[i].row, sizeof(int), 1, fp);
|
||||
fwrite(&t->keys[i].value, sizeof(float), 1, fp);
|
||||
fwrite(&type, sizeof(char), 1, fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void save_tracks(const char *base, struct sync_data *data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (int)data->num_tracks; ++i) {
|
||||
const struct sync_track *t = data->tracks[i];
|
||||
save_track(t, sync_track_path(base, t->name));
|
||||
}
|
||||
}
|
||||
|
||||
static int request_track_data(SOCKET sock, const char *name, int idx)
|
||||
{
|
||||
int ret;
|
||||
unsigned char cmd = GET_TRACK;
|
||||
size_t name_len = strlen(name);
|
||||
|
||||
/* send request data */
|
||||
ret = send(sock, (char *)&cmd, 1, 0);
|
||||
ret += send(sock, (char *)&idx, sizeof(int), 0);
|
||||
ret += send(sock, (char *)&name_len, sizeof(size_t), 0);
|
||||
ret += send(sock, name, (int)name_len, 0);
|
||||
|
||||
return ret != 1 + sizeof(size_t) * 2 + name_len;
|
||||
}
|
||||
|
||||
static int hanle_set_key_cmd(SOCKET sock, struct sync_data *data)
|
||||
{
|
||||
int ret, track;
|
||||
struct track_key key;
|
||||
unsigned char type;
|
||||
|
||||
ret = recv(sock, (char *)&track, sizeof(int), 0);
|
||||
ret += recv(sock, (char *)&key.row, sizeof(int), 0);
|
||||
ret += recv(sock, (char *)&key.value, sizeof(float), 0);
|
||||
ret += recv(sock, (char *)&type, 1, 0);
|
||||
if (ret != sizeof(int) * 2 + sizeof(float) + 1)
|
||||
return 1;
|
||||
|
||||
assert(type < KEY_TYPE_COUNT);
|
||||
assert(track < (int)data->num_tracks);
|
||||
|
||||
key.type = (enum key_type)type;
|
||||
sync_set_key(data->tracks[track], &key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hanle_del_key_cmd(SOCKET sock, struct sync_data *data)
|
||||
{
|
||||
int ret, track, row;
|
||||
ret = recv(sock, (char *)&track, sizeof(int), 0);
|
||||
ret += recv(sock, (char *)&row, sizeof(int), 0);
|
||||
if (ret != sizeof(int) * 2)
|
||||
return 1;
|
||||
|
||||
assert(track < (int)data->num_tracks);
|
||||
|
||||
sync_del_key(data->tracks[track], row);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sync_update(struct sync_device *d, double row)
|
||||
{
|
||||
/* look for new commands */
|
||||
while (d->sock != INVALID_SOCKET && socket_poll(d->sock)) {
|
||||
unsigned char cmd = 0, flag;
|
||||
int err = 1, row;
|
||||
if (!recv(d->sock, (char *)&cmd, 1, 0)) {
|
||||
d->sock = INVALID_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SET_KEY:
|
||||
err = hanle_set_key_cmd(d->sock, &d->data);
|
||||
break;
|
||||
case DELETE_KEY:
|
||||
err = hanle_del_key_cmd(d->sock, &d->data);
|
||||
break;
|
||||
case SET_ROW:
|
||||
err = recv(d->sock, (char *)&row, sizeof(int), 0) != sizeof(int);
|
||||
if (!err && d->cb && d->cb->set_row)
|
||||
d->cb->set_row(d->cb_param, row);
|
||||
break;
|
||||
case PAUSE:
|
||||
err = recv(d->sock, (char *)&flag, 1, 0) != 1;
|
||||
if (!err && d->cb && d->cb->pause)
|
||||
d->cb->pause(d->cb_param, flag);
|
||||
break;
|
||||
case SAVE_TRACKS:
|
||||
save_tracks(d->base, &d->data);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown cmd: %02x\n", cmd);
|
||||
}
|
||||
if (err) {
|
||||
d->sock = INVALID_SOCKET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (d->cb && d->cb->is_playing && d->cb->is_playing(d->cb_param)) {
|
||||
int nrow = (int)floor(row);
|
||||
if (d->row != nrow && d->sock != INVALID_SOCKET) {
|
||||
unsigned char cmd = SET_ROW;
|
||||
int ret = send(d->sock, (char*)&cmd, 1, 0);
|
||||
ret += send(d->sock, (char*)&nrow, sizeof(int), 0);
|
||||
if (ret != sizeof(int) + 1)
|
||||
d->sock = INVALID_SOCKET;
|
||||
else
|
||||
d->row = nrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct sync_track *sync_get_track(struct sync_device *d, const char *name)
|
||||
{
|
||||
struct sync_track *t;
|
||||
int idx = sync_find_track(&d->data, name);
|
||||
if (idx >= 0)
|
||||
return d->data.tracks[idx];
|
||||
|
||||
idx = sync_create_track(&d->data, name);
|
||||
t = d->data.tracks[idx];
|
||||
|
||||
#if SYNC_PLAYER
|
||||
load_track_data(t, sync_track_path(d->base, name));
|
||||
#else
|
||||
request_track_data(d->sock, name, idx);
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
|
||||
using namespace sync;
|
||||
|
||||
std::string Device::getTrackFileName(std::string trackName)
|
||||
{
|
||||
std::string fileName = baseName.c_str();
|
||||
fileName += "_";
|
||||
fileName += trackName;
|
||||
fileName += ".track";
|
||||
return fileName;
|
||||
}
|
||||
@ -2,40 +2,35 @@
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#ifndef SYNC_H
|
||||
#define SYNC_H
|
||||
#ifndef SYNC_DEVICE_H
|
||||
#define SYNC_DEVICE_H
|
||||
|
||||
#include <string>
|
||||
#include "track.h"
|
||||
#include "data.h"
|
||||
|
||||
namespace sync
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
virtual ~Timer() {};
|
||||
|
||||
virtual void pause() = 0;
|
||||
virtual void play() = 0;
|
||||
virtual float getRow() = 0;
|
||||
virtual void setRow(float pos) = 0;
|
||||
virtual bool isPlaying() = 0;
|
||||
};
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
Device(const std::string &baseName) : baseName(baseName) {}
|
||||
virtual ~Device() {}
|
||||
|
||||
virtual Track &getTrack(const std::string &trackName) = 0;
|
||||
virtual bool update(float row) = 0;
|
||||
protected:
|
||||
std::string getTrackFileName(std::string trackName);
|
||||
const std::string baseName;
|
||||
};
|
||||
|
||||
Device *createDevice(const std::string &baseName, Timer &timer);
|
||||
#ifndef SYNC_PLAYER
|
||||
#include "network.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sync_device {
|
||||
const char *base;
|
||||
struct sync_data data;
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
struct sync_cb *cb;
|
||||
void *cb_param;
|
||||
int row;
|
||||
SOCKET sock;
|
||||
#endif
|
||||
};
|
||||
const char *sync_track_path(const char *base, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SYNC_H */
|
||||
#endif /* SYNC_DEVICE_H */
|
||||
|
||||
@ -1,212 +0,0 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include "data.h"
|
||||
#include "network.h"
|
||||
|
||||
#ifndef REMOTE_HOST
|
||||
#define REMOTE_HOST "localhost"
|
||||
#endif
|
||||
#define REMOTE_PORT 1338
|
||||
|
||||
using namespace sync;
|
||||
|
||||
class ClientDevice : public Device
|
||||
{
|
||||
public:
|
||||
ClientDevice(const std::string &baseName, SOCKET serverSocket, Timer &timer) :
|
||||
Device(baseName),
|
||||
timer(timer),
|
||||
serverRow(-1),
|
||||
serverSocket(NetworkSocket(serverSocket))
|
||||
{
|
||||
}
|
||||
|
||||
~ClientDevice();
|
||||
|
||||
Track &getTrack(const std::string &trackName);
|
||||
bool update(float row);
|
||||
|
||||
private:
|
||||
void saveTracks();
|
||||
|
||||
sync::Data syncData;
|
||||
Timer &timer;
|
||||
|
||||
int serverRow;
|
||||
NetworkSocket serverSocket;
|
||||
};
|
||||
|
||||
ClientDevice::~ClientDevice()
|
||||
{
|
||||
}
|
||||
|
||||
Track &ClientDevice::getTrack(const std::string &trackName)
|
||||
{
|
||||
int index = syncData.getTrackIndex(trackName);
|
||||
if (0 <= index) return syncData.getTrack(size_t(index));
|
||||
|
||||
// send request data
|
||||
unsigned char cmd = GET_TRACK;
|
||||
serverSocket.send((char*)&cmd, 1, 0);
|
||||
size_t clientIndex = syncData.getTrackCount();
|
||||
serverSocket.send((char*)&clientIndex, sizeof(size_t), 0);
|
||||
size_t name_len = trackName.size();
|
||||
serverSocket.send((char*)&name_len, sizeof(size_t), 0);
|
||||
const char *name_str = trackName.c_str();
|
||||
serverSocket.send(name_str, int(name_len), 0);
|
||||
|
||||
// insert new track
|
||||
index = int(syncData.createTrack(trackName));
|
||||
return syncData.getTrack(size_t(index));
|
||||
}
|
||||
|
||||
bool ClientDevice::update(float row)
|
||||
{
|
||||
bool done = false;
|
||||
// look for new commands
|
||||
while (serverSocket.pollRead())
|
||||
{
|
||||
unsigned char cmd = 0;
|
||||
if (serverSocket.recv((char*)&cmd, 1, 0))
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SET_KEY:
|
||||
{
|
||||
int track = 0, row = 0;
|
||||
float value = 0.0f;
|
||||
unsigned char interp = 0;
|
||||
|
||||
serverSocket.recv((char*)&track, sizeof(int), 0);
|
||||
serverSocket.recv((char*)&row, sizeof(int), 0);
|
||||
serverSocket.recv((char*)&value, sizeof(float), 0);
|
||||
serverSocket.recv((char*)&interp, 1, 0);
|
||||
if (!serverSocket.connected()) return true;
|
||||
|
||||
assert(interp < Track::KeyFrame::IT_COUNT);
|
||||
|
||||
sync::Track &t = syncData.getTrack(track);
|
||||
t.setKeyFrame(row,
|
||||
Track::KeyFrame(
|
||||
value,
|
||||
Track::KeyFrame::InterpolationType(interp)
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case DELETE_KEY:
|
||||
{
|
||||
int track = 0, row = 0;
|
||||
serverSocket.recv((char*)&track, sizeof(int), 0);
|
||||
serverSocket.recv((char*)&row, sizeof(int), 0);
|
||||
if (!serverSocket.connected()) return true;
|
||||
|
||||
sync::Track &t = syncData.getTrack(track);
|
||||
t.deleteKeyFrame(row);
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_ROW:
|
||||
{
|
||||
int row;
|
||||
serverSocket.recv((char*)&row, sizeof(int), 0);
|
||||
if (!serverSocket.connected()) return true;
|
||||
timer.setRow(float(row));
|
||||
}
|
||||
break;
|
||||
|
||||
case PAUSE:
|
||||
{
|
||||
char flag;
|
||||
serverSocket.recv((char*)&flag, 1, 0);
|
||||
if (!serverSocket.connected()) return true;
|
||||
if (flag == 0) timer.play();
|
||||
else timer.pause();
|
||||
}
|
||||
break;
|
||||
|
||||
case SAVE_TRACKS:
|
||||
saveTracks();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
fprintf(stderr, "unknown cmd: %02x\n", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timer.isPlaying())
|
||||
{
|
||||
int newServerRow = int(floor(row));
|
||||
if (serverRow != newServerRow && serverSocket.connected())
|
||||
{
|
||||
unsigned char cmd = SET_ROW;
|
||||
serverSocket.send((char*)&cmd, 1, 0);
|
||||
serverSocket.send((char*)&newServerRow, sizeof(int), 0);
|
||||
serverRow = newServerRow;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool saveTrack(const sync::Track &track, std::string fileName)
|
||||
{
|
||||
FILE *fp = fopen(fileName.c_str(), "wb");
|
||||
if (NULL == fp) return false;
|
||||
|
||||
size_t keyFrameCount = track.getKeyFrameCount();
|
||||
fwrite(&keyFrameCount, sizeof(size_t), 1, fp);
|
||||
|
||||
sync::Track::KeyFrameContainer::const_iterator it;
|
||||
for (it = track.keyFramesBegin(); it != track.keyFramesEnd(); ++it)
|
||||
{
|
||||
size_t row = it->first;
|
||||
float value = it->second.value;
|
||||
char interpolationType = char(it->second.interpolationType);
|
||||
|
||||
// write key
|
||||
fwrite(&row, sizeof(size_t), 1, fp);
|
||||
fwrite(&value, sizeof(float), 1, fp);
|
||||
fwrite(&interpolationType, sizeof(char), 1, fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientDevice::saveTracks()
|
||||
{
|
||||
for (size_t i = 0; i < syncData.getTrackCount(); ++i)
|
||||
{
|
||||
const sync::Track &track = syncData.getTrack(i);
|
||||
saveTrack(track, getTrackFileName(track.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
Device *sync::createDevice(const std::string &baseName, Timer &timer)
|
||||
{
|
||||
if (false == initNetwork()) return NULL;
|
||||
|
||||
struct hostent *host = gethostbyname(REMOTE_HOST);
|
||||
if (NULL == host) return NULL;
|
||||
printf("IP address: %s\n", inet_ntoa(*(struct in_addr*)host->h_addr_list[0]));
|
||||
|
||||
struct sockaddr_in sain;
|
||||
sain.sin_family = AF_INET;
|
||||
sain.sin_port = htons(REMOTE_PORT);
|
||||
sain.sin_addr.s_addr = ((struct in_addr *)(host->h_addr_list[0]))->s_addr;
|
||||
|
||||
// connect to server
|
||||
SOCKET serverSocket = serverConnect(&sain);
|
||||
if (INVALID_SOCKET == serverSocket) return NULL;
|
||||
|
||||
ClientDevice *device = new ClientDevice(baseName, serverSocket, timer);
|
||||
return device;
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include "data.h"
|
||||
#include "network.h"
|
||||
|
||||
using namespace sync;
|
||||
|
||||
class PlayerDevice : public Device
|
||||
{
|
||||
public:
|
||||
PlayerDevice(const std::string &baseName, Timer &timer) :
|
||||
Device(baseName),
|
||||
timer(timer)
|
||||
{
|
||||
}
|
||||
|
||||
~PlayerDevice();
|
||||
|
||||
Track &getTrack(const std::string &trackName);
|
||||
bool update(float row);
|
||||
|
||||
private:
|
||||
sync::Data syncData;
|
||||
Timer &timer;
|
||||
};
|
||||
|
||||
PlayerDevice::~PlayerDevice() { }
|
||||
|
||||
static bool loadTrack(sync::Track &track, std::string fileName)
|
||||
{
|
||||
FILE *fp = fopen(fileName.c_str(), "rb");
|
||||
if (NULL == fp) return false;
|
||||
|
||||
size_t keyFrameCount;
|
||||
fread(&keyFrameCount, sizeof(size_t), 1, fp);
|
||||
|
||||
for (size_t i = 0; i < keyFrameCount; ++i)
|
||||
{
|
||||
size_t row;
|
||||
float value;
|
||||
char interp;
|
||||
fread(&row, sizeof(size_t), 1, fp);
|
||||
fread(&value, sizeof(float), 1, fp);
|
||||
fread(&interp, sizeof(char), 1, fp);
|
||||
|
||||
track.setKeyFrame(row,
|
||||
Track::KeyFrame(
|
||||
value,
|
||||
Track::KeyFrame::InterpolationType(interp)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Track &PlayerDevice::getTrack(const std::string &trackName)
|
||||
{
|
||||
int trackIndex = syncData.getTrackIndex(trackName);
|
||||
if (0 <= trackIndex) return syncData.getTrack(trackIndex);
|
||||
|
||||
trackIndex = int(syncData.createTrack(trackName));
|
||||
sync::Track &track = syncData.getTrack(trackIndex);
|
||||
loadTrack(track, getTrackFileName(trackName));
|
||||
return track;
|
||||
}
|
||||
|
||||
bool PlayerDevice::update(float row)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Device *sync::createDevice(const std::string &baseName, Timer &timer)
|
||||
{
|
||||
Device *device = new PlayerDevice(baseName, timer);
|
||||
return device;
|
||||
}
|
||||
123
sync/network.cpp
123
sync/network.cpp
@ -1,123 +0,0 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include "network.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include "../wifi9.h"
|
||||
#include <nds/jtypes.h>
|
||||
#include <dswifi9.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#endif
|
||||
|
||||
bool initNetwork()
|
||||
{
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsaData;
|
||||
if (0 != WSAStartup(MAKEWORD( 2, 0 ), &wsaData)) return false;
|
||||
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0) return false;
|
||||
#endif
|
||||
|
||||
// unix sockets need no init
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void closeNetwork()
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *clientGreeting = "hello, synctracker!";
|
||||
static const char *serverGreeting = "hello, demo!";
|
||||
|
||||
SOCKET clientConnect(SOCKET serverSocket, sockaddr_in *host)
|
||||
{
|
||||
sockaddr_in hostTemp;
|
||||
int hostSize = sizeof(sockaddr_in);
|
||||
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&hostTemp, &hostSize);
|
||||
if (INVALID_SOCKET == clientSocket) return INVALID_SOCKET;
|
||||
|
||||
const char *expectedGreeting = clientGreeting;
|
||||
char recievedGreeting[128];
|
||||
|
||||
recv(clientSocket, recievedGreeting, int(strlen(expectedGreeting)), 0);
|
||||
|
||||
if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0)
|
||||
{
|
||||
closesocket(clientSocket);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
const char *greeting = serverGreeting;
|
||||
send(clientSocket, greeting, int(strlen(greeting)), 0);
|
||||
|
||||
if (NULL != host) *host = hostTemp;
|
||||
return clientSocket;
|
||||
}
|
||||
|
||||
SOCKET serverConnect(struct sockaddr_in *addr)
|
||||
{
|
||||
SOCKET serverSocket = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
connect( serverSocket,(struct sockaddr *)addr, sizeof(struct sockaddr_in));
|
||||
|
||||
const char *greeting = clientGreeting;
|
||||
send(serverSocket, greeting, int(strlen(greeting)), 0);
|
||||
|
||||
const char *expectedGreeting = serverGreeting;
|
||||
char recievedGreeting[128];
|
||||
|
||||
recv(serverSocket, recievedGreeting, int(strlen(expectedGreeting)), 0);
|
||||
if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0)
|
||||
{
|
||||
closesocket(serverSocket);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
bool pollRead(SOCKET socket)
|
||||
{
|
||||
struct timeval timeout = { 0, 0 };
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(socket, &fds);
|
||||
|
||||
// look for new commands
|
||||
return select(0, &fds, NULL, NULL, &timeout) > 0;
|
||||
}
|
||||
#if 0
|
||||
bool recvBlock(SOCKET socket, char *buffer, size_t length, int flags)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while (pos < length)
|
||||
{
|
||||
int ret = recv(socket, &buffer[pos], int(length - pos), flags);
|
||||
if (0 > ret) return false; // error
|
||||
pos += ret;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sendBlock(SOCKET socket, const char *buffer, size_t length, int flags)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while (pos < length)
|
||||
{
|
||||
int ret = send(socket, &buffer[pos], int(length - pos), flags);
|
||||
if (0 > ret) return false; // error
|
||||
pos += ret;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
130
sync/network.h
130
sync/network.h
@ -1,101 +1,65 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
/* Copyright (C) 2007-2010 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_H
|
||||
#define NETWORK_H
|
||||
#ifndef SYNC_NETWORK_H
|
||||
#define SYNC_NETWORK_H
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <winsock2.h>
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h>
|
||||
|
||||
#include <winsock2.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET -1
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
bool initNetwork();
|
||||
void closeNetwork();
|
||||
#include "base.h"
|
||||
|
||||
// SOCKET clientConnect(SOCKET serverSocket);
|
||||
SOCKET clientConnect(SOCKET serverSocket, sockaddr_in *host = NULL);
|
||||
SOCKET serverConnect(struct sockaddr_in *addr);
|
||||
bool pollRead(SOCKET socket);
|
||||
static const char *client_greet = "hello, synctracker!";
|
||||
static const char *server_greet = "hello, demo!";
|
||||
|
||||
class NetworkSocket
|
||||
{
|
||||
public:
|
||||
NetworkSocket() : socket(INVALID_SOCKET) {}
|
||||
explicit NetworkSocket(SOCKET socket) : socket(socket) {}
|
||||
|
||||
bool connected() const { return INVALID_SOCKET != socket; };
|
||||
void disconnect()
|
||||
{
|
||||
closesocket(socket);
|
||||
socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
bool recv(char *buffer, size_t length, int flags)
|
||||
{
|
||||
if (!connected()) return false;
|
||||
int ret = ::recv(socket, buffer, int(length), flags);
|
||||
if (ret != length)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send(const char *buffer, size_t length, int flags)
|
||||
{
|
||||
if (!connected()) return false;
|
||||
int ret = ::send(socket, buffer, int(length), flags);
|
||||
if (ret != length)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pollRead()
|
||||
{
|
||||
if (!connected()) return false;
|
||||
return ::pollRead(socket);
|
||||
}
|
||||
|
||||
private:
|
||||
SOCKET socket;
|
||||
};
|
||||
|
||||
#if 0
|
||||
bool recvBlock(SOCKET socket, char *buffer, size_t length, int flags);
|
||||
bool sendBlock(SOCKET socket, const char *buffer, size_t length, int flags);
|
||||
#endif
|
||||
|
||||
enum RemoteCommand {
|
||||
// server -> client
|
||||
enum {
|
||||
SET_KEY = 0,
|
||||
DELETE_KEY = 1,
|
||||
|
||||
// client -> server
|
||||
GET_TRACK = 2,
|
||||
|
||||
// client -> server, server -> client
|
||||
SET_ROW = 3,
|
||||
|
||||
// server -> client
|
||||
PAUSE = 4,
|
||||
|
||||
SAVE_TRACKS = 5
|
||||
};
|
||||
|
||||
#endif /* NETWORK_H */
|
||||
static inline int init_network()
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSADATA wsa;
|
||||
if (0 != WSAStartup(MAKEWORD(2, 0), &wsa))
|
||||
return 0;
|
||||
if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void close_network()
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int socket_poll(SOCKET socket)
|
||||
{
|
||||
struct timeval to = { 0, 0 };
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(socket, &fds);
|
||||
|
||||
return select(0, &fds, NULL, NULL, &to) > 0;
|
||||
}
|
||||
|
||||
#endif /* SYNC_NETWORK_H */
|
||||
|
||||
34
sync/sync.h
Normal file
34
sync/sync.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2010 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#ifndef SYNC_H
|
||||
#define SYNC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sync_device;
|
||||
struct sync_track;
|
||||
|
||||
struct sync_device *sync_create_device(const char *);
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
struct sync_cb {
|
||||
void (*pause)(void *, int);
|
||||
void (*set_row)(void *, int);
|
||||
int (*is_playing)(void *);
|
||||
};
|
||||
void sync_set_callbacks(struct sync_device *, struct sync_cb *, void *);
|
||||
#endif /* !defined(SYNC_PLAYER) */
|
||||
|
||||
void sync_update(struct sync_device *, double);
|
||||
struct sync_track *sync_get_track(struct sync_device *, const char *);
|
||||
float sync_get_val(const struct sync_track *, double);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SYNC_H) */
|
||||
107
sync/track.c
Normal file
107
sync/track.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* Copyright (C) 2010 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141926
|
||||
#endif
|
||||
|
||||
#include "sync.h"
|
||||
#include "track.h"
|
||||
#include "base.h"
|
||||
|
||||
static float key_linear(const struct track_key k[2], double row)
|
||||
{
|
||||
double t = (row - k[0].row) / (k[1].row - k[0].row);
|
||||
return (float)(k[0].value + (k[1].value - k[0].value) * t);
|
||||
}
|
||||
|
||||
static float key_smooth(const struct track_key k[2], double row)
|
||||
{
|
||||
double t = (row - k[0].row) / (k[1].row - k[0].row);
|
||||
t = (1.0 - cos(t * M_PI)) * 0.5;
|
||||
return (float)(k[0].value + (k[1].value - k[0].value) * t);
|
||||
}
|
||||
|
||||
static float key_ramp(const struct track_key k[2], double row)
|
||||
{
|
||||
double t = (row - k[0].row) / (k[1].row - k[0].row);
|
||||
t = pow(t, 2.0);
|
||||
return (float)(k[0].value + (k[1].value - k[0].value) * t);
|
||||
}
|
||||
|
||||
float sync_get_val(const struct sync_track *t, double row)
|
||||
{
|
||||
int idx, irow;
|
||||
if (!t->num_keys)
|
||||
return 0.0f;
|
||||
|
||||
irow = (int)floor(row);
|
||||
idx = key_idx_floor(t, irow);
|
||||
if (idx < 0)
|
||||
return t->keys[0].value;
|
||||
if (idx > (int)t->num_keys - 2)
|
||||
return t->keys[t->num_keys - 1].value;
|
||||
|
||||
switch (t->keys[idx].type) {
|
||||
case KEY_STEP:
|
||||
return t->keys[idx].value;
|
||||
case KEY_LINEAR:
|
||||
return key_linear(t->keys + idx, row);
|
||||
case KEY_SMOOTH:
|
||||
return key_smooth(t->keys + idx, row);
|
||||
case KEY_RAMP:
|
||||
return key_ramp(t->keys + idx, row);
|
||||
default:
|
||||
assert(0);
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
int sync_find_key(const struct sync_track *t, int row)
|
||||
{
|
||||
int lo = 0, hi = t->num_keys;
|
||||
while (lo < hi) {
|
||||
int mi = (lo + hi) / 2;
|
||||
assert(mi != hi);
|
||||
|
||||
if (t->keys[mi].row < row)
|
||||
lo = mi + 1;
|
||||
else if (t->keys[mi].row > row)
|
||||
hi = mi;
|
||||
else
|
||||
return mi;
|
||||
}
|
||||
return -lo - 1;
|
||||
}
|
||||
|
||||
#ifndef SYNC_PLAYER
|
||||
void sync_set_key(struct sync_track *t, const struct track_key *k)
|
||||
{
|
||||
int idx = sync_find_key(t, k->row);
|
||||
if (idx < 0) {
|
||||
idx = -idx - 1;
|
||||
t->num_keys++;
|
||||
t->keys = realloc(t->keys, sizeof(struct track_key) *
|
||||
t->num_keys);
|
||||
assert(t->keys);
|
||||
memmove(t->keys + idx + 1, t->keys + idx,
|
||||
sizeof(struct track_key) * (t->num_keys - idx - 1));
|
||||
}
|
||||
t->keys[idx] = *k;
|
||||
}
|
||||
|
||||
void sync_del_key(struct sync_track *t, int pos)
|
||||
{
|
||||
int idx = sync_find_key(t, pos);
|
||||
assert(idx >= 0);
|
||||
memmove(t->keys + idx, t->keys + idx + 1,
|
||||
sizeof(struct track_key) * (t->num_keys - idx - 1));
|
||||
assert(t->keys);
|
||||
t->num_keys--;
|
||||
t->keys = realloc(t->keys, t->num_keys * sizeof(struct track_key));
|
||||
}
|
||||
#endif
|
||||
110
sync/track.cpp
110
sync/track.cpp
@ -1,110 +0,0 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
#include "track.h"
|
||||
#include "data.h"
|
||||
using namespace sync;
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/*#ifndef M_PI
|
||||
#define M_PI
|
||||
#endif */
|
||||
|
||||
static inline float step(Track::KeyFrameContainer::const_iterator lower, Track::KeyFrameContainer::const_iterator upper, float time)
|
||||
{
|
||||
return lower->second.value;
|
||||
}
|
||||
|
||||
static inline float lerp(Track::KeyFrameContainer::const_iterator lower, Track::KeyFrameContainer::const_iterator upper, float time)
|
||||
{
|
||||
// find local time
|
||||
float t = (time - lower->first) / (upper->first - lower->first);
|
||||
|
||||
// lerp, bitch
|
||||
float delta = upper->second.value - lower->second.value;
|
||||
return lower->second.value + delta * t;
|
||||
}
|
||||
|
||||
static inline float cosine(Track::KeyFrameContainer::const_iterator lower, Track::KeyFrameContainer::const_iterator upper, float time)
|
||||
{
|
||||
// find local time
|
||||
float t = (time - lower->first) / (upper->first - lower->first);
|
||||
t = float((1.0 - cos(t * M_PI)) * 0.5);
|
||||
|
||||
// lerp, bitch
|
||||
float delta = upper->second.value - lower->second.value;
|
||||
return lower->second.value + delta * t;
|
||||
}
|
||||
|
||||
static inline float ramp(Track::KeyFrameContainer::const_iterator lower, Track::KeyFrameContainer::const_iterator upper, float time)
|
||||
{
|
||||
// find local time
|
||||
float t = (time - lower->first) / (upper->first - lower->first);
|
||||
t = powf(t, 2.0f);
|
||||
|
||||
// lerp, bitch
|
||||
float delta = upper->second.value - lower->second.value;
|
||||
return lower->second.value + delta * t;
|
||||
}
|
||||
|
||||
/*float cosine(float time) const;
|
||||
float ramp(float time) const; */
|
||||
|
||||
float Track::getValue(float time) const
|
||||
{
|
||||
if (keyFrames.size() == 0) return 0.0f;
|
||||
|
||||
// find bounding keyframes
|
||||
int currRow = int(floor(time));
|
||||
KeyFrameContainer::const_iterator upper = keyFrames.upper_bound(currRow);
|
||||
KeyFrameContainer::const_iterator lower = upper;
|
||||
lower--;
|
||||
|
||||
// bounds check
|
||||
if (lower == keyFrames.end()) return upper->second.value;
|
||||
if (upper == keyFrames.end()) return lower->second.value;
|
||||
|
||||
switch (lower->second.interpolationType)
|
||||
{
|
||||
case Track::KeyFrame::IT_STEP: return step( lower, upper, time);
|
||||
case Track::KeyFrame::IT_LERP: return lerp( lower, upper, time);
|
||||
case Track::KeyFrame::IT_COSINE: return cosine(lower, upper, time);
|
||||
case Track::KeyFrame::IT_RAMP: return ramp( lower, upper, time);
|
||||
default:
|
||||
assert(false);
|
||||
return step(lower, upper, time);
|
||||
}
|
||||
}
|
||||
|
||||
bool Track::isKeyFrame(size_t row) const
|
||||
{
|
||||
return keyFrames.find(row) != keyFrames.end();
|
||||
}
|
||||
|
||||
const Track::KeyFrame *Track::getKeyFrame(size_t row) const
|
||||
{
|
||||
KeyFrameContainer::const_iterator iter = keyFrames.find(row);
|
||||
if (iter == keyFrames.end()) return NULL;
|
||||
return &iter->second;
|
||||
}
|
||||
|
||||
void Track::deleteKeyFrame(size_t row)
|
||||
{
|
||||
keyFrames.erase(row);
|
||||
}
|
||||
|
||||
void Track::setKeyFrame(size_t row, const KeyFrame &keyFrame)
|
||||
{
|
||||
keyFrames[row] = keyFrame;
|
||||
}
|
||||
|
||||
void Track::truncate()
|
||||
{
|
||||
keyFrames.clear();
|
||||
}
|
||||
|
||||
115
sync/track.h
115
sync/track.h
@ -1,76 +1,59 @@
|
||||
/* Copyright (C) 2007-2008 Erik Faye-Lund and Egbert Teeselink
|
||||
/* Copyright (C) 2007-2010 Erik Faye-Lund and Egbert Teeselink
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.TXT
|
||||
*/
|
||||
|
||||
#ifndef SYNC_TRACK_H
|
||||
#define SYNC_TRACK_H
|
||||
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "base.h"
|
||||
|
||||
namespace sync
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum key_type {
|
||||
KEY_STEP, /* stay constant */
|
||||
KEY_LINEAR, /* lerp to the next value */
|
||||
KEY_SMOOTH, /* smooth curve to the next value */
|
||||
KEY_RAMP,
|
||||
KEY_TYPE_COUNT
|
||||
};
|
||||
|
||||
struct track_key {
|
||||
int row;
|
||||
float value;
|
||||
enum key_type type;
|
||||
};
|
||||
|
||||
struct sync_track {
|
||||
char *name;
|
||||
struct track_key *keys;
|
||||
size_t num_keys;
|
||||
};
|
||||
|
||||
int sync_find_key(const struct sync_track *, int);
|
||||
static inline int key_idx_floor(const struct sync_track *t, int row)
|
||||
{
|
||||
class Track
|
||||
{
|
||||
public:
|
||||
explicit Track(const std::string &name) : name(name) { }
|
||||
|
||||
struct KeyFrame
|
||||
{
|
||||
enum InterpolationType
|
||||
{
|
||||
IT_STEP,
|
||||
IT_LERP,
|
||||
IT_COSINE,
|
||||
IT_RAMP,
|
||||
IT_COUNT // max value
|
||||
};
|
||||
|
||||
KeyFrame() : value(0.0f), interpolationType(IT_STEP) {}
|
||||
KeyFrame(float value, InterpolationType interpolationType) :
|
||||
value(value),
|
||||
interpolationType(interpolationType)
|
||||
{
|
||||
}
|
||||
|
||||
float value;
|
||||
InterpolationType interpolationType;
|
||||
};
|
||||
|
||||
float getValue(float time) const;
|
||||
|
||||
bool isKeyFrame(size_t row) const;
|
||||
const KeyFrame *getKeyFrame(size_t row) const;
|
||||
|
||||
void deleteKeyFrame(size_t row);
|
||||
void setKeyFrame(size_t row, const KeyFrame &keyFrame);
|
||||
|
||||
void truncate();
|
||||
|
||||
const std::string &getName() const { return name; }
|
||||
|
||||
typedef std::map<size_t, struct KeyFrame> KeyFrameContainer;
|
||||
KeyFrameContainer::const_iterator keyFramesBegin() const { return keyFrames.begin(); }
|
||||
KeyFrameContainer::const_iterator keyFramesEnd() const { return keyFrames.end(); }
|
||||
size_t getKeyFrameCount() const { return keyFrames.size(); }
|
||||
|
||||
KeyFrame::InterpolationType getInterpolationType(int row) const
|
||||
{
|
||||
KeyFrame::InterpolationType interpolationType = KeyFrame::IT_STEP;
|
||||
{
|
||||
KeyFrameContainer::const_iterator upper = keyFrames.upper_bound(row);
|
||||
KeyFrameContainer::const_iterator lower = upper;
|
||||
if (lower != keyFrames.end())
|
||||
{
|
||||
lower--;
|
||||
if (lower != keyFrames.end()) interpolationType = lower->second.interpolationType;
|
||||
}
|
||||
}
|
||||
return interpolationType;
|
||||
}
|
||||
private:
|
||||
KeyFrameContainer keyFrames;
|
||||
std::string name;
|
||||
};
|
||||
int idx = sync_find_key(t, row);
|
||||
if (idx < 0)
|
||||
idx = -idx - 2;
|
||||
return idx;
|
||||
}
|
||||
|
||||
#endif // SYNC_TRACK_H
|
||||
#ifndef SYNC_PLAYER
|
||||
void sync_set_key(struct sync_track *, const struct track_key *);
|
||||
void sync_del_key(struct sync_track *, int);
|
||||
static inline int is_key_frame(const struct sync_track *t, size_t row)
|
||||
{
|
||||
return sync_find_key(t, row) >= 0;
|
||||
}
|
||||
|
||||
#endif /* !defined(SYNC_PLAYER) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SYNC_TRACK_H */
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;SYNC_PLAYER"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -102,7 +102,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;SYNC_PLAYER"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
@ -161,7 +161,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -268,75 +268,15 @@
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\sync\data.cpp"
|
||||
RelativePath=".\sync\data.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\device.cpp"
|
||||
RelativePath=".\sync\device.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\device_client.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\device_player.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug Client|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Client|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\network.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\track.cpp"
|
||||
RelativePath=".\sync\track.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
@ -346,6 +286,10 @@
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\sync\base.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\data.h"
|
||||
>
|
||||
</File>
|
||||
@ -358,6 +302,10 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\sync.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sync\track.h"
|
||||
>
|
||||
</File>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user