Initial commit
This commit is contained in:
commit
9e75ca73b2
39 changed files with 2553 additions and 0 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
BIN
audio/.DS_Store
vendored
Normal file
BIN
audio/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
audio/include/.DS_Store
vendored
Normal file
BIN
audio/include/.DS_Store
vendored
Normal file
Binary file not shown.
14
audio/include/audio_handler.h
Normal file
14
audio/include/audio_handler.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef AUDIOHANDLER
|
||||
#define AUDIOHANDLER
|
||||
|
||||
|
||||
void init_audio ();
|
||||
|
||||
void feed_output_buffer ( char *data, int len );
|
||||
|
||||
int send_audio_package ();
|
||||
|
||||
void close_audio ();
|
||||
|
||||
|
||||
#endif
|
||||
24
audio/include/frame_buffer.h
Normal file
24
audio/include/frame_buffer.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef FRAMEBUFFER
|
||||
#define FRAMEBUFFER
|
||||
|
||||
|
||||
typedef struct {
|
||||
int frames_free, frames_used;
|
||||
char *data, *cursor;
|
||||
} frame_buffer;
|
||||
|
||||
|
||||
void init_fb ( frame_buffer *fb );
|
||||
|
||||
void delete_fb ( frame_buffer *fb );
|
||||
|
||||
void clear_fb ( frame_buffer *fb );
|
||||
|
||||
void insert_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len );
|
||||
|
||||
void rewrite_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len );
|
||||
|
||||
char* read_frame_at_cursor_fb ( frame_buffer *fb );
|
||||
|
||||
|
||||
#endif
|
||||
BIN
audio/src/.DS_Store
vendored
Normal file
BIN
audio/src/.DS_Store
vendored
Normal file
Binary file not shown.
348
audio/src/audio_handler.c
Normal file
348
audio/src/audio_handler.c
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <portaudio.h>
|
||||
#include <fvad.h>
|
||||
#include "frame_buffer.h"
|
||||
#include "package_handler.h"
|
||||
#include "anims.h"
|
||||
|
||||
#include "audio_handler.h"
|
||||
|
||||
|
||||
#define SAMPLE_RATE (16000)
|
||||
#define BUFFER_mSECS (30)
|
||||
#define FRAMES_PER_BUFFER (160 * (BUFFER_mSECS/10))
|
||||
|
||||
#define NUM_CHANNELS (1)
|
||||
|
||||
|
||||
/* Select sample format. */
|
||||
#define PA_SAMPLE_TYPE paInt16
|
||||
typedef short SAMPLE;
|
||||
#define SAMPLE_SILENCE (0)
|
||||
#define PRINTF_S_FORMAT "%d"
|
||||
|
||||
|
||||
|
||||
static frame_buffer input_buffer;
|
||||
static frame_buffer output_buffer;
|
||||
|
||||
/* tri-state semaphore-esque variable:
|
||||
* 0 - output_buffer is available
|
||||
* 1 - output_buffer is being inserted into
|
||||
* 2 - output_buffer is being read from */
|
||||
static int write_to_o_buf = 0;
|
||||
|
||||
static bool streams_open;
|
||||
|
||||
static bool voice_activate = false;
|
||||
static int vad_streak = 0;
|
||||
|
||||
static Fvad *vad;
|
||||
|
||||
int send_audio_package ();
|
||||
int send_close_package ();
|
||||
|
||||
static int min_int (int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int o_callback( const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *fb )
|
||||
{
|
||||
(void) fb;
|
||||
unsigned int i;
|
||||
char *o_buf = (char *) outputBuffer;
|
||||
|
||||
(void) inputBuffer; /* Prevent unused variable warnings. */
|
||||
(void) timeInfo;
|
||||
(void) statusFlags;
|
||||
|
||||
if (write_to_o_buf == 0) {
|
||||
write_to_o_buf = 2;
|
||||
if (output_buffer.frames_used > 0) {
|
||||
int frames_to_read = min_int(framesPerBuffer, output_buffer.frames_used);
|
||||
for (int i = 0; i < frames_to_read; i++) {
|
||||
*((SAMPLE *)o_buf) = *((SAMPLE *) read_frame_at_cursor_fb(&output_buffer));
|
||||
o_buf += sizeof(SAMPLE);
|
||||
}
|
||||
} else {
|
||||
*((SAMPLE *)o_buf) = 0;
|
||||
}
|
||||
write_to_o_buf = 0;
|
||||
}
|
||||
|
||||
return paContinue;
|
||||
}
|
||||
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may be called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int i_callback( const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *fb )
|
||||
{
|
||||
(void) fb;
|
||||
int i;
|
||||
char *i_buf = (char *) inputBuffer;
|
||||
|
||||
(void) outputBuffer; /* Prevent unused variable warnings. */
|
||||
(void) timeInfo;
|
||||
(void) statusFlags;
|
||||
|
||||
|
||||
i = fvad_process(vad, (int16_t *) i_buf, framesPerBuffer);
|
||||
|
||||
if ( (i == 1) || voice_activate) {
|
||||
if (!voice_activate) {
|
||||
// set_anim(THINKING_ANIM);
|
||||
puts("Recording...");
|
||||
}
|
||||
if (i == 1) {
|
||||
voice_activate = true;
|
||||
vad_streak = 60;
|
||||
}
|
||||
insert_frames_fb(&input_buffer, i_buf, framesPerBuffer*sizeof(SAMPLE));
|
||||
}
|
||||
|
||||
if (!voice_activate) {
|
||||
rewrite_frames_fb(&input_buffer, i_buf, framesPerBuffer*sizeof(SAMPLE));
|
||||
}
|
||||
|
||||
if (vad_streak >= 1) {
|
||||
vad_streak -= 1;
|
||||
|
||||
if (input_buffer.frames_used == (3*FRAMES_PER_BUFFER)) {
|
||||
send_audio_package();
|
||||
}
|
||||
|
||||
/* This means we had voice audio, but we no longer do so send what we got */
|
||||
if (vad_streak == 0) {
|
||||
voice_activate = false;
|
||||
// set_anim(PULSE_ANIM);
|
||||
if (input_buffer.frames_used > 0) {
|
||||
send_audio_package();
|
||||
}
|
||||
send_close_package();
|
||||
}
|
||||
}
|
||||
|
||||
return paContinue;
|
||||
}
|
||||
|
||||
|
||||
static void handle_input_stream () {
|
||||
PaStreamParameters inputParameters;
|
||||
PaStream* istream;
|
||||
PaError err = paNoError;
|
||||
|
||||
init_fb(&input_buffer);
|
||||
|
||||
|
||||
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
|
||||
if (inputParameters.device == paNoDevice) {
|
||||
fprintf(stderr,"Error: No default input device.\n");
|
||||
goto done;
|
||||
}
|
||||
inputParameters.channelCount = 1; /* mono input */
|
||||
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
|
||||
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency;
|
||||
inputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
|
||||
/* Record some audio. -------------------------------------------- */
|
||||
err = Pa_OpenStream(
|
||||
&istream,
|
||||
&inputParameters,
|
||||
NULL, /* &outputParameters, */
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER,
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
i_callback,
|
||||
&input_buffer );
|
||||
if( err != paNoError ) goto done;
|
||||
|
||||
err = Pa_StartStream( istream );
|
||||
if( err != paNoError ) goto done;
|
||||
|
||||
while( (( err = Pa_IsStreamActive( istream ) ) == 1) && streams_open)
|
||||
{
|
||||
Pa_Sleep(1000);
|
||||
}
|
||||
|
||||
delete_fb(&input_buffer);
|
||||
|
||||
if( err < 0 ) goto done;
|
||||
|
||||
err = Pa_CloseStream( istream );
|
||||
if( err != paNoError ) goto done;
|
||||
|
||||
done:
|
||||
Pa_Terminate();
|
||||
if( err != paNoError )
|
||||
{
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
err = 1; /* Always return 0 or 1, but no other return codes. */
|
||||
}
|
||||
printf("input audio stream error code (0 is SUCCESS): %d\n\n", err);
|
||||
}
|
||||
|
||||
|
||||
static void handle_output_stream () {
|
||||
PaStreamParameters outputParameters;
|
||||
PaStream* ostream;
|
||||
PaError err = paNoError;
|
||||
|
||||
init_fb(&output_buffer);
|
||||
|
||||
|
||||
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
|
||||
if (outputParameters.device == paNoDevice) {
|
||||
fprintf(stderr,"Error: No default output device.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
outputParameters.channelCount = 1; /* mono output */
|
||||
outputParameters.sampleFormat = PA_SAMPLE_TYPE;
|
||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
|
||||
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&ostream,
|
||||
NULL,
|
||||
&outputParameters, /* &outputParameters, */
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER,
|
||||
paClipOff,
|
||||
o_callback,
|
||||
&output_buffer );
|
||||
if( err != paNoError ) goto done;
|
||||
|
||||
err = Pa_StartStream( ostream );
|
||||
if( err != paNoError ) goto done;
|
||||
|
||||
while(((err = Pa_IsStreamActive( ostream ) ) == 1) && streams_open)
|
||||
{
|
||||
Pa_Sleep(1000);
|
||||
}
|
||||
|
||||
delete_fb(&output_buffer);
|
||||
|
||||
if( err < 0 ) goto done;
|
||||
|
||||
err = Pa_CloseStream( ostream );
|
||||
if( err != paNoError ) goto done;
|
||||
|
||||
done:
|
||||
Pa_Terminate();
|
||||
if( err != paNoError )
|
||||
{
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
err = 1; /* Always return 0 or 1, but no other return codes. */
|
||||
}
|
||||
printf("output audio stream error code (0 is SUCCESS): %d\n\n", err);
|
||||
}
|
||||
|
||||
|
||||
void init_audio () {
|
||||
pthread_t in_th, out_th;
|
||||
int err = paNoError;
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) {
|
||||
fprintf(stderr, "error initializing port audio: %s\n", Pa_GetErrorText(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
streams_open = true;
|
||||
|
||||
vad = fvad_new();
|
||||
if (!vad) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fvad_set_sample_rate(vad, SAMPLE_RATE) < 0) {
|
||||
fprintf(stderr, "invalid mode\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fvad_set_mode(vad, 1) < 0) {
|
||||
fprintf(stderr, "invalid mode\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
puts("Creating input and output streams.");
|
||||
sleep(1);
|
||||
pthread_create(&in_th, NULL, (void *) handle_input_stream, NULL);
|
||||
// pthread_create(&out_th, NULL, (void *) handle_output_stream, NULL);
|
||||
|
||||
pthread_join(in_th, NULL);
|
||||
// pthread_join(out_th, NULL);
|
||||
|
||||
fvad_free(vad);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void feed_output_buffer (char * data, int len) {
|
||||
|
||||
while (write_to_o_buf == 2) {
|
||||
struct timespec t;
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = 5000;
|
||||
nanosleep(&t, &t);
|
||||
}
|
||||
write_to_o_buf = 1;
|
||||
insert_frames_fb(&output_buffer, data, len);
|
||||
|
||||
write_to_o_buf = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int send_audio_package () {
|
||||
int err = 0;
|
||||
if ((err = send_package(input_buffer.data, input_buffer.frames_used*sizeof(SAMPLE), 0))) {
|
||||
printf("error sending audio package");
|
||||
}
|
||||
clear_fb(&input_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int send_close_package () {
|
||||
int err = 0;
|
||||
if ((err = send_package("END", strlen("END"), 1))) {
|
||||
fprintf(stderr, "error sending closing package");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void close_audio () {
|
||||
streams_open = false;
|
||||
}
|
||||
|
||||
120
audio/src/frame_buffer.c
Normal file
120
audio/src/frame_buffer.c
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "frame_buffer.h"
|
||||
|
||||
#define BYTES_PER_FRAME (2)
|
||||
#define INITIAL_FRAME_COUNT (480*100)
|
||||
|
||||
|
||||
#define ALPHA (2)
|
||||
|
||||
|
||||
|
||||
void init_fb ( frame_buffer *fb ) {
|
||||
fb->frames_used = 0;
|
||||
fb->frames_free = INITIAL_FRAME_COUNT;
|
||||
fb->data = (char *) malloc(BYTES_PER_FRAME*INITIAL_FRAME_COUNT);
|
||||
fb->cursor = fb->data;
|
||||
}
|
||||
|
||||
|
||||
void delete_fb ( frame_buffer *fb ) {
|
||||
fb->frames_used = 0;
|
||||
fb->frames_free = 0;
|
||||
fb->cursor = NULL;
|
||||
free(fb->data);
|
||||
}
|
||||
|
||||
|
||||
void clear_fb ( frame_buffer *fb ) {
|
||||
free(fb->data);
|
||||
fb->data = (char *) malloc(BYTES_PER_FRAME*INITIAL_FRAME_COUNT);
|
||||
fb->cursor = fb->data;
|
||||
fb->frames_free = INITIAL_FRAME_COUNT;
|
||||
fb->frames_used = 0;
|
||||
}
|
||||
|
||||
|
||||
void insert_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ) {
|
||||
|
||||
int frames = frames_len / BYTES_PER_FRAME;
|
||||
|
||||
int cursor_diff = fb->cursor - fb->data;
|
||||
int data_len = (fb->frames_free+fb->frames_used)*BYTES_PER_FRAME;
|
||||
|
||||
if (frames > fb->frames_free) {
|
||||
fb->data = realloc(fb->data, (data_len+frames_len)*ALPHA);
|
||||
fb->cursor = fb->data+cursor_diff;
|
||||
|
||||
if (fb->frames_used*BYTES_PER_FRAME > data_len-cursor_diff) {
|
||||
memmove(fb->data+data_len, fb->data, (fb->frames_used*BYTES_PER_FRAME)-(data_len-cursor_diff));
|
||||
}
|
||||
fb->frames_used += frames;
|
||||
fb->frames_free = fb->frames_used;
|
||||
}
|
||||
|
||||
data_len = (fb->frames_free+fb->frames_used)*BYTES_PER_FRAME;
|
||||
if (fb->frames_used*BYTES_PER_FRAME > data_len-cursor_diff) {
|
||||
memcpy(fb->data+((fb->frames_used*BYTES_PER_FRAME)-(data_len-cursor_diff)), frame_data, frames_len);
|
||||
fb->frames_free -= frames;
|
||||
fb->frames_used += frames;
|
||||
return;
|
||||
}
|
||||
if (frames_len+(fb->frames_used*BYTES_PER_FRAME) > data_len-cursor_diff) {
|
||||
int non_overlap = data_len - (cursor_diff+(fb->frames_used*BYTES_PER_FRAME));
|
||||
int overlap = frames_len - non_overlap;
|
||||
memcpy(fb->cursor+(fb->frames_used*BYTES_PER_FRAME), frame_data, non_overlap);
|
||||
memcpy(fb->data, &(frame_data[non_overlap]), overlap);
|
||||
fb->frames_free -= frames;
|
||||
fb->frames_used += frames;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(fb->cursor+(fb->frames_used*BYTES_PER_FRAME), frame_data, frames_len);
|
||||
fb->frames_free -= frames;
|
||||
fb->frames_used += frames;
|
||||
}
|
||||
|
||||
|
||||
void rewrite_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ) {
|
||||
int frames = frames_len / BYTES_PER_FRAME;
|
||||
|
||||
if (frames > (fb->frames_used + fb->frames_free)) {
|
||||
fb->data = realloc(fb->data, frames_len*ALPHA);
|
||||
fb->frames_free = frames;
|
||||
fb->frames_used = frames;
|
||||
} else {
|
||||
fb->frames_free = fb->frames_free + fb->frames_used - frames;
|
||||
fb->frames_used = frames;
|
||||
}
|
||||
memcpy(fb->data, frame_data, frames_len);
|
||||
fb->cursor = fb->data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char* read_frame_at_cursor_fb ( frame_buffer *fb ) {
|
||||
char *begin = fb->cursor;
|
||||
int frames_free = fb->frames_free;
|
||||
int frames_used = fb->frames_used;
|
||||
char *data = fb->data;
|
||||
|
||||
if (frames_used == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fb->cursor += BYTES_PER_FRAME;
|
||||
if (fb->cursor >= data + ((frames_free+frames_used)*BYTES_PER_FRAME)) {
|
||||
fb->cursor = data;
|
||||
}
|
||||
|
||||
fb->frames_free += 1;
|
||||
fb->frames_used -= 1;
|
||||
|
||||
return begin;
|
||||
}
|
||||
|
||||
|
||||
BIN
core/.DS_Store
vendored
Normal file
BIN
core/.DS_Store
vendored
Normal file
Binary file not shown.
37
core/Info.plist
Normal file
37
core/Info.plist
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>0.1.0, Copyright 2020 Crimata Technologies LLC</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Crimata</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.crimata.www</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>Crimata</string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>ICON.icns</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.01</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
<key>IFMajorVersion</key>
|
||||
<integer>0</integer>
|
||||
|
||||
<key>IFMinorVersion</key>
|
||||
<integer>1</integer>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
core/build/.DS_Store
vendored
Normal file
BIN
core/build/.DS_Store
vendored
Normal file
Binary file not shown.
37
core/build/apps/Crimata.app/Contents/Info.plist
Normal file
37
core/build/apps/Crimata.app/Contents/Info.plist
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>0.1.0, Copyright 2020 Crimata Technologies LLC</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Crimata</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.crimata.www</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>Crimata</string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>ICON.icns</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.01</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
<key>IFMajorVersion</key>
|
||||
<integer>0</integer>
|
||||
|
||||
<key>IFMinorVersion</key>
|
||||
<integer>1</integer>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
core/build/apps/Crimata.app/Contents/MacOS/Crimata
Executable file
BIN
core/build/apps/Crimata.app/Contents/MacOS/Crimata
Executable file
Binary file not shown.
BIN
core/build/apps/Crimata.app/Contents/Resources/ICON.icns
Normal file
BIN
core/build/apps/Crimata.app/Contents/Resources/ICON.icns
Normal file
Binary file not shown.
BIN
core/build/objects/src/main.o
Normal file
BIN
core/build/objects/src/main.o
Normal file
Binary file not shown.
31
core/include/main.h
Normal file
31
core/include/main.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef __TEST_MAIN
|
||||
#define __TEST_MAIN
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <anims.h>
|
||||
#include <gtk-cairo_api.h>
|
||||
#include <package_handler.h>
|
||||
#include <audio_handler.h>
|
||||
|
||||
GtkBuilder *builder;
|
||||
GObject *homeWindow;
|
||||
GObject *homeBox;
|
||||
GObject *crimataAiBox;
|
||||
|
||||
char *render_text;
|
||||
|
||||
enum anim_e;
|
||||
|
||||
void * anim_handler ();
|
||||
|
||||
int main (int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
88
core/makefile
Normal file
88
core/makefile
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#################################################
|
||||
#
|
||||
# Makefile - Test GUI
|
||||
#
|
||||
# Crimata Technologies 2020
|
||||
#
|
||||
#####################################################
|
||||
|
||||
CXX := -gcc
|
||||
CXXFLAGS := `pkg-config --cflags gtk+-3.0`
|
||||
|
||||
|
||||
LDFLAGS := \
|
||||
-L/usr/lib \
|
||||
-L/usr/local/lib \
|
||||
-lfvad \
|
||||
-lportaudio \
|
||||
|
||||
APP_NAME := Crimata
|
||||
BUILD_DIR := ./build
|
||||
OBJ_DIR := $(BUILD_DIR)/objects
|
||||
APP_DIR := $(BUILD_DIR)/apps
|
||||
EXE_DIR := $(BUILD_DIR)/apps/$(APP_NAME).app/Contents/MacOS
|
||||
INCLUDE := \
|
||||
-I . \
|
||||
-I include/ \
|
||||
-I ../gui/include/ \
|
||||
-I ../networking/include/ \
|
||||
-I ../audio/include/ \
|
||||
-I /usr/include/gtk-3.0
|
||||
|
||||
SRC := \
|
||||
$(wildcard src/main.c) \
|
||||
$(wildcard ../gui/src/gtk-cairo_api.c) \
|
||||
$(wildcard ../gui/src/anims.c) \
|
||||
$(wildcard ../gui/src/eases.c) \
|
||||
$(wildcard ../networking/src/package_handler.c) \
|
||||
$(wildcard ../audio/src/audio_handler.c) \
|
||||
$(wildcard ../audio/src/frame_buffer.c) \
|
||||
|
||||
|
||||
OBJECTS := $(SRC:%.c=$(OBJ_DIR)/%.o)
|
||||
|
||||
|
||||
# Rules
|
||||
all: kill clean build $(EXE_DIR)/$(APP_NAME) run
|
||||
|
||||
|
||||
# Compile all src files into object files into object directory
|
||||
$(OBJ_DIR)/%.o: %.c
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -o $@
|
||||
|
||||
|
||||
# Link and make exe
|
||||
$(EXE_DIR)/$(APP_NAME): $(OBJECTS)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^ `pkg-config --libs gtk+-3.0` $(LDFLAGS)
|
||||
|
||||
|
||||
.PHONY: all build clean debug release
|
||||
|
||||
|
||||
build:
|
||||
@mkdir -p $(APP_DIR)/$(APP_NAME).app/Contents/{MacOS,Resources}
|
||||
@mkdir -p $(OBJ_DIR)
|
||||
@cp Info.plist $(APP_DIR)/$(APP_NAME).app/Contents/
|
||||
@cp resources/* $(APP_DIR)/$(APP_NAME).app/Contents/Resources/
|
||||
|
||||
# debug: CXXFLAGS += -DDEBUG -g
|
||||
# debug: all
|
||||
|
||||
|
||||
# release: CXXFLAGS += -O2
|
||||
# release: all
|
||||
|
||||
|
||||
run: $(EXE_DIR)/$(APP_NAME)
|
||||
# remove object file directories
|
||||
rm -rvf $(BUILD_DIR)/audio $(BUILD_DIR)/gui $(BUILD_DIR)/networking
|
||||
# $<
|
||||
|
||||
|
||||
clean:
|
||||
-@rm -rvf $(BUILD_DIR)/*
|
||||
|
||||
kill:
|
||||
@pkill $(APP_NAME) || true
|
||||
BIN
core/resources/.DS_Store
vendored
Normal file
BIN
core/resources/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
core/resources/ICON.icns
Normal file
BIN
core/resources/ICON.icns
Normal file
Binary file not shown.
172
core/src/main.c
Normal file
172
core/src/main.c
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
** Crimata Technologies - 2020
|
||||
**
|
||||
** Client Main
|
||||
**
|
||||
**
|
||||
** This is the top-level file for the client program. It is the home
|
||||
** of main (), which spawns all the nessesary threads and ensures
|
||||
** the program shutsdown correctly.
|
||||
**
|
||||
** The functions are as follows:
|
||||
**
|
||||
** **********************FUNCTIONS SEMANTICS************************
|
||||
**
|
||||
** 1. main () : spawns three additional threads for audio, networking
|
||||
** and the "main loop" in addition to initiating the GTK gui.
|
||||
**
|
||||
** @ -
|
||||
** @@ -
|
||||
*/
|
||||
|
||||
#include <main.h>
|
||||
|
||||
GtkBuilder *builder;
|
||||
GObject *homeWindow;
|
||||
GObject *homeBox;
|
||||
GObject *crimataAiBox;
|
||||
|
||||
pthread_t drawing_thread;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
enum anim_e
|
||||
{ BOUNCE_ANIM, STANDBY_ANIM };
|
||||
|
||||
static char* user_id;
|
||||
|
||||
// static bool exit = false;
|
||||
|
||||
void * anim_handler ()
|
||||
{
|
||||
//! This will run indefinately, which is fine for the Version 0.1.0.
|
||||
//! This anim will render any value that is at the mem loc of render_text.
|
||||
print_anim ();
|
||||
|
||||
// while (!exit) //! Will return null once exit is true.
|
||||
// {
|
||||
// switch (current_anim)
|
||||
// {
|
||||
// case BOUNCE_ANIM:
|
||||
// bounce_anim ();
|
||||
// break;
|
||||
|
||||
// case STANDBY_ANIM:
|
||||
// standby_anim ();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
||||
void * server_connect (void *ptr)
|
||||
{
|
||||
puts("Connecting to the server!");
|
||||
|
||||
if (connect_socket ( "127.0.0.1", 1040 ) < 0) {
|
||||
puts("error connecting to socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Send the user_id to the backend. */
|
||||
user_id = (char *) malloc(2);
|
||||
strcpy(user_id, "1");
|
||||
send_package(user_id, strlen(user_id), 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void * main_loop (void *ptr)
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
bool exit = false;
|
||||
|
||||
// recv_package() will write to this variable.
|
||||
char *package_response = malloc(sizeof(int));
|
||||
|
||||
while (!exit) {
|
||||
|
||||
int mes_len;
|
||||
int mes_type = recv_package(&package_response, &mes_len);
|
||||
|
||||
switch (mes_type) {
|
||||
|
||||
case 0:
|
||||
printf("audio message length: %d\n", mes_len);
|
||||
feed_output_buffer(package_response, mes_len);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (strcmp(package_response, "EXIT") == 0) {
|
||||
exit = true;
|
||||
} else {
|
||||
//! write to render_text memory address.
|
||||
render_text = (char *) malloc(sizeof package_response);
|
||||
strcpy(render_text, (const char *) package_response);
|
||||
puts((const char *) package_response);
|
||||
}
|
||||
break;
|
||||
|
||||
case -1:
|
||||
puts("error parsing package");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(package_response);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
pthread_t _admin, _main, _audio;
|
||||
|
||||
//! Launch non-UI threads before initializing the UI.
|
||||
//! Le9t's simply try connecting to the server.
|
||||
//! Now, let's kickstarting the main loop.
|
||||
pthread_create(&_admin, NULL, (void *) server_connect, NULL);
|
||||
pthread_create(&_main, NULL, (void *) main_loop, NULL);
|
||||
pthread_create(&_audio, NULL, (void *) init_audio, NULL);
|
||||
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
GError *error = NULL;
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_add_from_file (builder, "../gui/src/window.ui", &error);
|
||||
|
||||
/* Set up hooks for relevant UI elements. */
|
||||
homeWindow = gtk_builder_get_object (builder, "homeWindow");
|
||||
homeBox = gtk_builder_get_object (builder, "homeBox");
|
||||
crimataAiBox = gtk_builder_get_object (builder, "crimataAiBox");
|
||||
|
||||
/* Allocate area of window to have drawing functionality and set dims. */
|
||||
create_cairo_surface(crimataAiBox);
|
||||
|
||||
/* CrimataAi animations */
|
||||
pthread_mutex_init (&mutex, NULL);
|
||||
pthread_create (&drawing_thread, NULL, anim_handler, NULL);
|
||||
|
||||
/* Create a timer to invalidate (refresh) crimataAiBox at 60Hz
|
||||
** Needs to only be called when crimataAiBox is showing.
|
||||
*/
|
||||
g_timeout_add (1000 / 60, invalidate_cb, (void *) crimataAiBox);
|
||||
|
||||
/* Assign UI opertaions using GTK singals */
|
||||
g_signal_connect (homeWindow, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
||||
g_signal_connect (crimataAiBox, "draw", G_CALLBACK (drawing_area_draw_cb), NULL);
|
||||
g_signal_connect (crimataAiBox, "configure-event", G_CALLBACK (resize_cairo_surface_cb), NULL);
|
||||
|
||||
gtk_main();
|
||||
|
||||
|
||||
close_audio();
|
||||
close_socket();
|
||||
|
||||
pthread_join(_audio, NULL);
|
||||
pthread_join(_admin, NULL);
|
||||
// pthread_join(_main, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
gui/include/anims.h
Normal file
28
gui/include/anims.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef ANIMS
|
||||
#define ANIMS
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern cairo_surface_t *surface;
|
||||
extern int surface_width;
|
||||
extern int surface_height;
|
||||
|
||||
extern char *render_text;
|
||||
|
||||
extern pthread_mutex_t mutex;
|
||||
|
||||
void * test_anim ();
|
||||
|
||||
void * print_anim ();
|
||||
|
||||
void * start_up_anim ();
|
||||
|
||||
void * recording_anim ();
|
||||
|
||||
void * standby_anim ();
|
||||
|
||||
void * bounce_anim ();
|
||||
|
||||
#endif
|
||||
46
gui/include/eases.h
Normal file
46
gui/include/eases.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef __EASES
|
||||
#define __EASES
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* Easing Math Utilites */
|
||||
|
||||
float quadratic_ease_in_out(double p, int distance);
|
||||
|
||||
float elastic_ease_out(float p);
|
||||
|
||||
float quadratic_ease_in(float p);
|
||||
|
||||
float quadratic_ease_out(float p);
|
||||
|
||||
float sine_ease_out(float p);
|
||||
|
||||
float back_ease_out(float p);
|
||||
|
||||
float exponential_ease_out(float p);
|
||||
|
||||
float sine_wave (float counter, float f, int A);
|
||||
|
||||
float sin_wave_scaled (float counter, float f, int A);
|
||||
|
||||
// float asin_wave_scaled (float counter, float f, int A, float t);
|
||||
|
||||
float cos_wave (float counter, float f, int A, float t);
|
||||
|
||||
float gravity_wave (float counter, float f, int A, float t);
|
||||
|
||||
float gravity_wave_cos (float counter, float w, float ampl);
|
||||
|
||||
struct Strobes
|
||||
{
|
||||
int positionY;
|
||||
int positionX;
|
||||
|
||||
float velocityY;
|
||||
float velocityX;
|
||||
};
|
||||
|
||||
void damped_oscillator (float anchorX, float anchorY, float k, struct Strobes* circle);
|
||||
|
||||
|
||||
#endif
|
||||
61
gui/include/gtk-cairo_api.h
Normal file
61
gui/include/gtk-cairo_api.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef GTK_CAIRO_API
|
||||
#define GTK_CAIRO_API
|
||||
|
||||
/*
|
||||
** Crimata Technologies - 2020
|
||||
**
|
||||
** Client Gtk-Cairo API
|
||||
**
|
||||
**
|
||||
** An API that serves as a boilerplate for rendering graphics in the
|
||||
** center of a given GObject or GTKWidget.
|
||||
**
|
||||
** The semantics are as follows:
|
||||
|
||||
** **********************VARIABLES SEMANTICS************************
|
||||
|
||||
** 1. @cairo_surface_t *surface : tells functions to look for the
|
||||
** definition of surface in your code.
|
||||
**
|
||||
** 2. pthread_mutex_t mutex : Gives Mutual (MUT) Exclustion (EX)
|
||||
** functionality to functions so that they don't access surface
|
||||
** and context variables at the same time.
|
||||
|
||||
** **********************FUNCTIONS SEMANTICS************************
|
||||
|
||||
**
|
||||
** 3. @@invalidate_cb () : Calls gtk_widget_queue_draw() on a given
|
||||
** widget so that GTK knows to refresh it.
|
||||
**
|
||||
** 4. create_cairo_surface () : Allocate a region of the window to
|
||||
** create (technically update) the surface while also updating its
|
||||
** surface_width and surface_height variables.
|
||||
**
|
||||
** 5. drawing_area_draw_cb () : Set this function up in a callback
|
||||
** so that it can refresh and paint over the cairo source every
|
||||
** "frame" to obtain the animation effect.
|
||||
**
|
||||
** 6. resize_cairo_surface_cb () : Effectivly the same as create_-
|
||||
** cairo_surface but is called everytime the window gets resized.
|
||||
**
|
||||
** @ - https://cairographics.org/manual/cairo-cairo-surface-t.html
|
||||
** @@ - _cb in name means should be used as a GTK callback.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
extern cairo_surface_t *surface;
|
||||
extern int surface_width;
|
||||
extern int surface_height;
|
||||
|
||||
extern pthread_mutex_t mutex;
|
||||
|
||||
gboolean invalidate_cb (gpointer widget);
|
||||
|
||||
void create_cairo_surface (GObject* uiBox);
|
||||
|
||||
void drawing_area_draw_cb (GtkWidget *widget, cairo_t *context);
|
||||
|
||||
void resize_cairo_surface_cb (GtkWidget *widget, GdkEvent *event);
|
||||
|
||||
#endif
|
||||
81
gui/src/anims.c
Normal file
81
gui/src/anims.c
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "anims.h"
|
||||
#include "eases.h"
|
||||
|
||||
static const int frames_per_sec = 60;
|
||||
|
||||
void * init_context ()
|
||||
{
|
||||
pthread_mutex_lock (&mutex);
|
||||
cairo_t *cr = cairo_create (surface);
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_rectangle (cr, 0, 0, surface_width, surface_height);
|
||||
cairo_fill (cr);
|
||||
cairo_translate (cr, surface_width/2, surface_height/2);
|
||||
return cr;
|
||||
}
|
||||
|
||||
void * destroy_context (cairo_t *cr)
|
||||
{
|
||||
cairo_destroy (cr);
|
||||
pthread_mutex_unlock (&mutex);
|
||||
usleep (1E6 / frames_per_sec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Animate a logo through multiple calls and adjusting x y cords.
|
||||
** X's and Y's @ 0 means logo is at default position:
|
||||
**
|
||||
** *
|
||||
** * *
|
||||
*/
|
||||
void logo (cairo_t *cr, float x1, // circle top
|
||||
float y1,
|
||||
float x2, // circle bottom left
|
||||
float y2,
|
||||
float x3, // circle bottom right
|
||||
float y3
|
||||
)
|
||||
{
|
||||
// circle top
|
||||
cairo_arc (cr, x1+0, y1-10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
// circle bottom left
|
||||
cairo_arc (cr, x2-9.34, y2+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
// circle bottom right
|
||||
cairo_arc (cr, x3+9.34, y3+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
// #include "start_up_anim.c"
|
||||
#include "recording_anim.c"
|
||||
#include "standby_anim.c"
|
||||
#include "bounce_anim.c"
|
||||
|
||||
void * print_anim ()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
//! Render text based on global text variable.
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 20);
|
||||
cairo_text_extents (cr, render_text, &te);
|
||||
cairo_move_to (cr, te.width/-2, te.height/2);
|
||||
cairo_show_text (cr, render_text);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
33
gui/src/bounce_anim.c
Normal file
33
gui/src/bounce_anim.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
void * bounce_anim ()
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
logo (cr, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
destroy_context (cr);
|
||||
|
||||
sleep(1);
|
||||
|
||||
int counter = 0;
|
||||
while (1)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
float e = sine_wave (counter, 1.5, 30);
|
||||
e = fabsf(e);
|
||||
logo (cr, 0, // circle top
|
||||
-e,
|
||||
0, // circle bottom left
|
||||
-e,
|
||||
0, // circle bottom right
|
||||
-e
|
||||
);
|
||||
|
||||
destroy_context (cr);
|
||||
counter++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
128
gui/src/eases.c
Normal file
128
gui/src/eases.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#include <eases.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Modeled after the piecewise quadratic
|
||||
// y = (1/2)((2x)^2) ; [0, 0.5)
|
||||
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
|
||||
float quadratic_ease_in_out(double p, int distance)
|
||||
{
|
||||
double s = p / distance;
|
||||
|
||||
if(s < 0.5)
|
||||
{
|
||||
return distance * 2 * s * s;
|
||||
}
|
||||
else
|
||||
{
|
||||
return distance * ((-2 * s * s) + (4 * s) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
|
||||
float elastic_ease_out(float p)
|
||||
{
|
||||
return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1;
|
||||
}
|
||||
|
||||
// Modeled after the parabola y = x^2
|
||||
float quadratic_ease_in(float p)
|
||||
{
|
||||
return p * p;
|
||||
}
|
||||
|
||||
// Modeled after the parabola y = -x^2 + 2x
|
||||
float quadratic_ease_out(float p)
|
||||
{
|
||||
return -(p * (p - 2));
|
||||
}
|
||||
|
||||
// Modeled after quarter-cycle of sine wave (different phase)
|
||||
float sine_ease_out(float p)
|
||||
{
|
||||
return sin(p * M_PI_2);
|
||||
}
|
||||
|
||||
// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
|
||||
float back_ease_out(float p)
|
||||
{
|
||||
float f = (1 - p);
|
||||
return 1 - (f * f * f - f * sin(f * M_PI));
|
||||
}
|
||||
|
||||
// Modeled after the exponential function y = -2^(-10x) + 1
|
||||
float exponential_ease_out(float p)
|
||||
{
|
||||
return (p == 1.0) ? p : 1 - pow(2, -10 * p);
|
||||
}
|
||||
|
||||
float sine_wave (float counter, float f, int A)
|
||||
{
|
||||
float t = counter * 0.01;
|
||||
return A * sin (2 * M_PI * f * t);
|
||||
}
|
||||
|
||||
float sin_wave_scaled (float counter, float f, int A)
|
||||
{
|
||||
int t = counter;
|
||||
return A * sin (2 * M_PI * f * t);
|
||||
}
|
||||
|
||||
// float asin_wave_scaled (float counter, float f, int A, float t)
|
||||
// {
|
||||
// t = counter;
|
||||
// return A * asin (2 * M_PI * f * t);
|
||||
// }
|
||||
|
||||
|
||||
float cos_wave (float counter, float f, int A, float t)
|
||||
{
|
||||
t = counter * 0.01;
|
||||
return A * cos (2 * M_PI * f * t);
|
||||
}
|
||||
|
||||
float gravity_wave (float counter, float f, int A, float t)
|
||||
{
|
||||
t = counter;
|
||||
float x = A * sin (2 * M_PI * f * t);
|
||||
return fabsf(x);
|
||||
}
|
||||
|
||||
float gravity_wave_cos (float counter, float w, float ampl)
|
||||
{
|
||||
float t = 0.5;
|
||||
float x = ampl * cos ( counter * w * t );
|
||||
return fabsf(x);
|
||||
}
|
||||
|
||||
void damped_oscillator (float anchorX, float anchorY, float k, struct Strobes* circle)
|
||||
{
|
||||
|
||||
// constants
|
||||
int gravity = 0;
|
||||
int mass = 10;
|
||||
float timeStep = 0.28;
|
||||
float damping = 10;
|
||||
|
||||
// calculate force Y
|
||||
float springForceY = -k*(circle->positionY - anchorY);
|
||||
float dampingForceY = damping * circle->velocityY;
|
||||
float forceY = springForceY + mass * gravity - dampingForceY;
|
||||
|
||||
// calculate position Y
|
||||
float accelerationY = forceY/mass;
|
||||
circle->velocityY = circle->velocityY + accelerationY * timeStep;
|
||||
circle->positionY = circle->positionY + circle->velocityY * timeStep;
|
||||
|
||||
// calculate force X
|
||||
float springForceX = -k*(circle->positionX - anchorX);
|
||||
float dampingForceX = damping * circle->velocityX;
|
||||
float forceX = springForceX - dampingForceX;
|
||||
|
||||
// calculate position X
|
||||
float accelerationX = forceX/mass;
|
||||
circle->velocityX = circle->velocityX + accelerationX * timeStep;
|
||||
circle->positionX = circle->positionX + circle->velocityX * timeStep;
|
||||
}
|
||||
60
gui/src/gtk-cairo_api.c
Normal file
60
gui/src/gtk-cairo_api.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include <gtk-cairo_api.h>
|
||||
|
||||
cairo_surface_t *surface;
|
||||
int surface_width;
|
||||
int surface_height;
|
||||
|
||||
// // simply call gtk_widget_queue_draw on crimataAiBox
|
||||
gboolean invalidate_cb (gpointer uiBox)
|
||||
{
|
||||
gtk_widget_queue_draw (GTK_WIDGET (uiBox));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// refresh the drawing surface
|
||||
void drawing_area_draw_cb (GtkWidget *widget, cairo_t *context)
|
||||
{
|
||||
// copy the contents of the surface to the current context
|
||||
pthread_mutex_lock (&mutex);
|
||||
|
||||
if (surface != (cairo_surface_t *)NULL)
|
||||
{
|
||||
cairo_set_source_rgb (context, 1, 1, 1);
|
||||
cairo_set_source_surface (context, surface, 0, 0);
|
||||
cairo_paint (context);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
void create_cairo_surface (GObject* uiBox)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation ((GtkWidget*) uiBox, &allocation);
|
||||
|
||||
// create the surface -> what we are going to be painting on
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, allocation.width,
|
||||
allocation.height);
|
||||
|
||||
surface_width = allocation.width;
|
||||
surface_height = allocation.height;
|
||||
}
|
||||
|
||||
/* Create drawing surface on crimataAiBox during Gtk config event. */
|
||||
void resize_cairo_surface_cb (GtkWidget *widget, GdkEvent *event)
|
||||
{
|
||||
if (event->type == GDK_CONFIGURE)
|
||||
{
|
||||
pthread_mutex_lock (&mutex);
|
||||
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, allocation.width,
|
||||
allocation.height);
|
||||
|
||||
surface_width = allocation.width;
|
||||
surface_height = allocation.height;
|
||||
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
}
|
||||
18
gui/src/print_anim.c
Normal file
18
gui/src/print_anim.c
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
void * print_anim ()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
//! Render text based on global text variable.
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, counter/200);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 20);
|
||||
cairo_text_extents (cr, "Crimata", &te);
|
||||
cairo_move_to (cr, te.width/-2+25, te.height/2-4);
|
||||
cairo_show_text (cr, "Crimata");
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
}
|
||||
228
gui/src/recording_anim.c
Normal file
228
gui/src/recording_anim.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/* Scatter dots and move relative to sound effects and
|
||||
** the transcription of the user's voice dynamically renders
|
||||
** on screen.
|
||||
**
|
||||
**
|
||||
** ▼
|
||||
** * ▼ *
|
||||
** ▲ * ▲
|
||||
** ▲
|
||||
**
|
||||
**
|
||||
** "Hey Andrew, how's..."
|
||||
**
|
||||
*/
|
||||
void * recording_anim ()
|
||||
{
|
||||
struct Strobes circle_1;
|
||||
circle_1.positionY=0;
|
||||
circle_1.positionX=0;
|
||||
|
||||
circle_1.velocityY=0;
|
||||
circle_1.velocityX=0;
|
||||
|
||||
struct Strobes circle_2;
|
||||
circle_2.positionY=0;
|
||||
circle_2.positionX=0;
|
||||
|
||||
circle_2.velocityY=0;
|
||||
circle_2.velocityX=0;
|
||||
|
||||
struct Strobes circle_3;
|
||||
circle_3.positionY=0;
|
||||
circle_3.positionX=0;
|
||||
|
||||
circle_3.velocityY=0;
|
||||
circle_3.velocityX=0;
|
||||
|
||||
struct Strobes circle_4;
|
||||
circle_4.positionY=0;
|
||||
circle_4.positionX=0;
|
||||
|
||||
circle_4.velocityY=0;
|
||||
circle_4.velocityX=0;
|
||||
|
||||
struct Strobes circle_5;
|
||||
circle_5.positionY=0;
|
||||
circle_5.positionX=0;
|
||||
|
||||
circle_5.velocityY=0;
|
||||
circle_5.velocityX=0;
|
||||
|
||||
struct Strobes circle_6;
|
||||
circle_6.positionY=0;
|
||||
circle_6.positionX=0;
|
||||
|
||||
circle_6.velocityY=0;
|
||||
circle_6.velocityX=0;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
|
||||
cairo_arc (cr, 0, -10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, -9.34, 6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, 9.34, 6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
destroy_context (cr);
|
||||
|
||||
sleep(1);
|
||||
|
||||
// first damped oscillator animation
|
||||
static float k = 30;
|
||||
for (float c=0; c<1; c+=0.02)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
float c_elastic = exponential_ease_out (c);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
float x1 = -1*c_elastic*30;
|
||||
float y1 = x1/4;
|
||||
cairo_arc (cr, x1-7+2, (y1)-8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.75);
|
||||
damped_oscillator( x1, y1, k, &circle_1 );
|
||||
cairo_arc (cr, circle_1.positionX-7+2, (circle_1.positionY)-8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
|
||||
damped_oscillator( circle_1.positionX, circle_1.positionY, k, &circle_2 );
|
||||
cairo_arc (cr, circle_2.positionX-7+2, (circle_2.positionY)-8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
float x2 = c_elastic*30/2;
|
||||
float y2 = -1*x2;
|
||||
cairo_arc (cr, x2-7+2, y2+8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.75);
|
||||
damped_oscillator( x2, y2, k, &circle_3 );
|
||||
cairo_arc (cr, circle_3.positionX-7+2, (circle_3.positionY)+8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
|
||||
damped_oscillator( circle_3.positionX, circle_3.positionY, k, &circle_4 );
|
||||
cairo_arc (cr, circle_4.positionX-7+2, (circle_4.positionY)+8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
float x3 = c_elastic*30+10;
|
||||
float y3 = -1*x3/4;
|
||||
cairo_arc (cr, x3+7+2, y3, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.75);
|
||||
damped_oscillator( x3, y3, k, &circle_5 );
|
||||
cairo_arc (cr, circle_5.positionX+7+2, (circle_5.positionY), 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
|
||||
damped_oscillator( circle_5.positionX, circle_5.positionY, k, &circle_6 );
|
||||
cairo_arc (cr, circle_6.positionX+7+2, (circle_6.positionY), 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
|
||||
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
for (float c=0; c<10; c+=0.01)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//! where we will input sound values
|
||||
float wav_y = sin_wave_scaled (c, 1.2, 20);
|
||||
float wav_y_2 = sin_wave_scaled (c, 1, 10);
|
||||
float wav_y_3 = sin_wave_scaled (c, 1, 25);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
float x1 = -30;
|
||||
float y1 = wav_y-7.5;
|
||||
cairo_arc (cr, x1-7+2, (y1)-8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.75);
|
||||
damped_oscillator( x1, y1, k, &circle_1 );
|
||||
cairo_arc (cr, circle_1.positionX-7+2, (circle_1.positionY)-8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
|
||||
damped_oscillator( circle_1.positionX, circle_1.positionY, k, &circle_2 );
|
||||
cairo_arc (cr, circle_2.positionX-7+2, (circle_2.positionY)-8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
float x2 = 15;
|
||||
float y2 = wav_y_2-15;
|
||||
cairo_arc (cr, x2-7+2, y2+8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.75);
|
||||
damped_oscillator( x2, y2, k, &circle_3 );
|
||||
cairo_arc (cr, circle_3.positionX-7+2, (circle_3.positionY)+8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
|
||||
damped_oscillator( circle_3.positionX, circle_3.positionY, k, &circle_4 );
|
||||
cairo_arc (cr, circle_4.positionX-7+2, (circle_4.positionY)+8, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
float x3 = 40;
|
||||
float y3 = wav_y_3-10;
|
||||
cairo_arc (cr, x3+7+2, y3, 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.75);
|
||||
damped_oscillator( x3, y3, k, &circle_5 );
|
||||
cairo_arc (cr, circle_5.positionX+7+2, (circle_5.positionY), 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.5);
|
||||
damped_oscillator( circle_5.positionX, circle_5.positionY, k, &circle_6 );
|
||||
cairo_arc (cr, circle_6.positionX+7+2, (circle_6.positionY), 7, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
134
gui/src/standby_anim.c
Normal file
134
gui/src/standby_anim.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/* On start-up animation; poster-child Crimata animation.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
*/
|
||||
void * standby_anim ()
|
||||
{
|
||||
/* Hold starting point for 1s. */
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
logo (cr, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
destroy_context (cr);
|
||||
|
||||
sleep(1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Pulse-out 12 points slow. */
|
||||
for (float counter=0; counter<12; counter+=0.5)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
int e = quadratic_ease_in_out (counter, 12);
|
||||
logo (cr, 0, // circle top
|
||||
-e,
|
||||
-e, // circle bottom left
|
||||
e,
|
||||
e, // circle bottom right
|
||||
e
|
||||
);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
sleep (1);
|
||||
|
||||
/* Pulse-in 12 points fast */
|
||||
for (float counter=0; counter<12; counter+=2)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
/* Begin @ position where the last anim left off */
|
||||
//! might be good thing to automate
|
||||
int offset = 11;
|
||||
int e = quadratic_ease_in_out (counter, 12);
|
||||
logo (cr, 0, // circle top
|
||||
e-offset,
|
||||
e-offset, // circle bottom left
|
||||
-e+offset,
|
||||
-e+offset, // circle bottom right
|
||||
-e+offset
|
||||
);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
/* Accellerate rotation. */
|
||||
for (float speed=0; speed<1; speed+=0.1)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
float v = quadratic_ease_in (speed);
|
||||
cairo_rotate(cr, 10*v);
|
||||
|
||||
logo (cr, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
/* Decellerate rotation. */
|
||||
for (float speed=0; speed<1; speed+=0.01)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
float v = sine_ease_out (speed);
|
||||
cairo_rotate(cr, 80*v-2.5);
|
||||
|
||||
logo (cr, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
sleep (1);
|
||||
|
||||
/* Pulse-out-in 8 points twice. */
|
||||
for (float c=0; c<2; c++)
|
||||
{
|
||||
for (float counter=0; counter<8; counter+=1)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
int e = quadratic_ease_in_out (counter, 8);
|
||||
logo (cr, 0, // circle top
|
||||
-e,
|
||||
-e, // circle bottom left
|
||||
e,
|
||||
e, // circle bottom right
|
||||
e
|
||||
);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
for (float counter=0; counter<8; counter+=1)
|
||||
{
|
||||
cairo_t *cr = init_context ();
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
int offset = 7;
|
||||
int e = quadratic_ease_in_out (counter, 8);
|
||||
logo (cr, 0, // circle top
|
||||
e-offset,
|
||||
e-offset, // circle bottom left
|
||||
-e+offset,
|
||||
-e+offset, // circle bottom right
|
||||
-e+offset
|
||||
);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
}
|
||||
sleep(8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
195
gui/src/start_up_anim.c
Normal file
195
gui/src/start_up_anim.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
void * start_up_anim ()
|
||||
{
|
||||
sleep (1);
|
||||
static const char *render_text = "Good Morning";
|
||||
|
||||
for (float counter=0; counter<100; counter+=2)
|
||||
{
|
||||
int x_dist = 100;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_scale(cr, 0.9, 0.9);
|
||||
|
||||
/* X-Axis Ease */
|
||||
float ease_x = quadratic_ease_in_out(counter, x_dist);
|
||||
|
||||
/* Logo */
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, counter/x_dist);
|
||||
cairo_arc (cr, ease_x, -10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, ease_x-9.34, 6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, ease_x+9.34, 6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
for (float counter=0; counter<200; counter+=10)
|
||||
{
|
||||
int last_pos_x = 100;
|
||||
int x_dist = 185;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_scale(cr, 0.9, 0.9);
|
||||
|
||||
double ease_x = quadratic_ease_in_out(counter, x_dist);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_arc (cr, (ease_x*-1)+last_pos_x, -10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, (ease_x*-1)+last_pos_x-9.34, 6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, (ease_x*-1)+last_pos_x+9.34, 6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, counter/200);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 40);
|
||||
cairo_text_extents (cr, "Crimata", &te);
|
||||
cairo_move_to (cr, te.width/-2+25, te.height/2-4);
|
||||
cairo_show_text (cr, "Crimata");
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
for (float counter=0; counter<10; counter+=1)
|
||||
{
|
||||
int last_pos_x = -85;
|
||||
int y_dist = 10;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_scale(cr, 0.9, 0.9);
|
||||
|
||||
double ease_y = quadratic_ease_in_out(counter, y_dist);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_arc (cr, last_pos_x, ease_y-10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x-9.34, ease_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x+9.34, ease_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 40);
|
||||
cairo_text_extents (cr, "Crimata", &te);
|
||||
cairo_move_to (cr, te.width/-2+25, te.height/2-4);
|
||||
cairo_show_text (cr, "Crimata");
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
for (float counter=0; counter<15; counter+=1)
|
||||
{
|
||||
int last_pos_x = -85;
|
||||
int last_pos_y = 10;
|
||||
int y_dist = 15;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_scale(cr, 0.9, 0.9);
|
||||
|
||||
double ease_y = quadratic_ease_in_out(counter, y_dist);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_arc (cr, last_pos_x, (ease_y*-1)+last_pos_y-10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x-9.34, (ease_y*-1)+last_pos_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x+9.34, (ease_y*-1)+last_pos_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 40);
|
||||
cairo_text_extents (cr, "Crimata", &te);
|
||||
cairo_move_to (cr, te.width/-2+25, te.height/2-4);
|
||||
cairo_show_text (cr, "Crimata");
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
for (float counter=0; counter<5; counter+=0.25)
|
||||
{
|
||||
int last_pos_x = -85;
|
||||
int last_pos_y = -5;
|
||||
int y_dist = 5;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_scale(cr, 0.9, 0.9);
|
||||
|
||||
double ease_y = quadratic_ease_in_out(counter, y_dist);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_arc (cr, last_pos_x, ease_y+last_pos_y-10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x-9.34, ease_y+last_pos_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x+9.34, ease_y+last_pos_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 40);
|
||||
cairo_text_extents (cr, "Crimata", &te);
|
||||
cairo_move_to (cr, te.width/-2+25, te.height/2-4);
|
||||
cairo_show_text (cr, "Crimata");
|
||||
|
||||
// Render text beta.
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 12);
|
||||
cairo_text_extents (cr, render_text, &te);
|
||||
cairo_move_to (cr, te.width/-2, te.height/2+60);
|
||||
cairo_show_text (cr, render_text);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
int last_pos_x = -85;
|
||||
int last_pos_y = 0;
|
||||
|
||||
cairo_t *cr = init_context ();
|
||||
|
||||
cairo_scale(cr, 0.9, 0.9);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_arc (cr, last_pos_x, last_pos_y-10, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x-9.34, last_pos_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
cairo_arc (cr, last_pos_x+9.34, last_pos_y+6, 7.25, 0, 6.28);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_text_extents_t te;
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 40);
|
||||
cairo_text_extents (cr, "Crimata", &te);
|
||||
cairo_move_to (cr, te.width/-2+25, te.height/2-4);
|
||||
cairo_show_text (cr, "Crimata");
|
||||
|
||||
// Render text beta.
|
||||
cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 1);
|
||||
cairo_select_font_face (cr, "Montserrat", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 12);
|
||||
cairo_text_extents (cr, render_text, &te);
|
||||
cairo_move_to (cr, te.width/-2, te.height/2+60);
|
||||
cairo_show_text (cr, render_text);
|
||||
|
||||
destroy_context (cr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
55
gui/src/window 2.css
Normal file
55
gui/src/window 2.css
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
.font {
|
||||
font-family: Verdana;
|
||||
}
|
||||
|
||||
.cssTest {
|
||||
color: #383838;
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.loginButton {
|
||||
color: #383838;
|
||||
font-weight: normal;
|
||||
border-radius: 20px;
|
||||
border: none;
|
||||
background-image: linear-gradient(45deg, #F6F5F4, #F6F5F4);
|
||||
}
|
||||
|
||||
.loginButton:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.window {
|
||||
background-color: white;
|
||||
/* border-radius: 20px;
|
||||
*/}
|
||||
|
||||
.version {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.titlebar {
|
||||
border-radius: 0px;
|
||||
background-image: linear-gradient(45deg, #F6F5F4, #F6F5F4);
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.homeHeaderLabel {
|
||||
color: #383838;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.settingsButton {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.settingsButton:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*.customCloseButton {
|
||||
border-radius: 20;
|
||||
height: 5px;
|
||||
}*/
|
||||
31
gui/src/window 2.ui
Normal file
31
gui/src/window 2.ui
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.36.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<object class="GtkWindow" id="homeWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Crimata Tech</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="default_width">600</property>
|
||||
<property name="default_height">350</property>
|
||||
<property name="gravity">center</property>
|
||||
<child>
|
||||
<object class="GtkDrawingArea" id="crimataAiBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_top">0</property>
|
||||
<property name="margin_bottom">0</property>
|
||||
<style>
|
||||
<class name="crimataAiBox"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="window"/>
|
||||
</style>
|
||||
</object>
|
||||
</interface>
|
||||
55
gui/src/window.css
Normal file
55
gui/src/window.css
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
.font {
|
||||
font-family: Verdana;
|
||||
}
|
||||
|
||||
.cssTest {
|
||||
color: #383838;
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.loginButton {
|
||||
color: #383838;
|
||||
font-weight: normal;
|
||||
border-radius: 20px;
|
||||
border: none;
|
||||
background-image: linear-gradient(45deg, #F6F5F4, #F6F5F4);
|
||||
}
|
||||
|
||||
.loginButton:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.window {
|
||||
background-color: white;
|
||||
/* border-radius: 20px;
|
||||
*/}
|
||||
|
||||
.version {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.titlebar {
|
||||
border-radius: 0px;
|
||||
background-image: linear-gradient(45deg, #F6F5F4, #F6F5F4);
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.homeHeaderLabel {
|
||||
color: #383838;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.settingsButton {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.settingsButton:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*.customCloseButton {
|
||||
border-radius: 20;
|
||||
height: 5px;
|
||||
}*/
|
||||
31
gui/src/window.ui
Normal file
31
gui/src/window.ui
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.36.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<object class="GtkWindow" id="homeWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Crimata Tech</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="default_width">600</property>
|
||||
<property name="default_height">350</property>
|
||||
<property name="gravity">center</property>
|
||||
<child>
|
||||
<object class="GtkDrawingArea" id="crimataAiBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_top">0</property>
|
||||
<property name="margin_bottom">0</property>
|
||||
<style>
|
||||
<class name="crimataAiBox"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="window"/>
|
||||
</style>
|
||||
</object>
|
||||
</interface>
|
||||
18
networking/include/package_handler 2.h
Normal file
18
networking/include/package_handler 2.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef NETWORK
|
||||
#define NETWORK
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int connect_socket ( char *server_ip , int port );
|
||||
|
||||
int socket_send ( char *message, int len );
|
||||
|
||||
int send_package ( char *data, int mes_len, int type );
|
||||
|
||||
int socket_recv ( char *response, int resp_len );
|
||||
|
||||
int recv_package ( char **data, int *mes_len );
|
||||
|
||||
int close_socket ();
|
||||
|
||||
#endif
|
||||
18
networking/include/package_handler.h
Normal file
18
networking/include/package_handler.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef NETWORK
|
||||
#define NETWORK
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int connect_socket ( char *server_ip , int port );
|
||||
|
||||
int socket_send ( char *message, int len );
|
||||
|
||||
int send_package ( char *data, int mes_len, int type );
|
||||
|
||||
int socket_recv ( char *response, int resp_len );
|
||||
|
||||
int recv_package ( char **data, int *mes_len );
|
||||
|
||||
int close_socket ();
|
||||
|
||||
#endif
|
||||
231
networking/src/package_handler 2.c
Normal file
231
networking/src/package_handler 2.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
** Crimata Technologies - 2020
|
||||
**
|
||||
** Package Handler: Landon Clark
|
||||
**
|
||||
**
|
||||
** This file seeks to define quality-of-life functionality for client-side
|
||||
** networking. This implementation allows us to hold our client socket
|
||||
** information while abstracting away any handling of the socket data itself.
|
||||
**
|
||||
** The functions are as follows:
|
||||
**
|
||||
** *********************FUNCTIONS SEMANTICS*************************
|
||||
**
|
||||
** 1. @connect_socket ( host name, port number ) : This method allows us to
|
||||
** initiate our client side socket with only an IP and port, thus abstracting
|
||||
** the tedious and largely uniform aspects of the TCP socket away.
|
||||
**
|
||||
** 2. socket_send ( message, message length ) : This method allows us the
|
||||
** ability to send a message across our pre-established socket needing only
|
||||
** the message itself.
|
||||
**
|
||||
** 3. send_package ( package, package length ) : This method wraps up audio
|
||||
** data as an audio package and sends it across the pre-established socket.
|
||||
**
|
||||
** 4. @@socket_recv ( message, message length ) : This method places 'message
|
||||
** length' adjacent bytes of data received from the socket in the memory
|
||||
** held by message.
|
||||
**
|
||||
** 5. recv_package ( package, package length ) : This method parses a received
|
||||
** message to determine what type of message was sent, returns that value and
|
||||
** stores the length of the data in the 'message length' variable and the
|
||||
** actual data in ['message length' * sizeof('message type')] adjacent bytes
|
||||
** starting at 'package'. The data returned in 'package' should be handled
|
||||
** depending on the return value of this method as an audio message does not
|
||||
** contain 'char' data while a text message does.
|
||||
**
|
||||
** 6. close_socket () : This method handles the closing of our pre-established
|
||||
** socket.
|
||||
**
|
||||
**
|
||||
** @ - This needs to be done before any other method - there are no
|
||||
** protections on doing the others first, but they will not work as expected.
|
||||
**
|
||||
** @@ - Should be essentially a helper function as (4) handles packages which
|
||||
** will likely be how we receive data from our sockets anyways.
|
||||
*/
|
||||
|
||||
|
||||
/* LIBRARIES */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> //strlen
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h> //inet_addr
|
||||
#include <unistd.h>
|
||||
|
||||
/* HEADER FILE */
|
||||
#include "package_handler.h"
|
||||
|
||||
/* ERROR macro to return if problems occur */
|
||||
#define ERROR -1
|
||||
|
||||
/* Packages will either be audio or text, an enum exposes this pretty well */
|
||||
enum _package_type {
|
||||
AUDIO,
|
||||
TEXT,
|
||||
};
|
||||
|
||||
|
||||
/* This value will hold our socket information statically, allowing it to live
|
||||
* outside of this files lifetime which may be essential */
|
||||
static int socket_desc;
|
||||
|
||||
|
||||
/* Predefined header length as determined by Crimata Backend */
|
||||
size_t HEADER_LENGTH = 20;
|
||||
|
||||
|
||||
int min_int (int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
/* Boilerplate socket connection function */
|
||||
int connect_socket ( char *server_ip , int port ) {
|
||||
|
||||
struct sockaddr_in server;
|
||||
|
||||
//Create socket
|
||||
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
|
||||
if (socket_desc == ERROR)
|
||||
{
|
||||
printf("Could not create socket");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
server.sin_addr.s_addr = inet_addr(server_ip);
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons( port );
|
||||
|
||||
//Connect to remote server
|
||||
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
|
||||
{
|
||||
puts("connect error");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
puts("Connected\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Boilerplate message sending function */
|
||||
int socket_send ( char *message, int len ) {
|
||||
|
||||
if (send(socket_desc , message , len , 0) < 0)
|
||||
{
|
||||
puts("Send failed");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int send_package ( char *data, int mes_len, int type ) {
|
||||
|
||||
char header[HEADER_LENGTH];
|
||||
char len[12];
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
strcpy(header, "aud-");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
strcpy(header, "txt-");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
strcpy(header, "con-");
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(len, "%d", mes_len);
|
||||
|
||||
// makes eg. "aud-1532"
|
||||
strcat(header, len);
|
||||
|
||||
sprintf(header, "%-20s", header);
|
||||
|
||||
// sending header and data separately
|
||||
if ( socket_send(header, HEADER_LENGTH) < 0 ) {
|
||||
puts("failed to send package header");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if ( socket_send(data, mes_len) < 0) {
|
||||
puts("failed to send package data");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Boilerplate message receiving function */
|
||||
int socket_recv ( char *response, int resp_len ) {
|
||||
|
||||
int bytes_left = resp_len;
|
||||
int bytes_read = 0;
|
||||
|
||||
int _read = 0;
|
||||
|
||||
while (bytes_left > 0) {
|
||||
_read = recv(socket_desc, &(response[bytes_read]), bytes_left, 0);
|
||||
bytes_read += _read;
|
||||
bytes_left -= _read;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Boilerplate package parsing function */
|
||||
int recv_package ( char **data, int *mes_len ) {
|
||||
|
||||
char header[HEADER_LENGTH+1];
|
||||
char *mes_type;
|
||||
|
||||
if ( socket_recv(header, HEADER_LENGTH) < 0 ) {
|
||||
puts("receiving packet failed");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
mes_type = strtok(header, "-");
|
||||
*mes_len = atoi((const char *) strtok(NULL, "\0"));
|
||||
|
||||
*data = realloc(*data, (*mes_len+1)*sizeof(char));
|
||||
|
||||
if ( socket_recv(*data, *mes_len) < 0 ) {
|
||||
puts("failed to receive data from package");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if ( strcmp(mes_type, "aud") == 0 ) {
|
||||
return AUDIO;
|
||||
}
|
||||
|
||||
if ( strcmp(mes_type, "txt") == 0 ) {
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
puts("could not find package type");
|
||||
return ERROR;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Boilerplate socket closing function */
|
||||
int close_socket () {
|
||||
if (close(socket_desc) < 0) {
|
||||
return ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
231
networking/src/package_handler.c
Normal file
231
networking/src/package_handler.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
** Crimata Technologies - 2020
|
||||
**
|
||||
** Package Handler: Landon Clark
|
||||
**
|
||||
**
|
||||
** This file seeks to define quality-of-life functionality for client-side
|
||||
** networking. This implementation allows us to hold our client socket
|
||||
** information while abstracting away any handling of the socket data itself.
|
||||
**
|
||||
** The functions are as follows:
|
||||
**
|
||||
** *********************FUNCTIONS SEMANTICS*************************
|
||||
**
|
||||
** 1. @connect_socket ( host name, port number ) : This method allows us to
|
||||
** initiate our client side socket with only an IP and port, thus abstracting
|
||||
** the tedious and largely uniform aspects of the TCP socket away.
|
||||
**
|
||||
** 2. socket_send ( message, message length ) : This method allows us the
|
||||
** ability to send a message across our pre-established socket needing only
|
||||
** the message itself.
|
||||
**
|
||||
** 3. send_package ( package, package length ) : This method wraps up audio
|
||||
** data as an audio package and sends it across the pre-established socket.
|
||||
**
|
||||
** 4. @@socket_recv ( message, message length ) : This method places 'message
|
||||
** length' adjacent bytes of data received from the socket in the memory
|
||||
** held by message.
|
||||
**
|
||||
** 5. recv_package ( package, package length ) : This method parses a received
|
||||
** message to determine what type of message was sent, returns that value and
|
||||
** stores the length of the data in the 'message length' variable and the
|
||||
** actual data in ['message length' * sizeof('message type')] adjacent bytes
|
||||
** starting at 'package'. The data returned in 'package' should be handled
|
||||
** depending on the return value of this method as an audio message does not
|
||||
** contain 'char' data while a text message does.
|
||||
**
|
||||
** 6. close_socket () : This method handles the closing of our pre-established
|
||||
** socket.
|
||||
**
|
||||
**
|
||||
** @ - This needs to be done before any other method - there are no
|
||||
** protections on doing the others first, but they will not work as expected.
|
||||
**
|
||||
** @@ - Should be essentially a helper function as (4) handles packages which
|
||||
** will likely be how we receive data from our sockets anyways.
|
||||
*/
|
||||
|
||||
|
||||
/* LIBRARIES */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> //strlen
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h> //inet_addr
|
||||
#include <unistd.h>
|
||||
|
||||
/* HEADER FILE */
|
||||
#include "package_handler.h"
|
||||
|
||||
/* ERROR macro to return if problems occur */
|
||||
#define ERROR -1
|
||||
|
||||
/* Packages will either be audio or text, an enum exposes this pretty well */
|
||||
enum _package_type {
|
||||
AUDIO,
|
||||
TEXT,
|
||||
};
|
||||
|
||||
|
||||
/* This value will hold our socket information statically, allowing it to live
|
||||
* outside of this files lifetime which may be essential */
|
||||
static int socket_desc;
|
||||
|
||||
|
||||
/* Predefined header length as determined by Crimata Backend */
|
||||
size_t HEADER_LENGTH = 20;
|
||||
|
||||
|
||||
int min_int (int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
/* Boilerplate socket connection function */
|
||||
int connect_socket ( char *server_ip , int port ) {
|
||||
|
||||
struct sockaddr_in server;
|
||||
|
||||
//Create socket
|
||||
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
|
||||
if (socket_desc == ERROR)
|
||||
{
|
||||
printf("Could not create socket");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
server.sin_addr.s_addr = inet_addr(server_ip);
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons( port );
|
||||
|
||||
//Connect to remote server
|
||||
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
|
||||
{
|
||||
puts("connect error");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
puts("Connected\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Boilerplate message sending function */
|
||||
int socket_send ( char *message, int len ) {
|
||||
|
||||
if (send(socket_desc , message , len , 0) < 0)
|
||||
{
|
||||
puts("Send failed");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int send_package ( char *data, int mes_len, int type ) {
|
||||
|
||||
char header[HEADER_LENGTH];
|
||||
char len[12];
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
strcpy(header, "aud-");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
strcpy(header, "txt-");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
strcpy(header, "con-");
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(len, "%d", mes_len);
|
||||
|
||||
// makes eg. "aud-1532"
|
||||
strcat(header, len);
|
||||
|
||||
sprintf(header, "%-20s", header);
|
||||
|
||||
// sending header and data separately
|
||||
if ( socket_send(header, HEADER_LENGTH) < 0 ) {
|
||||
puts("failed to send package header");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if ( socket_send(data, mes_len) < 0) {
|
||||
puts("failed to send package data");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Boilerplate message receiving function */
|
||||
int socket_recv ( char *response, int resp_len ) {
|
||||
|
||||
int bytes_left = resp_len;
|
||||
int bytes_read = 0;
|
||||
|
||||
int _read = 0;
|
||||
|
||||
while (bytes_left > 0) {
|
||||
_read = recv(socket_desc, &(response[bytes_read]), bytes_left, 0);
|
||||
bytes_read += _read;
|
||||
bytes_left -= _read;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Boilerplate package parsing function */
|
||||
int recv_package ( char **data, int *mes_len ) {
|
||||
|
||||
char header[HEADER_LENGTH+1];
|
||||
char *mes_type;
|
||||
|
||||
if ( socket_recv(header, HEADER_LENGTH) < 0 ) {
|
||||
puts("receiving packet failed");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
mes_type = strtok(header, "-");
|
||||
*mes_len = atoi((const char *) strtok(NULL, "\0"));
|
||||
|
||||
*data = realloc(*data, (*mes_len+1)*sizeof(char));
|
||||
|
||||
if ( socket_recv(*data, *mes_len) < 0 ) {
|
||||
puts("failed to receive data from package");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if ( strcmp(mes_type, "aud") == 0 ) {
|
||||
return AUDIO;
|
||||
}
|
||||
|
||||
if ( strcmp(mes_type, "txt") == 0 ) {
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
puts("could not find package type");
|
||||
return ERROR;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Boilerplate socket closing function */
|
||||
int close_socket () {
|
||||
if (close(socket_desc) < 0) {
|
||||
return ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue