// マルチバイト文字セット
#pragma comment(lib, "winmm")
#define _USE_MATH_DEFINES
#include <stdio.h>
#include <math.h>
#include <Windows.h>
#include <vector>
using namespace std;
#define SAFE_FREE(p) if (p) { free(p); p = NULL; }
#define SAMPLING_RATE 11025
#define FREQ 882.0
// 関数プロトタイプ宣言
void AddDots(bool b, int count);
// 欧文文字
LPCTSTR letters[] = {
"01", // A
"1000", // B
"1010", // C
"100", // D
"0", // E
"0010", // F
"110", // G
"0000", // H
"00", // I
"0111", // J
"101", // K
"0100", // L
"11", // M
"10", // N
"111", // O
"0110", // P
"1101", // Q
"010", // R
"000", // S
"1", // T
"001", // U
"0001", // V
"011", // W
"1001", // X
"1011", // Y
"1100", // Z
};
// 数字
LPCTSTR numbers[] = {
"11111", // 0
"01111", // 1
"00111", // 2
"00011", // 3
"00001", // 4
"00000", // 5
"10000", // 6
"11000", // 7
"11100", // 8
"11110", // 9
};
// 記号
LPCTSTR punctuation[] = {
"010101", // . Period
"110011", // , Comma
"001100", // ? Question mark
"011110", // ' Apostrophe
"101011", // ! Exclamation mark
"10010", // / Slash, Fraction bar
"10110", // ( Parenthesis open
"101101", // ) Parenthesis close
"01000", // & Ampersand, Wait
"111000", // : Colon
"101010", // ; Semicolon
"10001", // = Double dash
"01010", // + Plus
"100001", // - Hyphen, Minus
"001101", // _ Underscore
"010010", // " Quotation mark
"0001001", // $ Dollar sign
"011010", // @ At sign
};
// 和文文字
LPCTSTR kana[] = {
NULL, // 。
NULL, // 「
"010100", // 」(段落)
"010101", // 、(区切点)
NULL, // ・
"0111", // ヲ
NULL, // ァ
NULL, // ィ
NULL, // ゥ
NULL, // ェ
NULL, // ォ
NULL, // ャ
NULL, // ュ
NULL, // ョ
NULL, // ッ
"01101", // ー(長音)
"11011", // ア
"01", // イ
"001", // ウ
"10111", // エ
"01000", // オ
"0100", // カ
"10100", // キ
"0001", // ク
"1011", // ケ
"1111", // コ
"10101", // サ
"11010", // シ
"11101", // ス
"01110", // セ
"1110", // ソ
"10", // タ
"0010", // チ
"0110", // ツ
"01011", // テ
"00100", // ト
"010", // ナ
"1010", // ニ
"0000", // ヌ
"1101", // ネ
"0011", // ノ
"1000", // ハ
"11001", // ヒ
"1100", // フ
"0", // ヘ
"100", // ホ
"1001", // マ
"00101", // ミ
"1", // ム
"10001", // メ
"10010", // モ
"011", // ヤ
"10011", // ユ
"11", // ヨ
"000", // ラ
"110", // リ
"10110", // ル
"111", // レ
"0101", // ロ
"101", // ワ
// "01001", // ヰ
// "01100", // ヱ
"01010", // ン
"00", // ゛(濁点)
"00110", // ゜(半濁点)
};
// 外部変数
DWORD sampleLength = 0;
PBYTE waveformData = NULL;
vector<bool> dots;
//==============================================================================
int main(int argc, char *argv[])
{
// プログラム引数
LPCTSTR words = NULL;
double amp = 0.1;
int loops = 0;
int wpm = 20;
for (int i = 1; i < argc; i++) {
LPCTSTR p = argv[i];
if (p[0] == '-') {
switch (p[1]) {
case 'a':
amp = atof(p + 2);
break;
case 'l':
loops = atoi(p + 2);
break;
case 'w':
wpm = atoi(p + 2);
break;
}
} else {
words = p;
}
}
if (words == NULL) {
fprintf(stderr, "usage: morse -a(f) -l(n) -w(n) \"words\"\n");
return 1;
}
// 符号化
for (int i = 0; words[i]; i++) {
LPCTSTR code = NULL;
BYTE c = words[i];
if (c == ' ') {
AddDots(false, 4);
} else if ('A' <= c && c <= 'Z') {
code = letters[c - 'A'];
} else if ('a' <= c && c <= 'z') {
code = letters[c - 'a'];
} else if (0xa1 <= c && c <= 0xdf) {
code = kana[c - 0xa1];
}
if (code) {
for ( ; *code; code++) {
AddDots(true, (*code & 1) ? 3 : 1);
AddDots(false, 1);
}
AddDots(false, 2);
}
}
// 波形データの作成
int dotLen = SAMPLING_RATE * 60 / (50 * wpm);
sampleLength = dots.size() * dotLen;
waveformData = (PBYTE)malloc(sampleLength);
int i = 0;
for (vector<bool>::iterator it = dots.begin(); it != dots.end(); it++) {
if (*it) {
for (int n = 0; n < dotLen; n++) {
double t = fmod(FREQ * i / SAMPLING_RATE, 1);
double y = amp * sin(2 * M_PI * t);
waveformData[i++] = BYTE(128 + 127 * y);
}
} else {
for (int n = 0; n < dotLen; n++) {
waveformData[i++] = 128;
}
}
}
// Play
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = 8;
wfx.nChannels = 1;
wfx.nSamplesPerSec = SAMPLING_RATE;
wfx.nBlockAlign = (wfx.wBitsPerSample / 8) * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
HWAVEOUT hwo;
MMRESULT mmr = waveOutOpen(&hwo, WAVE_MAPPER, &wfx, NULL, 0, CALLBACK_NULL);
WAVEHDR wh;
ZeroMemory(&wh, sizeof wh);
wh.lpData = (LPSTR)waveformData;
wh.dwBufferLength = sampleLength;
wh.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
wh.dwLoops = loops ? MAXDWORD : 1;
mmr = waveOutPrepareHeader(hwo, &wh, sizeof wh);
mmr = waveOutWrite(hwo, &wh, sizeof wh);
// Wait
Sleep(loops ? loops : 1000 * sampleLength / SAMPLING_RATE);
// Stop
mmr = waveOutReset(hwo);
mmr = waveOutUnprepareHeader(hwo, &wh, sizeof wh);
mmr = waveOutClose(hwo);
SAFE_FREE(waveformData);
return 0;
}
void AddDots(bool b, int count)
{
for (int n = 0; n < count; n++) {
dots.push_back(b);
}
}