#include <SDL2/SDL.h>
|
|
#ifdef SV_EXP
|
|
#include <experimental/string_view>
|
|
namespace std
|
|
{
|
|
using string_view = std::experimental::string_view;
|
|
}
|
|
#else
|
|
#include <string_view>
|
|
#endif
|
|
#include <vector>
|
|
#include <set>
|
|
#include <chrono>
|
|
#include <thread>
|
|
#include <atomic>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <cassert>
|
|
#include <random>
|
|
#include <fstream>
|
|
#include <algorithm>
|
|
#include "rigid_paradise/display.h"
|
|
#include "rigid_paradise/config.h"
|
|
#include "rigid_paradise/pomodoro.h"
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
auto wait_interval = 12min;
|
|
//auto wait_interval = 12s;
|
|
|
|
std::vector<std::string_view> audioDeviceNames;
|
|
std::vector<SDL_AudioDeviceID> audioDeviceIDs;
|
|
Uint8* audio_pos; // global pointer to the audio buffer to be played
|
|
Uint8* audio_pos_orig; // global pointer to the audio buffer to be played
|
|
Uint32 audio_len; // remaining length of the sample we have to play
|
|
Uint32 audio_len_orig; // remaining length of the sample we have to play
|
|
std::atomic<bool> must_play = false;
|
|
|
|
std::minstd_rand bad_rng;
|
|
|
|
std::set<std::pair<char, std::string>> pomodoro_actions = pomodoro_actions_unwrap;
|
|
|
|
namespace sound_mng
|
|
{
|
|
|
|
void my_audio_callback(void* userdata, Uint8* stream, int len)
|
|
{
|
|
|
|
if (audio_len ==0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
len = ( len > audio_len ? audio_len : len );
|
|
//SDL_memcpy (stream, audio_pos, len); // simply copy from one buffer into the other
|
|
SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);// mix from one buffer into another
|
|
|
|
audio_pos += len;
|
|
audio_len -= len;
|
|
}
|
|
|
|
constexpr SDL_AudioSpec base_spec =
|
|
{
|
|
.freq = 48000,
|
|
.format = AUDIO_F32,
|
|
.channels = 2,
|
|
.silence = 0,
|
|
.samples = 4096,
|
|
.callback = my_audio_callback,
|
|
.userdata = nullptr
|
|
};
|
|
|
|
void loadAudioDevices()
|
|
{
|
|
int i, count = SDL_GetNumAudioDevices(0);
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
const char* name = SDL_GetAudioDeviceName(i, 0);
|
|
audioDeviceNames.push_back(name);
|
|
SDL_AudioSpec ignored;
|
|
audioDeviceIDs.push_back(SDL_OpenAudioDevice(
|
|
name,
|
|
0,
|
|
&base_spec,
|
|
&ignored,
|
|
0
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
void player()
|
|
{
|
|
while ( true )
|
|
{
|
|
while(must_play)
|
|
{
|
|
SDL_PauseAudio(0);
|
|
std::this_thread::sleep_for(1s);
|
|
audio_pos = audio_pos_orig;
|
|
audio_len = audio_len_orig;
|
|
SDL_PauseAudio(1);
|
|
std::this_thread::sleep_for(3s);
|
|
}
|
|
|
|
std::this_thread::sleep_for(1s);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
int main();
|
|
|
|
int WinMain()
|
|
{
|
|
return main();
|
|
}
|
|
|
|
int main()
|
|
{
|
|
assert(SDL_Init(SDL_INIT_AUDIO) >= 0);
|
|
|
|
sound_mng::loadAudioDevices();
|
|
|
|
// sound data
|
|
static Uint32 wav_length; // length
|
|
static Uint8* wav_buffer; // buffer containing our audio file
|
|
static SDL_AudioSpec wav_spec; // the specs of our sound
|
|
|
|
|
|
// Load the WAV
|
|
assert( SDL_LoadWAV(config::get_value("pomodoro_sound").c_str(), &wav_spec, &wav_buffer, &wav_length) != NULL );
|
|
|
|
// set the callback function
|
|
wav_spec.callback = sound_mng::my_audio_callback;
|
|
wav_spec.userdata = NULL;
|
|
// set our global static variables
|
|
audio_pos = wav_buffer; // copy sound buffer
|
|
audio_pos_orig = wav_buffer; // copy sound buffer
|
|
audio_len = wav_length; // copy file length
|
|
audio_len_orig = wav_length; // copy file length
|
|
|
|
/* Open the device */
|
|
if ( SDL_OpenAudio(&wav_spec, NULL) < 0 )
|
|
{
|
|
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
std::thread my_player{sound_mng::player};
|
|
|
|
/********************* MAIN LOOP *************************/
|
|
|
|
bool quit = false;
|
|
|
|
while(!quit)
|
|
{
|
|
display::header("Pomodoro");
|
|
std::cout << "> Interval time is: "<< display::to_string(wait_interval) <<std::endl;
|
|
std::cout << "> Tasklist excerpt:\n";
|
|
|
|
std::array<pomodoro::pomotask,5> sample;
|
|
|
|
auto list = pomodoro::get_pomodoro_tasks();
|
|
|
|
auto smp_end = std::sample(list.begin(), list.end(), sample.begin(),5, bad_rng);
|
|
|
|
for(auto it = sample.begin(); it != smp_end; it++)
|
|
{
|
|
std::cout << "> ["<<it->first<<"]: "<<it->second<<"\n";
|
|
}
|
|
|
|
std::cout<<std::endl;
|
|
|
|
std::this_thread::sleep_for(wait_interval);
|
|
must_play.store(true);
|
|
{
|
|
display::header("Pomodoro");
|
|
std::cout << "> Select your current action:" << std::endl;
|
|
|
|
display::pair_set(pomodoro_actions);
|
|
|
|
char action;
|
|
bool valid=false;
|
|
|
|
do
|
|
{
|
|
std::string str;
|
|
getline (std::cin, str);
|
|
|
|
auto is_matching = [&](auto action)
|
|
{
|
|
return str[0]==action.first;
|
|
};
|
|
|
|
if(
|
|
std::any_of(
|
|
pomodoro_actions.begin(),
|
|
pomodoro_actions.end(),
|
|
is_matching
|
|
)
|
|
)
|
|
{
|
|
action=str[0];
|
|
valid=true;
|
|
}
|
|
}
|
|
while(!valid);
|
|
|
|
auto task_list = pomodoro::get_pomodoro_tasks();
|
|
std::cout<<"> Select your current assigned task:"<<std::endl;
|
|
|
|
display::pair_set(task_list);
|
|
|
|
int task_nb;
|
|
std::string task_label;
|
|
valid=false;
|
|
|
|
do
|
|
{
|
|
try
|
|
{
|
|
std::cin >> task_nb;
|
|
}
|
|
catch(...)
|
|
{
|
|
task_nb = 0;
|
|
}
|
|
|
|
std::for_each(task_list.begin(), task_list.end(), [&](auto action)
|
|
{
|
|
if(task_nb==action.first)
|
|
{
|
|
valid=true;
|
|
task_label = display::escape_csv(action.second);
|
|
}
|
|
});
|
|
|
|
}
|
|
while(!valid);
|
|
|
|
|
|
std::ofstream(config::get_value("pomodoro.log"), std::ofstream::app)<<std::chrono::seconds(std::time(NULL)).count()<<"\t"<<action<<"\t"<<task_label<<std::endl;
|
|
}
|
|
must_play.store(false);
|
|
}
|
|
|
|
// shut everything down
|
|
SDL_CloseAudio();
|
|
SDL_FreeWAV(wav_buffer);
|
|
}
|