my ttl clock

news/2024/12/2 20:32:03/

文章目录

    • my ttl clock
    • 概述
    • 实现
    • 补充
    • 补充
    • END

my ttl clock

概述

最近想检测一下自己的睡眠质量.
想做个闹钟, 从22:00~03:00, 每隔5分钟报时. 将小时:分钟念出来就行. 这样, 我入静之后, 听到的最后时间, 就是我入睡的时间.

看到网上同学写好一个ttl类, 改了一下. 加了检测声音播放完的函数.
加入了任务时间段跨零点的判断.
任务结束时, 将本本关机.
花了1天时间, 手搓了一个工具, 完成了这个功能.

前几年, 买华为手机时, 附赠了一个AM08的蓝牙音箱, 一直没用过, 试了试, 还和新的一样. 这次正好用上.
在卧室摆上蓝牙音箱, 调节好音量, 在本本上开这个ttl clock程序, 准备睡觉时, 将音频切到蓝牙音箱上.
平时, 将蓝牙音箱断开, 用本本的声卡发声.

实现

写好的程序如下:

// my_ttl_clock.cpp
// env = vs2022 c++ console win10-22H2
// 需要禁止警告 4996#include "pch.h"
#include "ttl.h"// 任务时间从开始到结束
#define TM_TASK_BEGIN_HOUR 22
#define TM_TASK_BEGIN_MINU 00 // minute#define TM_TASK_END_HOUR 3
#define TM_TASK_END_MINU 0#define TM_ALERT_SPAN 5 // 多少分钟告警一次, 值范围 (1 ~ 59)bool get_cur_time(int* year, int* month, int* day, int* hour, int* minute, int* second);
void wait_for_next_minute(int _minute);
bool is_in_task_time(int year, int month, int day, int hour, int minute, int second);int main()
{int i = 0;int year = 0;int month = 0;int day = 0;int hour = 0;int minute = 0;int second = 0;int entry_cnt = 0;bool b_work_once = false;TTS ttl;TCHAR szBuf[0x100];do {Sleep(1000);if (!get_cur_time(&year, &month, &day, &hour, &minute, &second)){break;}_stprintf(szBuf, _T("%d点%.2d"), hour, minute);_tprintf(_T("now time : %2.2d:%2.2d:%2.2d\n"), hour, minute, second);if (entry_cnt++ < 3){// 程序启动后的头3次每秒, 需要报警, 用于测试音频播放是否正常_tprintf(_T("test sound!\n"));ttl.Speak_until_over(szBuf);}if ((21 == hour) && (minute == 30)){// 21:30 准备进屋-报警 PM的需求_tprintf(_T("PM need this!\n"));for (i = 0; i < 6; i++){ttl.Speak_until_over(szBuf);ttl.Speak_until_over(_T("准备进屋")); // testSleep(100);}}if (is_in_task_time(year, month, day, hour, minute, second)){// 我的需求 22:00 ~ 03:00, 每隔5分钟, 报警一次// workif (0 == (minute % TM_ALERT_SPAN)) {_tprintf(_T("alert!\n"));b_work_once = true;// workttl.Speak_until_over(szBuf);}}else {// 过了3点, 关机, 任务完成了if (b_work_once){// 如果进入过我的任务, 就关机了// 需要管理员权限// ExitWindowsEx(EWX_POWEROFF | EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE);system("shutdown /s");break;}}wait_for_next_minute(minute);} while (true);Sleep(1000);_tprintf_s(_T("END\n"));system("pause");
}bool is_in_task_time(int year, int month, int day, int hour, int minute, int second)
{/*
#define TM_TASK_BEGIN_HOUR 22
#define TM_TASK_BEGIN_MINU 00 // minute#define TM_TASK_END_HOUR 3
#define TM_TASK_END_MINU 0
*/int i_begin_hour = TM_TASK_BEGIN_HOUR;int i_begin_minute = TM_TASK_BEGIN_MINU;int i_end_hour = TM_TASK_END_HOUR;int i_end_minute = TM_TASK_END_MINU;int i_end_hour_org = i_end_hour;long l_tick_begin = 0;long l_tick_end = 0;long l_tick_cur = 0;if (i_begin_hour < 0) { i_begin_hour = 0; }else if (i_begin_hour > 23) { i_begin_hour = 23; }if (i_begin_minute < 0) { i_begin_minute = 0; }else if (i_begin_minute > 59) { i_begin_minute = 59; }if (i_end_hour < 0) { i_end_hour = 0; }else if (i_end_hour > 23) { i_end_hour = 23; }if (i_end_minute < 0) { i_end_minute = 0; }else if (i_end_minute > 59) { i_end_minute = 59; }if (i_end_hour < i_begin_hour){// 跨零点i_end_hour += 24;if (hour < i_end_hour_org){hour += 24;}}l_tick_begin = i_begin_hour * 60 + i_begin_minute;l_tick_end = i_end_hour * 60 + i_end_minute;l_tick_cur = hour * 60 + minute;return ((l_tick_cur >= l_tick_begin) && (l_tick_cur <= l_tick_end));
}void wait_for_next_minute(int _minute)
{int year = 0;int month = 0;int day = 0;int hour = 0;int minute = 0;int second = 0;_tprintf(_T("wait for next minute...\n"));do {if (!get_cur_time(&year, &month, &day, &hour, &minute, &second)){break;}if (minute != _minute){break; // next minute arrive}Sleep(100);} while (true);
}bool get_cur_time(int* year, int* month, int* day, int* hour, int* minute, int* second)
{time_t rawtime;struct tm* timeinfo = NULL;time(&rawtime);timeinfo = localtime(&rawtime);if (NULL == timeinfo){return false;}// Tue Apr 11 21:04:31 2023// printf("The current date/time is: %s", asctime(timeinfo));/*		tm_sec	54	inttm_min	6	inttm_hour	21	inttm_mday	11	inttm_mon	3	int + 1tm_year	123	int + 1900tm_wday	2	inttm_yday	100	inttm_isdst	0	int
*/if (NULL != year){*year = timeinfo->tm_year + 1900;}if (NULL != month){*month = timeinfo->tm_mon + 1;}if (NULL != day){*day = timeinfo->tm_mday;}if (NULL != hour){*hour = timeinfo->tm_hour;}if (NULL != minute){*minute = timeinfo->tm_min;}if (NULL != second){*second = timeinfo->tm_sec;}return true;
}
#pragma once#include "pch.h"
#include "sapi.h"#include "sphelper.h"
#pragma comment(lib, "sapi.lib")class TTS
{
public:TTS();~TTS();bool Speak(std::wstring);bool IsUseful();bool Speak_until_over(std::wstring);DWORD get_status();private:ISpVoice* m_pSpVoice;bool is_play_over();bool InitVoice();void StopVoice();
};
#include "pch.h"
#include "ttl.h"TTS::TTS()
{m_pSpVoice = nullptr;
}TTS::~TTS()
{StopVoice();::CoUninitialize();
}bool TTS::InitVoice()
{HRESULT ret = ::CoInitialize(NULL);ret = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void**)&m_pSpVoice);if (0 == ret && m_pSpVoice){m_pSpVoice->SetVolume(80);IEnumSpObjectTokens* pSpEnumTokens = NULL;if (SUCCEEDED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &pSpEnumTokens)))		//找到lili语音进行朗读, 否则就跳出{ISpObjectToken* pSpToken = NULL;while (SUCCEEDED(pSpEnumTokens->Next(1, &pSpToken, NULL)) && pSpToken != NULL){LPWSTR pId = new WCHAR[32];pSpToken->GetId(&pId);int nLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pId, -1, NULL, 0, NULL, NULL);char* s = new char[nLen + 1];WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pId, -1, s, nLen, NULL, NULL);if (0 == strcmp(s, ("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\MS-Lili-2052-20-DSK"))){m_pSpVoice->SetVoice(pSpToken);      // 设置lili语音pSpToken->Release();delete[] s;break;}delete[] s;pSpToken->Release();}pSpEnumTokens->Release();}return true;}else{}return false;
}bool TTS::Speak(std::wstring word)
{DWORD dwRc = -1;if (InitVoice()){HRESULT ret = m_pSpVoice->Speak(word.c_str(), SPF_ASYNC /*SPF_ASYNC*/, NULL);if (S_OK != ret){return false;}do {dwRc = get_status();if ((0 != dwRc) && (1 != dwRc) && (2 != dwRc) && (3 != dwRc)){break;}if (0 == dwRc){// playingbreak;}} while (true);return (S_OK == ret);}else{return false;}}DWORD TTS::get_status()
{DWORD dw_rc = -1; // 默认无效状态HRESULT hr = S_OK;SPVOICESTATUS status;wchar_t szBuf[0x100];LPWSTR p = szBuf;do {if (NULL == m_pSpVoice){break;}memset(szBuf, 0, sizeof(szBuf));memset(&status, 0, sizeof(status));hr = m_pSpVoice->GetStatus(&status, &p);if (S_OK != hr){break;}dw_rc = status.dwRunningState;} while (false);return dw_rc;
}bool TTS::Speak_until_over(std::wstring str)
{do {if (is_play_over()){// StopVoice();break;}} while (true);if (!Speak(str)){return false;}do {if (is_play_over()){// StopVoice();break;}} while (true);return true;
}bool TTS::is_play_over()
{bool b_play_over = true; // 默认为播放完成状态DWORD dwRc = -1;do {if (NULL == m_pSpVoice){break;}dwRc = get_status();if ((0 != dwRc) && (1 != dwRc) && (2 != dwRc) && (3 != dwRc)){break;}if (1 == dwRc){break; // play over}} while (true);return b_play_over;
}bool TTS::IsUseful()
{bool bRet = InitVoice();StopVoice();return bRet;
}void TTS::StopVoice()
{if (m_pSpVoice != nullptr){m_pSpVoice->Release();}
}

补充

将程序的快捷方式丢进当前用户开机启动文件夹(C:\Users\me\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup), 计算机早上打开, 这个程序就运行, 到了夜里3点, 这个程序就将计算机关掉.

睡觉前, 将音频切到蓝牙音箱上, 将计算机音量开到30%. 在夜深人静的时候, 听到的蓝牙音箱发出的声音不至于惊到人.

补充

发现有几天, 早上起来, 计算机没有关机, 但是按任意键只是亮灯, 没动作. 只能强行电源键长按关机.
昨天, 将电源改为10分钟关闭屏幕, 永远不睡眠. 将多余的程序都关掉, 只剩下杀毒软件和ttl clock.
早上起来, 计算机已经很好的关机了.

END


http://www.ppmy.cn/news/45098.html

相关文章

windows无盘启动技术开发之UEFI(新一代BIOS)引导程序开发之二

by fanxiushu 2023-04-14/18 转载或引用请注明原始作者。 接上文。 上文提到了至少有两种办法制作UEFI的虚拟磁盘驱动。 本文只接收利用BlockIO的方式来构造一个临时用的虚拟磁盘。 之所以说是临时使用&#xff0c;是因为在作为引导程序中&#xff0c;一旦进入到 \EFI\boot\boo…

双榜加冕!加速科技荣登2023准独角兽中国未来独角兽双榜单

4月10日至11日&#xff0c;由杭州市人民政府、民建浙江省委会、中国投资发展促进会主办的第7届万物生长大会在杭州国际博览中心隆重举行。会上&#xff0c;中国投资发展促进会创投专委会、杭州市创业投资协会联合微链共同发布2023杭州市独角兽&#xff08;准独角兽&#xff09;…

【架构设计】如何设计一个几十万在线用户弹幕系统

文章目录 一、前言二、项目介绍客户端轮询WebSocket主动推送 三、弹幕初始架构四、弹幕架构演进五、弹幕存储六、弹幕查询七、总结 一、前言 现在无论是直播还是电视剧&#xff0c;我们都可以看到上面慢慢的弹幕&#xff0c;满足十几万用户在线的弹幕系统&#xff0c;我们该如…

装饰模式的C++实现——设计模式学习(1)

编程目的&#xff1a;理解装饰模式及其用法。 装饰模式&#xff08;Decorator)&#xff0c;动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更为灵活。[DP] 装饰模式是一种结构型设计模式&#xff0c;它允许在运行时动态地给对…

【实用】解决.gitignore文件不生效

文章目录 背景原因解决方法 背景 针对&#xff1a;.gitignore文件不生效&#xff0c;哪怕是将某个目录、文件加入到忽略规则里 原因 .gitignore只能忽略那些原来没有被追踪的文件如果某些文件已经被纳入了版本管理中&#xff0c;那么修改.gitignore是无效的。 解决方法 先把本…

python实现将给定列表划分为元素和大致相等的两个子列表

假设现有列表[300,150,75,38,19,9,5,2]&#xff0c;我想把它划分为两个子列表&#xff0c;并要求两个列表的元素和大致相等&#xff0c;应该如何做&#xff1f; 这是一个很有意思的问题&#xff0c;我们期待的答案应该是&#xff1a; list1: [300] list2: [150,75,38,19,9,5,…

如何让心情保持平静?100多条禅修心法

静的层次和阶段 静首先是不要去争&#xff0c;没有任何争的心&#xff0c;没有任何杂念心。静有几个层次阶段&#xff1a; ⒈. 自己的心情相对于自己平静&#xff0c;是平静的第一个阶段。 ⒉. 第二个平静的阶段是&#xff1a;别人觉得你很静&#xff0c;自己也很静&#xf…

面试题整理

1、new关键字干了什么&#xff1f; let a new Object() let a Object() let a {} 都会创建一个新对象 new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 function Person(name) { // 构造函数Person()this.name name;// this.prototype Obj…