Initial commit

This commit is contained in:
Andrew Gundersen 2020-07-27 14:47:43 -05:00
commit 9e75ca73b2
39 changed files with 2553 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
audio/.DS_Store vendored Normal file

Binary file not shown.

BIN
audio/include/.DS_Store vendored Normal file

Binary file not shown.

View 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

View 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

Binary file not shown.

348
audio/src/audio_handler.c Normal file
View 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
View 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

Binary file not shown.

37
core/Info.plist Normal file
View 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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

31
core/include/main.h Normal file
View 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
View 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

Binary file not shown.

BIN
core/resources/ICON.icns Normal file

Binary file not shown.

172
core/src/main.c Normal file
View 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
View 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
View 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

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

View 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

View 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

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

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