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:
Erik Faye-Lund 2010-01-02 17:00:32 +01:00
parent dc1ab70976
commit decf843c04
23 changed files with 1051 additions and 1243 deletions

View File

@ -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>

View 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());

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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
View 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
View 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;
}

View File

@ -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;
}

View File

@ -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
View 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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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();
}

View File

@ -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 */

View File

@ -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>