2018-02-02 15:31:13

▶ 타이머 만들기


시간을 세팅하면 그 시간 후에 종료하는 타이머를 만들어보자. 예를 들어 30초를 세팅하면 29, 28, 27, 26,...이 검은 화면에 뜨다가 0이 되면 노래가 재생하도록 만들어보자. 좀 더 예쁘게 만들기 위해서 숫자의 색깔이 계속 랜덤해서 바뀌게 할 것이다. 아래와 같은 절차를 밟을 것이다. 


1. 몇 시간, 몇 분, 몇 초 뒤에 알람이 울릴지 입력한다.

2. 입력된 시간을 초로 변환한다. 

3. 검정 화면에 남은 초가 출력된다. 

4. 시간이 종료 되면 음악이 재생된다.

5. 사용자가 0을 타이핑하면 음악이 중지되며 타이머 프로그램이 종료된다. 


코드는 아래와 같다. 주석을 잘 참고하자. 아래에서 중요한 부분들은 좀 더 자세히 다룰 것이다. 


#include <iostream>

#include <opencv2/core.hpp>

#include <opencv2/highgui.hpp>

#include <opencv2/imgproc.hpp> // cv::putText() 사용을 위해


#include <stdlib.h> // srand() 사용을 위해

#include <time.h> // time() 사용을 위해



#include <Windows.h> // PlaySound() 사용을 위해

#include <mmsystem.h> // PlaySound() 사용을 위해


#pragma comment(lib, "winmm.lib") // 


#define SOUND_NAME "Man-Of-Sorrows_-Acoustic.wav" // 재생할 노래 이름



int main()

{

int h, m, s;

int total_s;


srand((int)time(NULL)); //현재 시간을 이용해서 씨드 설정 


std::cout << "[ ] hours, [ ] minutes, [ ] seconds" << std::endl;

std::cout << "ex) 0 hours, 1 minutes, 0 seconds. Type >> 0 1 0" << std::endl;

std::cout << "ex) 0 hours, 0 minutes, 30 seconds. Type >> 0 0 30\n" << std::endl;


std::cin >> h >> m >> s;


total_s = h * 3600 + m * 60 + s;

std::cout << "Timer is set: " << total_s << " sec" << std::endl;


for (int i = 1; i <= total_s; i++)

{

cv::Mat bg(100, 400, CV_8UC3, cv::Scalar(0.0, 0.0, 0.0)); // 타이머 검정 배경 화면

char buf[100];

sprintf_s(buf, "%d", total_s - i); // int형 정수를 char형 문자열로 전환, total_s - i 는 남은 초를 의미. 


cv::putText(bg, buf, cv::Point(40, 70), cv::FONT_HERSHEY_PLAIN, 5.0, cv::Scalar(rand() % 255 + 1.0, rand() % 255 + 1.0, rand() % 255 + 1.0), 5); // 검정 화면에 초를 띄운다. 숫자의 색이 랜덤하게 변하게 설정. 

cv::imshow("Timer", bg);

cv::waitKey(1000);

}


PlaySound(TEXT(SOUND_NAME), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); // 노래 재생, 재생하면서 아래 코드 계속 진행. 노래는 반복 재생되게 설정. 


int opt = 1;

do

{

std::cout << "\nDo you want to turn off the music?" << std::endl;

std::cout << "Type >> 0\n" << std::endl;

std::cin >> opt;

} while (opt != 0); // 0이 입력되지 않았다면 계속 반복문 실행


PlaySound(NULL, 0, 0); // 재생중이던 음악 중지


std::cout << "\nTimer is finished!\a" << std::endl; // 종료 문구와 함께 경고음

 

    return 0;

}


타이머를 실행한 결과는 영상으로 녹화를 해보았다. 시간이 종료되고 음악이 재생될 때 0을 입력해야 음악이 종료되는데 일부러 먼저 1을 입력해서 0외의 다른 키를 입력할 때는 종료되지 않음을 보였다. 




▶ 좀 더 알고 넘어갈 것들


1) 남는 시간 화면에 출력하기


타이머를 예쁘기 만들기 위해서 나는 opencv를 활용해서 남은 초를 이미지 창을 하나 열어 이미지로 나타냈다. 먼저 검정색 이미지를 만든 다음에 거기에 남은 초가 보여지게 만들었다. 그리고 for문 안에 cv::waitKey(1000)을 이용해서 1초마다 남은 초가 갱신되게 했다. 


cv::waitKey(1000);


cv::waitKey()의 입력 인자가 0보다 큰 양수일 때는 ms단위만큼 이미지를 보여준다는 의미이다. 따라서 1000이면 1초, 2000이면 2초가 된다.



2) 숫자를 문자열로 변환


남은 초를 이미지창에 텍스트로 삽입하기 위해서 cv::putText()를 사용했다. 남은 초는 정수이기 때문에 이 함수를 활용하기 위해서는 문자열로 변형해줄 필요가 있다. 이 부분은 구글링 중에 [2]를 참고해서 구현했다. 


char buf[100];

sprintf_s(buf, "%d", total_s - i);


먼저 문자열을 저장해줄 공간을 준비한 다음에 sprintf_s()를 활용하여 정수를 문자열로 변환했다. 2번째 줄 코드를 해석하면 buf라는 이름의 배열에 int형 정수인 total_s - i (남은 초)를 문자열로 변환해서 저장하라는 것이다. 



3) 음악 재생 관련


타이머가 종료되는 것을 알려주기 위해 노래를 재생시켰다. PlaySound() 함수를 사용했는데, 이를 사용하기 위해서는 먼저 헤더부분에 아래와 같은 코드들이 필요하다. 


#include <Windows.h> 

#include <mmsystem.h> 


#pragma comment(lib, "winmm.lib") 

#define SOUND_NAME "Man-Of-Sorrows_-Acoustic.wav" 


Windows.h와 mmsystem.h는 PlaySound()를 사용하기 위해 필요한 헤더 파일들이다. 그리고 #pragma 매크로는 lib파일을 불러들이는데 필요하다고 한다. 그리고 네번째 줄에서 Man-Of-sorrows_-Acoustic.wav는 재생할 음악의 파일명이다. PlaySound() 함수로는 wav 파일만 재생이 가능하다. 


그리고 노래를 재생하고 싶은 부분에 아래와 같은 코드를 넣어줘야 한다. 


PlaySound(TEXT(SOUND_NAME), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);


여기서 중요한 것은 SND_ASYNC와 SND_LOOP인데, SND_ASYNC는 음악을 재생하면서 다음 코드를 실행한다는 의미이고, SND_LOOP는 음악를 계속해서 반복재생하라는 것이다. 노래를 재생 중간에 끄고 싶으면 다음과 같은 코드가 필요하다. 


PlaySound(NULL, 0, 0);



▶ 정리


내용 중 이해가 안되는 부분이 있다면 말씀해주시면 좀 더 자세히 설명해드리겠습니다! 또한 잘못된 것 있다면 친절히 알려주세요~ㅎㅎ



<참고자료>

[1] https://convertio.co/kr/mp3-converter/ => .mp3 파일로 변환 또는 .mp3 파일을 다른 형식으로 변환해주는 사이트. 본 프로그램을 위해 mp3 파일을 wmv 파일로 변환했음. 

[2] https://blog.naver.com/djtjf12/220625803727 => PlaySound 함수 사용법 참고