码迷,mamicode.com
首页 > 其他好文 > 详细

第22章 声音与音乐(3)

时间:2015-08-09 16:57:47      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:

22.2.7 波形音频文件格式——WAV音频格式

偏移量

字节

数据

0000

4

字符串——“RIFF”(资源交换文件格式),文件由很多数据“块”组成,每一块数据由块的名称和块长组成。名称由4个ASCII字符组成。块长不包含块的名称和块长这个字段本身所需的8个字节,也就是说是“块”的实际长度。

0004

4

波形数据块的大小(文件大小-8)即从偏移0008开始到文件结束的大小

0008

4

字符串——“WAVE”

000C

4

字符串——“fmt ”(注意:fmt后面有一空格)

0010

4

格式数据块的大小(16字节),即sizeof(PCMWAVEFORMATEX)

0014

2

wf.wFormatTag = WAVE_FORMAT_PCM =1

0016

2

wf.nChannels

0018

4

wf.nSamplesPerSec

001C

4

wf.nAvgBytesPerSec

0020

2

wf.nBlockAlign

0022

2

wf.wBitsPerSample //样本大小,当为8位及以下时,被解释为无符号整数,0x80表示无声。8位以上时无声为0

0024

4

字符串——“data”

0028

4

波形数据的大小,即真正的声音数据的大小

002C

n

波形数据——声音数据

22.2.8 使用加法合成来生成波形声音(小号、双簧管、单簧管)

(1)每一种乐器由一系列的分音组成(小号12个分音,双簧管和单簧管各21个分音)

(2)PRT结构:存放每个分音的振幅和频率包络线的点的个数和各振幅和各频率。

(3)INS结构:为每种乐器的结构,存放乐音的总时间,分音的数量和所有分音振幅和频率。

(4)FillBuffer:先计算累计最大振幅。这个振幅在后面用于把采样按比例缩放到8位的样本大小。接着,按指定的频率开始采样,然后对每个分音的振幅和频率进行线性插值。

传入频率值和相位角,并调用SineGenerator函数正弦值并累加分音振幅,最后将振幅缩放到8位的样本大小。

【AddSynth程序】

 技术分享

/*------------------------------------------------------------------
ADDSYNTH.C —— additive Synthesis Sound Generator声音的加法合成器
               (c)Charles Petzold,1998
-------------------------------------------------------------------*/
#include <Windows.h>
#include <math.h>
#include "AddSynth.h"
#include "resource.h"

#pragma comment(lib,"WINMM.LIB")

#define ID_TIMER      1        //计时器
#define PI            3.14159
#define SAMPLE_RATE   22050    //采样频率
#define MAX_PARTIALS  21       //最大的泛音个数


BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

TCHAR szAppName[] = TEXT("AddSynth");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iShowCmd)
{
    if (-1 ==DialogBox(hInstance,szAppName,NULL,DlgProc))
    {
        MessageBox(NULL, TEXT("This program require Windows NT!"), 
                        szAppName, MB_ICONERROR);
    }
    return 0;
}

//正弦波发生器
//根据相位角,求正弦波的振幅。并根据频率给出下一个相位角
double SineGenerator(double dFreq, double* pdAngle)
{
    double dAmp; //振幅
    
    dAmp = sin(*pdAngle); //计算振幅
    *pdAngle += 2 * PI*dFreq / SAMPLE_RATE; //计算下一个样本的相位角
    if (*pdAngle >= 2 * PI)
        *pdAngle -= 2 * PI;
    return dAmp;  //返回振幅值
}

//用合成的波形数据填充缓冲区
void FillBuffer(INS ins, PBYTE pBuffer, int iNumSamples)
{
    static double dAngle[MAX_PARTIALS];//定义一个相位角数组
    double dAmp, dFrq, dComp, dFrac;  //定义振幅、频率、合成振幅、包络的线性插值比例因子
    int i, iPrt, iMsecTime, iCompMaxAmp, iMaxAmp, iSmp;//定义i、泛音数组下标、每个样本的时间(毫秒)
                                                       //最大合成振幅、最大振幅、样本号

    //计算合成的最大振幅
    iCompMaxAmp = 0;

    //在泛音集中循环以计算最大振幅
    for (iPrt = 0; iPrt < ins.iNumPartials; iPrt++)
    {
        iMaxAmp = 0;
        for (i = 0; i < ins.pprt[iPrt].iNumAmp; i++)
            iMaxAmp = max(iMaxAmp, ins.pprt[iPrt].pEnvAmp[i].iValue);

        iCompMaxAmp += iMaxAmp;
    }

    //循环每个样本
    for (iSmp = 0; iSmp < iNumSamples; iSmp++)
    {
        dComp = 0;
        iMsecTime = (int)(1000 * iSmp / SAMPLE_RATE);//取得每个样本的毫秒数

        //循环每个泛音集
        //以下循环在每个泛音中进行振幅和频率插值
        for (iPrt = 0; iPrt < ins.iNumPartials; iPrt++)
        {
            dAmp = 0;  //插值处的振幅
            dFrq = 0;  //插值处的频率

            //对每个泛音集在指定的时间处(iMsecTime),进行振幅的插值
            for (i = 0; i < ins.pprt[iPrt].iNumAmp-1; i++)
            {
                if (iMsecTime >= ins.pprt[iPrt].pEnvAmp[i].iTime &&
                    iMsecTime <= ins.pprt[iPrt].pEnvAmp[i+1].iTime)
                {
                    //计算插值比例
                    dFrac = (iMsecTime - ins.pprt[iPrt].pEnvAmp[i].iTime) /
                            (ins.pprt[iPrt].pEnvAmp[i + 1].iTime - ins.pprt[iPrt].pEnvAmp[i].iTime);
                    
                    //dAmp = v[i]+ dFrac*(v[i+1]-v[i]),即:
                    //利用前两后两个振幅的插值比例,计算出插值处的振辐
                    dAmp = dFrac* ins.pprt[iPrt].pEnvAmp[i + 1].iValue +
                        (1 - dFrac)*ins.pprt[iPrt].pEnvAmp[i].iValue;

                    break;
                }
            }

            //对每个泛音集在指定的时间处(iMsecTime),进行频率的插值
            for (i = 0; i < ins.pprt[iPrt].iNumFrq - 1; i++)
            {
                if (iMsecTime >= ins.pprt[iPrt].pEnvFrq[i].iTime &&
                    iMsecTime <= ins.pprt[iPrt].pEnvFrq[i + 1].iTime)
                {
                    //计算插值比例
                    dFrac = (iMsecTime - ins.pprt[iPrt].pEnvFrq[i].iTime) /
                        (ins.pprt[iPrt].pEnvFrq[i + 1].iTime - ins.pprt[iPrt].pEnvFrq[i].iTime);

                    //dFrq = v[i]+ dFrac*(v[i+1]-v[i]),即:
                    //利用前两后两个振幅的插值比例,计算出插值处的振辐
                    dFrq = dFrac* ins.pprt[iPrt].pEnvFrq[i + 1].iValue +
                        (1 - dFrac)*ins.pprt[iPrt].pEnvFrq[i].iValue;

                    break;
                }
            }
            //计算每个采样点处的合成振幅
            dComp += dAmp*SineGenerator(dFrq, dAngle + iPrt); 
        }
        pBuffer[iSmp] = (BYTE)(127 + 127 * dComp / iCompMaxAmp); //每个样本的振幅缩放到0-254之间
    }
}

//创建声音波形文件
BOOL MakeWaveFile(INS ins, TCHAR* szFileName)
{
    HANDLE hFile;
    PBYTE pBuffer; //缓冲区,用来接受一个音符的所有样本。
    int iNumSamples,iPcmSize,iChunkSize;
    WAVEFORMATEX waveform; //定义一个波形音频结构变量
    DWORD dwWritten;

    hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == NULL)
        return FALSE;

    //SAMPLE_RATE:采样率(样本数/秒),以下表示在iMsecTime毫秒内应采样的数量(取偶数个)
    iNumSamples = ((long)ins.iMsecTime*SAMPLE_RATE / 1000 + 1) / 2 * 2;
    iPcmSize = sizeof(PCMWAVEFORMAT);//取得脉冲编码调制结构体大小
    
    //文件大小-8,即从第3个字段开始的WAV文件(见课本P1020图22-6)
    //0008-0014:12节字(分别为“WAVE”、“fmt ”、“格式数据块大小”字段
    //0014-0024:PCMWAVEFORMAT结构体
    //0024-002C:“data”、波形数据大小字段
    //002C以后:波形数据(本例每个样本用1字节存储)
    iChunkSize = 12 + iPcmSize + 8 + iNumSamples; //除“RIFF”和“波形数据块大小”两个字段

    if (NULL == (pBuffer = malloc(iNumSamples)))
    {
        CloseHandle(hFile);
        return FALSE;
    }

    FillBuffer(ins, pBuffer, iNumSamples);

    //初始化waveform结构
    waveform.wFormatTag = WAVE_FORMAT_PCM; //脉冲编码调制格式
    waveform.nChannels = 1;//单声道
    waveform.nSamplesPerSec = SAMPLE_RATE; //采样率
    waveform.nAvgBytesPerSec = SAMPLE_RATE; //平均数据传输率=nSamplesPerSec*nBlockAlign
    waveform.nBlockAlign = 1;//以1字节对齐,=nChannels*wBitsPerSample/8
    waveform.wBitsPerSample = 8; //样本大小,用来表示样本的振幅,介于(0-255)之间
    waveform.cbSize = 0; //对于PCM,必须为0;
    
    //将波形声音数据写入文件(文件格式:WAV格式)
    WriteFile(hFile, "RIFF", 4, &dwWritten, NULL);      //"RIFF"
    WriteFile(hFile, &iChunkSize, 4, &dwWritten, NULL); //波形数据块的大小(文件大小-8),即W从AV文件第3字段开始
    WriteFile(hFile, "WAVEfmt ", 8, &dwWritten, NULL);  //第3、4字段:“WAVE”、“fmt ”(注意fmt后有一空格)
    WriteFile(hFile, &iPcmSize, 4, &dwWritten, NULL);   //格式数据块的大小,即WAVEFORMATEX结构体
    WriteFile(hFile, &waveform, sizeof(WAVEFORMATEX)-2, &dwWritten, NULL); //不含WAVEFORMATEX中的cbSize字段
    WriteFile(hFile, "data", 4, &dwWritten, NULL);       //“data”字段
    WriteFile(hFile, &iNumSamples, 4, &dwWritten, NULL); //波形数据的大小
    WriteFile(hFile, pBuffer, iNumSamples, &dwWritten, NULL);

    CloseHandle(hFile);
    free(pBuffer);

    if (dwWritten !=iNumSamples)
    {
        DeleteFile(szFileName);
        return FALSE;
    }
    return TRUE;
}

//测试和创建音频文件
void TestAndCreate(HWND hwnd, INS ins, TCHAR* szFileName, int idButton)
{
    TCHAR szMessage[64];

    //返回文件的属性,如果失败,返回-1
    if (-1 != GetFileAttributes(szFileName))
    {
        EnableWindow(GetDlgItem(hwnd, idButton), TRUE);
    }
    else
    {
        if (MakeWaveFile(ins,szFileName))
        {
            EnableWindow(GetDlgItem(hwnd, idButton), TRUE);
        }
        else
        {
            wsprintf(szMessage, TEXT("Could not create %x."), szFileName);
            MessageBeep(MB_ICONEXCLAMATION);
            MessageBox(hwnd, szMessage, szAppName, MB_OK | MB_ICONEXCLAMATION);
        }
    }
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static TCHAR* szTrum = TEXT("Trumpet.wav"); //小号
    static TCHAR* szOboe = TEXT("Oboe.wav");    //双簧管
    static TCHAR* szClar = TEXT("Clarinet.wav"); //单簧管
    RECT rect;
    

    switch (message)
    {
    case WM_INITDIALOG:
        GetWindowRect(hwnd, &rect);
        SetWindowPos(hwnd, NULL, (GetSystemMetrics(SM_CXSCREEN) - rect.right + rect.left) / 2, 
                                 (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2,
                                 rect.right-rect.left,rect.bottom-rect.top,SWP_SHOWWINDOW);

        SetTimer(hwnd, ID_TIMER, 1, NULL); //设置定时器。目的是
        return TRUE;

    case WM_TIMER:
        KillTimer(hwnd, ID_TIMER);
        SetCursor(LoadCursor(NULL,IDC_WAIT));
        ShowCursor(TRUE);

        TestAndCreate(hwnd, insTrum, szTrum, IDC_TRUMPET);
        TestAndCreate(hwnd, insOboe, szOboe, IDC_OBOE);
        TestAndCreate(hwnd, insClar, szClar, IDC_CLARINET);

        SetDlgItemText(hwnd, IDC_TEXT, TEXT(""));
        SetFocus(GetDlgItem(hwnd, IDC_TRUMPET));

        ShowCursor(FALSE);
        SetCursor(LoadCursor(NULL, IDC_ARROW));

        return TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDC_TRUMPET:
            PlaySound(szTrum, NULL, SND_FILENAME | SND_SYNC); //播放小号
            return TRUE;

        case IDC_OBOE:
            PlaySound(szOboe, NULL, SND_FILENAME | SND_SYNC); //播放双簧管
            return TRUE;

        case IDC_CLARINET:
            PlaySound(szClar, NULL, SND_FILENAME | SND_SYNC); //播放单簧管
            return TRUE;
        }
        break;

    case WM_SYSCOMMAND:
        switch (LOWORD(wParam))
        {
        case SC_CLOSE:
            EndDialog(hwnd, 0);
            return TRUE;
        }
        break;
    }
    return FALSE;
}

//AddSynth.h

/*-------------------------------------------------------------------
   ADDSYNTH.H -- Amplitude and Frequency Envelopes for 3 Instruments

                 From "Computer Music Journal," Volume II, Number 2
  -------------------------------------------------------------------*/

typedef struct
{
     int iTime ;  //时间
     int iValue ; //该时间处,振幅的大小或该振幅出现的频率
}
ENV ;//定义一个声音包络结构

typedef struct
{
     int  iNumAmp ; //分音中振幅的数量
     ENV *pEnvAmp ; 
     int  iNumFrq ; //分音中频率的数量
     ENV *pEnvFrq ;
}
PRT ;//定义一个泛音结构

typedef struct
{
     int   iMsecTime ;
     int   iNumPartials ;
     PRT  *pprt ;
}
INS ;//定义一个乐器结构

//以下定义小号的包络
ENV envTrumAmp01[] = { 1, 0, 20, 305, 36, 338, 141, 288, 237, 80, 360, 0 };//第1个分音,格式:时间,相应的振幅 
ENV envTrumFrq01[] = { 1, 321, 16, 324, 32, 312, 109, 310, 317, 314, 360, 310 };//第2个分音:格式:时间、及该时间处相应振幅出现的频率
ENV envTrumAmp02[] = { 1, 0, 3, 0, 25, 317, 39, 361, 123, 295, 222, 40, 326, 0, 360, 0 };
ENV envTrumFrq02[] = { 1, 0, 2, 0, 3, 607, 16, 657, 24, 621, 133, 621, 275, 628, 326, 628, 327, 0, 360, 0 };
ENV envTrumAmp03[] = { 1, 0, 2, 0, 19, 100, 34, 369, 111, 342, 207, 41, 273, 0, 360, 0 };
ENV envTrumFrq03[] = { 1, 0, 2, 977, 5, 782, 15, 987, 24, 932, 128, 932, 217, 936, 273, 945, 275, 0, 360, 0 };
ENV envTrumAmp04[] = { 1, 0, 3, 0, 24, 113, 29, 257, 118, 231, 187, 35, 235, 0, 360, 0 };
ENV envTrumFrq04[] = { 1, 0, 2, 0, 3, 718, 16, 1335, 24, 1243, 108, 1240, 199, 1248, 235, 1248, 236, 0, 360, 0 };
ENV envTrumAmp05[] = { 1, 0, 27, 52, 34, 130, 110, 126, 191, 13, 234, 0, 360, 0 };
ENV envTrumFrq05[] = { 1, 1225, 9, 1569, 12, 1269, 21, 1573, 37, 1553, 97, 1552, 181, 1556, 234, 1566, 235, 0, 360, 0 };
ENV envTrumAmp06[] = { 1, 0, 46, 83, 64, 100, 100, 100, 189, 11, 221, 0, 360, 0 };
ENV envTrumFrq06[] = { 1, 1483, 12, 1572, 23, 1988, 33, 1864, 114, 1864, 177, 1868, 221, 1879, 222, 0, 360, 0 };
ENV envTrumAmp07[] = { 1, 0, 37, 39, 45, 77, 110, 79, 176, 11, 205, 0, 207, 0, 360, 0 };
ENV envTrumFrq07[] = { 1, 1792, 9, 1612, 29, 2242, 36, 2174, 93, 2176, 126, 2170, 205, 2188, 207, 0, 360, 0 };
ENV envTrumAmp08[] = { 1, 0, 2, 0, 28, 17, 43, 71, 109, 66, 172, 8, 201, 0, 360, 0 };
ENV envTrumFrq08[] = { 1, 0, 2, 1590, 29, 2539, 36, 2491, 114, 2481, 153, 2489, 201, 2491, 203, 0, 360, 0 };
ENV envTrumAmp09[] = { 1, 0, 2, 0, 29, 16, 43, 53, 54, 66, 105, 64, 165, 7, 191, 0, 360, 0 };
ENV envTrumFrq09[] = { 1, 0, 2, 1993, 25, 2121, 32, 2821, 37, 2796, 84, 2798, 105, 2792, 191, 2797, 192, 0, 360, 0 };
ENV envTrumAmp10[] = { 1, 0, 27, 6, 41, 25, 56, 29, 72, 22, 95, 24, 180, 0, 360, 0 };
ENV envTrumFrq10[] = { 1, 1792, 12, 1849, 32, 3131, 37, 3111, 114, 3103, 164, 3116, 180, 3116, 181, 0, 360, 0 };
ENV envTrumAmp11[] = { 1, 0, 2, 0, 37, 6, 55, 25, 88, 29, 114, 28, 164, 3, 186, 0, 360, 0 };
ENV envTrumFrq11[] = { 1, 0, 2, 1398, 31, 3419, 42, 3419, 91, 3419, 106, 3406, 150, 3421, 186, 3421, 187, 0, 360, 0 };
ENV envTrumAmp12[] = { 1, 0, 7, 0, 39, 3, 43, 8, 88, 11, 118, 9, 138, 3, 165, 0, 360, 0 };
ENV envTrumFrq12[] = { 1, 0, 6, 0, 7, 1806, 23, 2942, 36, 2759, 37, 3746, 50, 3723, 84, 3731, 110, 3721, 156, 3741, 165, 3620, 167, 0, 360, 0 };

//以下定义双簧管的包络
ENV envOboeAmp01[] = { 1, 0, 9, 0, 14, 10, 26, 10, 52, 140, 94, 187, 153, 170, 313, 0 };
ENV envOboeFrq01[] = { 1, 0, 8, 0, 9, 314, 25, 292, 43, 311, 144, 311, 272, 313, 313, 309 };
ENV envOboeAmp02[] = { 1, 0, 10, 0, 26, 17, 40, 139, 159, 115, 239, 62, 307, 0, 313, 0 };
ENV envOboeFrq02[] = { 1, 0, 9, 0, 10, 708, 16, 617, 41, 625, 105, 621, 265, 630, 307, 626, 308, 0, 313, 0 };
ENV envOboeAmp03[] = { 1, 0, 10, 0, 25, 19, 36, 163, 71, 191, 129, 187, 297, 0, 313, 0 };
ENV envOboeFrq03[] = { 1, 0, 9, 0, 10, 915, 21, 931, 72, 938, 148, 935, 249, 941, 297, 938, 299, 0, 313, 0 };
ENV envOboeAmp04[] = { 1, 0, 10, 0, 25, 16, 43, 221, 64, 173, 114, 171, 284, 0, 313, 0 };
ENV envOboeFrq04[] = { 1, 0, 9, 0, 10, 1209, 18, 1261, 37, 1246, 109, 1245, 238, 1255, 284, 1253, 285, 0, 313, 0 };
ENV envOboeAmp05[] = { 1, 0, 6, 0, 13, 3, 21, 0, 28, 0, 44, 210, 59, 238, 126, 224, 199, 85, 292, 0, 313, 0 };
ENV envOboeFrq05[] = { 1, 0, 5, 0, 6, 1553, 21, 1582, 25, 1237, 28, 1533, 35, 1564, 56, 1557, 113, 1555, 185, 1565, 292, 1566, 293, 0, 313, 0 };
ENV envOboeAmp06[] = { 1, 0, 13, 0, 17, 1, 24, 0, 30, 0, 41, 63, 67, 40, 121, 38, 278, 0, 313, 0 };
ENV envOboeFrq06[] = { 1, 0, 12, 0, 13, 1907, 22, 1883, 28, 1544, 30, 1856, 36, 1878, 52, 1871, 113, 1866, 169, 1878, 225, 1876, 278, 1891, 280, 0, 313, 0 };
ENV envOboeAmp07[] = { 1, 0, 8, 0, 14, 0, 21, 0, 32, 0, 37, 22, 119, 12, 146, 3, 194, 8, 256, 0, 313, 0 };
ENV envOboeFrq07[] = { 1, 0, 6, 0, 8, 1978, 21, 1923, 28, 1717, 32, 2191, 111, 2177, 188, 2193, 229, 2182, 256, 2194, 257, 0, 313, 0 };
ENV envOboeAmp08[] = { 1, 0, 6, 0, 14, 0, 21, 0, 37, 0, 66, 5, 106, 3, 129, 4, 199, 3, 235, 0, 313, 0 };
ENV envOboeFrq08[] = { 1, 0, 5, 0, 6, 2506, 21, 2491, 25, 1252, 37, 2523, 56, 2495, 110, 2489, 140, 2491, 195, 2502, 235, 2505, 237, 0, 313, 0 };
ENV envOboeAmp09[] = { 1, 0, 4, 0, 14, 0, 20, 0, 36, 0, 45, 32, 78, 24, 132, 25, 161, 15, 241, 0, 313, 0 };
ENV envOboeFrq09[] = { 1, 0, 2, 0, 4, 2783, 20, 2779, 29, 1286, 37, 2803, 80, 2806, 113, 2799, 167, 2813, 241, 2818, 242, 0, 313, 0 };
ENV envOboeAmp10[] = { 1, 0, 6, 0, 17, 2, 22, 0, 35, 0, 47, 121, 144, 112, 206, 21, 242, 0, 313, 0 };
ENV envOboeFrq10[] = { 1, 0, 5, 0, 6, 3123, 22, 3115, 29, 2229, 35, 3118, 70, 3117, 113, 3109, 200, 3130, 242, 3131, 243, 0, 313, 0 };
ENV envOboeAmp11[] = { 1, 0, 5, 0, 17, 1, 24, 0, 37, 0, 47, 70, 123, 67, 167, 44, 188, 16, 239, 0, 313, 0 };
ENV envOboeFrq11[] = { 1, 0, 4, 0, 5, 3285, 24, 3388, 29, 1270, 37, 3430, 76, 3429, 110, 3423, 194, 3444, 239, 3444, 241, 0, 313, 0 };
ENV envOboeAmp12[] = { 1, 0, 14, 1, 24, 0, 37, 0, 44, 49, 79, 42, 122, 46, 185, 8, 231, 0, 313, 0 };
ENV envOboeFrq12[] = { 1, 3627, 24, 3664, 29, 1690, 37, 3739, 90, 3742, 115, 3733, 187, 3760, 231, 3763, 233, 0, 313, 0 };
ENV envOboeAmp13[] = { 1, 0, 4, 0, 16, 0, 24, 0, 40, 0, 47, 27, 84, 22, 126, 24, 177, 7, 229, 0, 313, 0 };
ENV envOboeFrq13[] = { 1, 0, 2, 0, 4, 4081, 24, 4064, 30, 1350, 40, 4064, 57, 4049, 148, 4051, 181, 4074, 229, 4069, 230, 0, 313, 0 };
ENV envOboeAmp14[] = { 1, 0, 4, 0, 16, 0, 21, 0, 41, 0, 44, 13, 63, 8, 82, 7, 111, 10, 175, 0, 313, 0 };
ENV envOboeFrq14[] = { 1, 0, 2, 0, 4, 4321, 21, 4259, 29, 1238, 41, 4346, 61, 4367, 87, 4368, 102, 4357, 175, 4376, 176, 0, 313, 0 };
ENV envOboeAmp15[] = { 1, 0, 47, 0, 72, 3, 97, 3, 121, 1, 161, 2, 175, 0, 313, 0 };
ENV envOboeFrq15[] = { 1, 0, 45, 0, 47, 3164, 55, 4557, 68, 4662, 98, 4670, 142, 4661, 175, 4666, 176, 0, 313, 0 };
ENV envOboeAmp16[] = { 1, 0, 48, 0, 61, 4, 86, 4, 126, 3, 137, 5, 161, 0, 313, 0 };
ENV envOboeFrq16[] = { 1, 0, 47, 0, 48, 4567, 49, 4978, 75, 4990, 109, 4982, 138, 4985, 161, 4996, 163, 0, 313, 0 };
ENV envOboeAmp17[] = { 1, 0, 51, 0, 61, 5, 76, 3, 132, 3, 164, 2, 173, 0, 313, 0 };
ENV envOboeFrq17[] = { 1, 0, 49, 0, 51, 4634, 55, 5313, 66, 5301, 99, 5301, 129, 5292, 173, 5318, 175, 0, 313, 0 };
ENV envOboeAmp18[] = { 1, 0, 52, 0, 63, 2, 91, 3, 126, 3, 156, 2, 168, 0, 313, 0 };
ENV envOboeFrq18[] = { 1, 0, 51, 0, 52, 4729, 59, 5606, 92, 5611, 122, 5605, 152, 5611, 168, 5628, 169, 0, 313, 0 };
ENV envOboeAmp19[] = { 1, 0, 47, 0, 56, 2, 80, 1, 117, 2, 159, 1, 176, 0, 313, 0 };
ENV envOboeFrq19[] = { 1, 0, 45, 0, 47, 5772, 57, 5921, 86, 5928, 114, 5914, 150, 5938, 176, 5930, 177, 0, 313, 0 };
ENV envOboeAmp20[] = { 1, 0, 49, 0, 57, 2, 83, 2, 109, 1, 159, 3, 195, 0, 313, 0 };
ENV envOboeFrq20[] = { 1, 0, 48, 0, 49, 5369, 57, 6268, 76, 6230, 145, 6234, 184, 6263, 195, 6244, 196, 0, 313, 0 };
ENV envOboeAmp21[] = { 1, 0, 57, 0, 61, 0, 88, 1, 113, 0, 129, 1, 140, 0, 313, 0 };
ENV envOboeFrq21[] = { 1, 0, 56, 0, 57, 5477, 61, 6440, 71, 6550, 97, 6538, 122, 6554, 140, 6548, 141, 0, 313, 0 };

//以下定义单簧管的包络
ENV envClarAmp01[] = { 1, 0, 7, 0, 20, 6, 32, 73, 48, 445, 199, 361, 330, 0 };
ENV envClarFrq01[] = { 1, 0, 6, 0, 7, 282, 19, 368, 21, 314, 46, 310, 141, 312, 284, 313, 330, 314 };
ENV envClarAmp02[] = { 1, 0, 24, 0, 43, 22, 104, 2, 193, 4, 238, 10, 301, 0, 330, 0 };
ENV envClarFrq02[] = { 1, 0, 23, 0, 24, 629, 68, 619, 116, 616, 167, 633, 223, 624, 301, 627, 302, 0, 330, 0 };
ENV envClarAmp03[] = { 1, 0, 15, 0, 37, 12, 48, 159, 204, 122, 286, 17, 309, 0, 330, 0 };
ENV envClarFrq03[] = { 1, 0, 14, 0, 15, 803, 24, 928, 36, 898, 46, 931, 113, 939, 330, 942 };
ENV envClarAmp04[] = { 1, 0, 9, 0, 19, 2, 24, 0, 39, 0, 49, 26, 103, 3, 167, 5, 229, 10, 291, 0, 330, 0 };
ENV envClarFrq04[] = { 1, 0, 7, 0, 9, 1261, 24, 1314, 30, 327, 39, 1245, 105, 1243, 215, 1257, 246, 1249, 291, 1261, 292, 0, 330, 0 };
ENV envClarAmp05[] = { 1, 0, 6, 0, 18, 5, 25, 0, 39, 0, 54, 375, 212, 210, 266, 20, 295, 0, 330, 0 };
ENV envClarFrq05[] = { 1, 0, 5, 0, 6, 1572, 25, 1528, 32, 911, 38, 1560, 67, 1554, 127, 1565, 308, 1569, 309, 0, 330, 0 };
ENV envClarAmp06[] = { 1, 0, 3, 0, 11, 0, 15, 0, 41, 0, 48, 25, 108, 4, 216, 12, 282, 0, 330, 0 };
ENV envClarFrq06[] = { 1, 0, 2, 0, 3, 1934, 12, 1890, 33, 320, 46, 1862, 186, 1883, 282, 1875, 283, 0, 330, 0 };
ENV envClarAmp07[] = { 1, 0, 2, 0, 18, 1, 24, 0, 42, 0, 52, 108, 127, 46, 177, 42, 253, 0, 330, 0 };
ENV envClarFrq07[] = { 1, 0, 2, 2180, 24, 2148, 34, 795, 43, 2167, 113, 2193, 253, 2192, 255, 0, 330, 0 };
ENV envClarAmp08[] = { 1, 0, 2, 0, 14, 1, 23, 0, 43, 0, 52, 83, 110, 17, 199, 18, 242, 0, 330, 0 };
ENV envClarFrq08[] = { 1, 0, 2, 2458, 23, 2343, 33, 328, 45, 2472, 125, 2507, 242, 2510, 243, 0, 330, 0 };
ENV envClarAmp09[] = { 1, 0, 5, 0, 20, 2, 21, 3, 27, 0, 42, 0, 55, 127, 132, 73, 163, 71, 255, 0, 330, 0 };
ENV envClarFrq09[] = { 1, 0, 3, 0, 5, 2849, 27, 2688, 33, 964, 42, 2792, 128, 2822, 255, 2819, 256, 0, 330, 0 };
ENV envClarAmp10[] = { 1, 0, 5, 0, 23, 1, 30, 0, 47, 0, 54, 32, 92, 17, 232, 7, 247, 0, 330, 0 };
ENV envClarFrq10[] = { 1, 0, 3, 0, 5, 3173, 30, 3030, 39, 2320, 50, 3096, 134, 3136, 247, 3138, 248, 0, 330, 0 };
ENV envClarAmp11[] = { 1, 0, 23, 1, 28, 0, 39, 0, 59, 44, 122, 26, 153, 26, 262, 0, 330, 0 };
ENV envClarFrq11[] = { 1, 3313, 28, 3279, 34, 1768, 43, 3420, 127, 3448, 262, 3441, 264, 0, 330, 0 };
ENV envClarAmp12[] = { 1, 0, 10, 2, 21, 0, 46, 0, 52, 53, 158, 9, 206, 28, 255, 0, 330, 0 };
ENV envClarFrq12[] = { 1, 3756, 21, 3728, 33, 2095, 47, 3741, 136, 3762, 255, 3759, 256, 0, 330, 0 };
ENV envClarAmp13[] = { 1, 0, 3, 0, 16, 1, 29, 0, 41, 0, 46, 24, 52, 8, 77, 57, 192, 8, 250, 0, 330, 0 };
ENV envClarFrq13[] = { 1, 0, 2, 0, 3, 4152, 29, 3868, 36, 2240, 46, 4045, 85, 4049, 128, 4078, 181, 4078, 250, 4103, 251, 0, 330, 0 };
ENV envClarAmp14[] = { 1, 0, 3, 0, 16, 0, 20, 0, 48, 0, 56, 38, 110, 3, 188, 14, 228, 0, 330, 0 };
ENV envClarFrq14[] = { 1, 0, 2, 0, 3, 4213, 20, 4119, 36, 1566, 48, 4344, 130, 4388, 228, 4388, 229, 0, 330, 0 };
ENV envClarAmp15[] = { 1, 0, 5, 0, 23, 1, 28, 0, 50, 0, 77, 14, 202, 1, 219, 2, 247, 0, 330, 0 };
ENV envClarFrq15[] = { 1, 0, 3, 0, 5, 4624, 28, 4496, 33, 1012, 48, 4649, 122, 4703, 247, 4685, 248, 0, 330, 0 };
ENV envClarAmp16[] = { 1, 0, 14, 0, 24, 0, 38, 0, 64, 12, 104, 4, 145, 4, 215, 1, 238, 0, 330, 0 };
ENV envClarFrq16[] = { 1, 4928, 24, 4751, 36, 1072, 52, 4965, 117, 5006, 155, 5003, 198, 5020, 238, 3197, 239, 0, 330, 0 };
ENV envClarAmp17[] = { 1, 0, 58, 0, 95, 12, 136, 13, 201, 1, 220, 3, 233, 0, 330, 0 };
ENV envClarFrq17[] = { 1, 0, 45, 0, 46, 5005, 58, 3759, 63, 5285, 119, 5325, 180, 5325, 233, 5367, 234, 0, 330, 0 };
ENV envClarAmp18[] = { 1, 0, 50, 0, 61, 5, 100, 0, 141, 4, 185, 2, 208, 0, 330, 0 };
ENV envClarFrq18[] = { 1, 0, 48, 0, 50, 4926, 52, 5563, 94, 5628, 113, 5602, 137, 5634, 208, 5646, 210, 0, 330, 0 };
ENV envClarAmp19[] = { 1, 0, 58, 0, 63, 1, 85, 0, 140, 1, 171, 0, 183, 0, 330, 0 };
ENV envClarFrq19[] = { 1, 0, 56, 0, 58, 3938, 65, 5753, 79, 5930, 104, 5889, 152, 5916, 183, 5880, 184, 0, 330, 0 };
ENV envClarAmp20[] = { 1, 0, 50, 0, 64, 5, 103, 1, 139, 1, 177, 2, 219, 0, 330, 0 };
ENV envClarFrq20[] = { 1, 0, 48, 0, 50, 5192, 58, 6209, 121, 6266, 190, 6266, 204, 6238, 219, 6288, 220, 0, 330, 0 };
ENV envClarAmp21[] = { 1, 0, 70, 0, 79, 3, 113, 3, 141, 1, 206, 1, 219, 0, 330, 0 };
ENV envClarFrq21[] = { 1, 0, 69, 0, 70, 4245, 77, 6537, 116, 6567, 140, 6571, 176, 6564, 219, 6583, 220, 0, 330, 0 };

//以下定义小号的泛音集
PRT prtTrum [12] =  { sizeof (envTrumAmp01) / sizeof (ENV), envTrumAmp01,
                      sizeof (envTrumFrq01) / sizeof (ENV), envTrumFrq01,
                      sizeof (envTrumAmp02) / sizeof (ENV), envTrumAmp02,
                      sizeof (envTrumFrq02) / sizeof (ENV), envTrumFrq02,
                      sizeof (envTrumAmp03) / sizeof (ENV), envTrumAmp03,
                      sizeof (envTrumFrq03) / sizeof (ENV), envTrumFrq03,
                      sizeof (envTrumAmp04) / sizeof (ENV), envTrumAmp04,
                      sizeof (envTrumFrq04) / sizeof (ENV), envTrumFrq04,
                      sizeof (envTrumAmp05) / sizeof (ENV), envTrumAmp05,
                      sizeof (envTrumFrq05) / sizeof (ENV), envTrumFrq05,
                      sizeof (envTrumAmp06) / sizeof (ENV), envTrumAmp06,
                      sizeof (envTrumFrq06) / sizeof (ENV), envTrumFrq06,
                      sizeof (envTrumAmp07) / sizeof (ENV), envTrumAmp07,
                      sizeof (envTrumFrq07) / sizeof (ENV), envTrumFrq07,
                      sizeof (envTrumAmp08) / sizeof (ENV), envTrumAmp08,
                      sizeof (envTrumFrq08) / sizeof (ENV), envTrumFrq08,
                      sizeof (envTrumAmp09) / sizeof (ENV), envTrumAmp09,
                      sizeof (envTrumFrq09) / sizeof (ENV), envTrumFrq09,
                      sizeof (envTrumAmp10) / sizeof (ENV), envTrumAmp10,
                      sizeof (envTrumFrq10) / sizeof (ENV), envTrumFrq10,
                      sizeof (envTrumAmp11) / sizeof (ENV), envTrumAmp11,
                      sizeof (envTrumFrq11) / sizeof (ENV), envTrumFrq11,
                      sizeof (envTrumAmp12) / sizeof (ENV), envTrumAmp12,
                      sizeof (envTrumFrq12) / sizeof (ENV), envTrumFrq12 } ;

//以下定义双簧管的泛音集
PRT prtOboe [21] =  { sizeof (envOboeAmp01) / sizeof (ENV), envOboeAmp01,
                      sizeof (envOboeFrq01) / sizeof (ENV), envOboeFrq01,
                      sizeof (envOboeAmp02) / sizeof (ENV), envOboeAmp02,
                      sizeof (envOboeFrq02) / sizeof (ENV), envOboeFrq02,
                      sizeof (envOboeAmp03) / sizeof (ENV), envOboeAmp03,
                      sizeof (envOboeFrq03) / sizeof (ENV), envOboeFrq03,
                      sizeof (envOboeAmp04) / sizeof (ENV), envOboeAmp04,
                      sizeof (envOboeFrq04) / sizeof (ENV), envOboeFrq04,
                      sizeof (envOboeAmp05) / sizeof (ENV), envOboeAmp05,
                      sizeof (envOboeFrq05) / sizeof (ENV), envOboeFrq05,
                      sizeof (envOboeAmp06) / sizeof (ENV), envOboeAmp06,
                      sizeof (envOboeFrq06) / sizeof (ENV), envOboeFrq06,
                      sizeof (envOboeAmp07) / sizeof (ENV), envOboeAmp07,
                      sizeof (envOboeFrq07) / sizeof (ENV), envOboeFrq07,
                      sizeof (envOboeAmp08) / sizeof (ENV), envOboeAmp08,
                      sizeof (envOboeFrq08) / sizeof (ENV), envOboeFrq08,
                      sizeof (envOboeAmp09) / sizeof (ENV), envOboeAmp09,
                      sizeof (envOboeFrq09) / sizeof (ENV), envOboeFrq09,
                      sizeof (envOboeAmp10) / sizeof (ENV), envOboeAmp10,
                      sizeof (envOboeFrq10) / sizeof (ENV), envOboeFrq10,
                      sizeof (envOboeAmp11) / sizeof (ENV), envOboeAmp11,
                      sizeof (envOboeFrq11) / sizeof (ENV), envOboeFrq11,
                      sizeof (envOboeAmp12) / sizeof (ENV), envOboeAmp12,
                      sizeof (envOboeFrq12) / sizeof (ENV), envOboeFrq12,
                      sizeof (envOboeAmp13) / sizeof (ENV), envOboeAmp13,
                      sizeof (envOboeFrq13) / sizeof (ENV), envOboeFrq13,
                      sizeof (envOboeAmp14) / sizeof (ENV), envOboeAmp14,
                      sizeof (envOboeFrq14) / sizeof (ENV), envOboeFrq14,
                      sizeof (envOboeAmp15) / sizeof (ENV), envOboeAmp15,
                      sizeof (envOboeFrq15) / sizeof (ENV), envOboeFrq15,
                      sizeof (envOboeAmp16) / sizeof (ENV), envOboeAmp16,
                      sizeof (envOboeFrq16) / sizeof (ENV), envOboeFrq16,
                      sizeof (envOboeAmp17) / sizeof (ENV), envOboeAmp17,
                      sizeof (envOboeFrq17) / sizeof (ENV), envOboeFrq17,
                      sizeof (envOboeAmp18) / sizeof (ENV), envOboeAmp18,
                      sizeof (envOboeFrq18) / sizeof (ENV), envOboeFrq18,
                      sizeof (envOboeAmp19) / sizeof (ENV), envOboeAmp19,
                      sizeof (envOboeFrq19) / sizeof (ENV), envOboeFrq19,
                      sizeof (envOboeAmp20) / sizeof (ENV), envOboeAmp20,
                      sizeof (envOboeFrq20) / sizeof (ENV), envOboeFrq20,
                      sizeof (envOboeAmp21) / sizeof (ENV), envOboeAmp21,
                      sizeof (envOboeFrq21) / sizeof (ENV), envOboeFrq21 } ;

//以下定义单簧管的泛音集
PRT prtClar [21] =  { sizeof (envClarAmp01) / sizeof (ENV), envClarAmp01,
                      sizeof (envClarFrq01) / sizeof (ENV), envClarFrq01,
                      sizeof (envClarAmp02) / sizeof (ENV), envClarAmp02,
                      sizeof (envClarFrq02) / sizeof (ENV), envClarFrq02,
                      sizeof (envClarAmp03) / sizeof (ENV), envClarAmp03,
                      sizeof (envClarFrq03) / sizeof (ENV), envClarFrq03,
                      sizeof (envClarAmp04) / sizeof (ENV), envClarAmp04,
                      sizeof (envClarFrq04) / sizeof (ENV), envClarFrq04,
                      sizeof (envClarAmp05) / sizeof (ENV), envClarAmp05,
                      sizeof (envClarFrq05) / sizeof (ENV), envClarFrq05,
                      sizeof (envClarAmp06) / sizeof (ENV), envClarAmp06,
                      sizeof (envClarFrq06) / sizeof (ENV), envClarFrq06,
                      sizeof (envClarAmp07) / sizeof (ENV), envClarAmp07,
                      sizeof (envClarFrq07) / sizeof (ENV), envClarFrq07,
                      sizeof (envClarAmp08) / sizeof (ENV), envClarAmp08,
                      sizeof (envClarFrq08) / sizeof (ENV), envClarFrq08,
                      sizeof (envClarAmp09) / sizeof (ENV), envClarAmp09,
                      sizeof (envClarFrq09) / sizeof (ENV), envClarFrq09,
                      sizeof (envClarAmp10) / sizeof (ENV), envClarAmp10,
                      sizeof (envClarFrq10) / sizeof (ENV), envClarFrq10,
                      sizeof (envClarAmp11) / sizeof (ENV), envClarAmp11,
                      sizeof (envClarFrq11) / sizeof (ENV), envClarFrq11,
                      sizeof (envClarAmp12) / sizeof (ENV), envClarAmp12,
                      sizeof (envClarFrq12) / sizeof (ENV), envClarFrq12,
                      sizeof (envClarAmp13) / sizeof (ENV), envClarAmp13,
                      sizeof (envClarFrq13) / sizeof (ENV), envClarFrq13,
                      sizeof (envClarAmp14) / sizeof (ENV), envClarAmp14,
                      sizeof (envClarFrq14) / sizeof (ENV), envClarFrq14,
                      sizeof (envClarAmp15) / sizeof (ENV), envClarAmp15,
                      sizeof (envClarFrq15) / sizeof (ENV), envClarFrq15,
                      sizeof (envClarAmp16) / sizeof (ENV), envClarAmp16,
                      sizeof (envClarFrq16) / sizeof (ENV), envClarFrq16,
                      sizeof (envClarAmp17) / sizeof (ENV), envClarAmp17,
                      sizeof (envClarFrq17) / sizeof (ENV), envClarFrq17,
                      sizeof (envClarAmp18) / sizeof (ENV), envClarAmp18,
                      sizeof (envClarFrq18) / sizeof (ENV), envClarFrq18,
                      sizeof (envClarAmp19) / sizeof (ENV), envClarAmp19,
                      sizeof (envClarFrq19) / sizeof (ENV), envClarFrq19,
                      sizeof (envClarAmp20) / sizeof (ENV), envClarAmp20,
                      sizeof (envClarFrq20) / sizeof (ENV), envClarFrq20,
                      sizeof (envClarAmp21) / sizeof (ENV), envClarAmp21,
                      sizeof (envClarFrq21) / sizeof (ENV), envClarFrq21 } ;

INS insTrum = { 360, 12, prtTrum } ;//定义小号的乐器结构并赋值
INS insOboe = { 313, 21, prtOboe } ;//定义双簧管的乐器结构并赋值
INS insClar = { 330, 21, prtClar } ;//定义单簧管的乐器结构并赋值

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 AddSynth.rc 使用
//
#define IDC_TRUMPET                     1001
#define IDC_OBOE                        1002
#define IDC_CLARINET                    1003
#define IDC_TEXT                        1004

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        102
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1005
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//Addsynth.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

ADDSYNTH DIALOGEX 0, 0, 229, 66
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "加法合成器(Additive Synthesis)"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    PUSHBUTTON      "小号\n(Trumpet)",IDC_TRUMPET,19,14,55,24,BS_MULTILINE
    PUSHBUTTON      "双簧管\n(Oboe)",IDC_OBOE,89,14,50,24,BS_MULTILINE
    PUSHBUTTON      "单簧管\n(Clarinet)",IDC_CLARINET,159,15,50,24,BS_MULTILINE
    LTEXT           "数据准备中(Preparing Data)...",IDC_TEXT,19,44,192,8
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    "ADDSYNTH", DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 222
        TOPMARGIN, 7
        BOTTOMMARGIN, 59
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

22.2.9 波形音频闹钟

(1)通用控件库:

  ①#include <commctrl.h>和#pragma comment(lib,"Comctl32.lib")

  ②初始化InitCommonControlsEx(&icex);//通用控件的数量多,所在默认情况下Comctl32.dll并不载入内存,需用专用函数来完成加载。使用InitCommonControls载入库时,会注册所有通用控件类,而InitCommonControlsEx会载入扩展通用控件

(2)利用FILETIME结构进行时间的加减

     //为了避免SYSTEMTIME中加9小时后可能出现的日期或年份进位,将系统时间转为文件时间,加9小时后,再转化为系统时间,最后将此时间设置控件的时间

    GetLocalTime(&st);  //GetLocalTime能够得到本地电脑设置时区的时间

    SystemTimeToFileTime(&st, &ft); //将系统时间转为文件时间

    li = *(LARGE_INTEGER*)&ft;      //将时间存入一个大整数结构体

    li.QuadPart += 9 * FTTICKSPERHOUR;//加上9个小时包含的100纳秒的数量

                                      //Quad表示4字,即64位。

    ft = *(FILETIME*)&li;   //将大整数结构体转换为文件时间

    FileTimeToSystemTime(&ft, &st);

    st.wMinute = st.wSecond = st.wMilliseconds = 0;

【WakeUp程序】

技术分享

/*------------------------------------------------------------
   WAKEUP.C -- Alarm Clock Program
                 (c) Charles Petzold, 1998
  ------------------------------------------------------------*/

#include <windows.h>
#include <commctrl.h> //包含通用控件头文件

#pragma comment(lib,"Comctl32.lib")
#pragma comment(lib,"WINMM.lib")

 
//三个子窗口ID
#define ID_TIMEPICK    0  //时间控件ID
#define ID_CHECKBOX    1  //复选框按钮ID
#define ID_PUSHBTN     2  //关闭响铃按钮ID

//计时器ID
#define ID_TIMER       1

//定义1小时包含多少个100纳秒(nanosecond:十亿分之一秒)的数量
#define FTTICKSPERHOUR  (60*60*(LONGLONG)10000000)

//定义音频流结构文件
#define        SAMPRATE      11025         //采样率
#define        NUMSAMPS      (3*SAMPRATE)  //采样的数量
#define        HALFSAMPS     (NUMSAMPS /2) //采样数量的一半 

//定义WAV波形文件结构
typedef struct
{
    char chRiff[4];
    DWORD dwRiffSize;
    char chWave[4];
    char chFmt[4];
    DWORD dwFmtSize;
    PCMWAVEFORMAT  pwf;
    char chData[4];
    DWORD dwDataSize;
    BYTE  byData[0];
}WAVEFORM,*PWAVEFORM;

//主窗口过程与子窗口类过程
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK SubProc(HWND, UINT, WPARAM, LPARAM);

//存储子控件旧的窗口过程
WNDPROC  SubbedProc[3];

//当前具有输入焦点的子窗口句柄
HWND hwndFocus;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("WakeUp") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         =0;  // CS_HREDRAW | CS_VREDRAW;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) (1+ COLOR_BTNFACE) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName,                  // window class name
                          szAppName, // window caption
                          WS_OVERLAPPED | WS_CAPTION |
                                          WS_SYSMENU | WS_MINIMIZEBOX,        // window style
                          CW_USEDEFAULT,              // initial x position
                          CW_USEDEFAULT,              // initial y position
                          CW_USEDEFAULT,              // initial x size
                          CW_USEDEFAULT,              // initial y size
                          NULL,                       // parent window handle
                          NULL,                       // window menu handle
                          hInstance,                  // program instance handle
                          NULL) ;                     // creation parameters
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND hwndDTP, hwndCheck, hwndPush; //时间控件、复选框、按钮
     INITCOMMONCONTROLSEX icex; //须包含commctrl.h文件头

     HINSTANCE hInstance;
     int cxChar, cyChar;
     SYSTEMTIME   st;//系统时间变量
     FILETIME     ft;//文件时间变量,FILETIME结构持有的64位无符号的文件的日期和时间值。
                      //此值表示自1601年1月1日开始的100纳秒为单位的时间

     LARGE_INTEGER        li;   //64位,用于储存时间的大整数结构体变量

     static WAVEFORM waveform = { "RIFF", NUMSAMPS + 0x24, "WAVE", "fmt ", 
                                 sizeof(PCMWAVEFORMAT),1,1,SAMPRATE,SAMPRATE,1,8,"data",
                                 NUMSAMPS};
     static WAVEFORM *pwaveform;  //定义音频结构体变量
     int i;

     switch (message)
     {
     case WM_CREATE:
          hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
          cxChar = LOWORD(GetDialogBaseUnits());
          cyChar = HIWORD(GetDialogBaseUnits());

          //SWP_NOMOVE:维持当前位置(忽略X和Y参数)
          //SWP_NOACTIVATE:不激活窗口。如果未设置标志,则窗口被激活,
          //并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)
          //SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)
          SetWindowPos(hwnd, NULL, 0, 0,
                       42*cxChar,
                       10 * cyChar / 3 + 2 * GetSystemMetrics(SM_CYBORDER)+
                                             GetSystemMetrics(SM_CYCAPTION),
                       SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);

          icex.dwSize = sizeof(icex);
          icex.dwICC = ICC_DATE_CLASSES;

           //通用控件的数量多,所在默认情况下Comctl32.dll并不载入内存,需用专用函数来完成加载
           //使用InitCommonControls载入库时,会注册所有通用控件类,而InitCommonControlsEx会载
           //入扩展通用控件
          InitCommonControlsEx(&icex);

          //用方波数据交替创建波形文件
          pwaveform = malloc(sizeof(WAVEFORM)+NUMSAMPS); //WAVEFORM为自定义的WAV音频结构体
          *pwaveform = waveform;  //填入WAV文件前面的数据
          for (i = 0; i < HALFSAMPS; i++)  //0-HALFSAMPS-1:有波形数据。HALFSAMEPLES以后静音
          {
              if (i % 600 <300)
              {
                  if (i % 16 < 8)
                      pwaveform->byData[i] = 25;
                  else
                      pwaveform->byData[i] = 230;
         
              }
              else
              {
                  if (i % 8 < 4)
                      pwaveform->byData[25];
                  else
                      pwaveform->byData[230];
              }
          }

          //创建三个子控件
          hwndDTP = CreateWindow(DATETIMEPICK_CLASS, TEXT(""), 
                                 WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_TIMEFORMAT,
                                 2*cxChar,cyChar*2/3,12*cxChar,4*cyChar /3,
                                 hwnd,(HMENU)ID_TIMEPICK,hInstance,NULL);

          hwndCheck = CreateWindow(TEXT("Button"), TEXT("Set Alarm"), 
                                   WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
                                   16*cxChar,cyChar*2/3,12*cxChar,4*cyChar/3,
                                   hwnd,(HMENU)ID_CHECKBOX,hInstance,NULL);

          hwndPush = CreateWindow(TEXT("Button"), TEXT("Turn Off"),
                                 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
                                 28 * cxChar, cyChar * 2 / 3, 11 * cxChar, 4 * cyChar / 3,
                                 hwnd, (HMENU)ID_PUSHBTN, hInstance, NULL);
          
          hwndFocus = hwndDTP;

          //子窗口类化三个子窗口控件
          SubbedProc[ID_TIMEPICK] = (WNDPROC)SetWindowLong(hwndDTP, GWL_WNDPROC, (LONG)SubProc);
          SubbedProc[ID_CHECKBOX] = (WNDPROC)SetWindowLong(hwndCheck, GWL_WNDPROC, (LONG)SubProc);
          SubbedProc[ID_PUSHBTN]  = (WNDPROC)SetWindowLong(hwndPush, GWL_WNDPROC, (LONG)SubProc);

          //将时间控件设置为当前计算机的时间加9个小时,表示9小时以后闹钟响铃
          //为了避免st加9小时后可能出现的日期或年份进位,将系统时间转为文件时间,加9小时后,再
          //转化为系统时间,最后将此时间设置控件的时间
          GetLocalTime(&st);  //GetLocalTime能够得到本地电脑设置时区的时间
          SystemTimeToFileTime(&st, &ft); //将系统时间转为文件时间
          li = *(LARGE_INTEGER*)&ft;      //将时间存入一个大整数结构体
          li.QuadPart += 9 * FTTICKSPERHOUR;//加上9个小时包含的100纳秒的数量
          ft = *(FILETIME*)&li;   //将大整数结构体转换为文件时间
          FileTimeToSystemTime(&ft, &st);
          st.wMinute = st.wSecond = st.wMilliseconds = 0;

          SendMessage(hwndDTP, DTM_SETSYSTEMTIME, 0, (LPARAM)&st);//定时,设置响铃时间
          return 0 ;

     case WM_SETFOCUS:
         SetFocus(hwndFocus);
         return 0;

     case WM_COMMAND:
         switch (LOWORD(wParam))
         {
         case ID_CHECKBOX:  //处理复选框按钮
             //当按下“Set Alarm”时,取得控件当前的时间并减去当前系统时间
             if (SendMessage(hwndCheck,BM_GETCHECK,0,0))
             {
                 //获得控件时间
                 SendMessage(hwndDTP, DTM_GETSYSTEMTIME, 0, (LPARAM)&st);
                 SystemTimeToFileTime(&st, &ft);
                 li = *(LARGE_INTEGER*)&ft;

                 //获取当前计算机时间
                 GetLocalTime(&st);
                 SystemTimeToFileTime(&st, &ft);
                 li.QuadPart -= ((LARGE_INTEGER*)&ft)->QuadPart; //计算时间间隔

                 //确保时差在0-24小时范围内
                 while (li.QuadPart < 0)
                     li.QuadPart += 24 * FTTICKSPERHOUR; //确保时差>=0;

                 li.QuadPart %= 24 * FTTICKSPERHOUR;    //确保时差<24;

                 //设置一个一次性的计时器,触发时间为以上的计算所得的时差
                 //x(ms)= (li.QuadPart*100(ns)/1000000000)*1000 =li.QuadPart/10000
                 SetTimer(hwnd, ID_TIMER, (int)(li.QuadPart / 10000), 0);

             }
             //如果未选中复选框,则删除计时器
             else
                 KillTimer(hwnd, ID_TIMER);

             return 0;

         case ID_PUSHBTN:
             PlaySound(NULL, NULL, 0); //播放声间
             SendMessage(hwndCheck, BM_SETCHECK, 0, 0); //取消复选框选中状态
             EnableWindow(hwndDTP, TRUE);
             EnableWindow(hwndCheck, TRUE);
             EnableWindow(hwndPush, FALSE);
             SetFocus(hwndDTP);
             return 0;
         }
         break;

     case WM_NOTIFY: //来自时间控件的通知消息
         //当用户选中复选框,然后再去改变时间控件的值时,会导致显示的时间和响铃的时间不同,
         //因此,在此种情况下改变时间控件时,则删除计时器,并让取消复选框选中状态,让用户
         //重新设置。
         switch (wParam) //wParam:控件ID。lParam——指向NMHDR结构(包含通知码和其他额外信息)
         {               //NMHDR:含三个字段:hwndFrom、idFrom、code
         case ID_TIMEPICK:
             switch (((NMHDR*)lParam)->code)
             {
             case DTN_DATETIMECHANGE:  //改变控件时间通知
                 if (SendMessage(hwndCheck,BM_GETCHECK,0,0))
                 {
                     KillTimer(hwnd, ID_TIMER);
                     SendMessage(hwndCheck, BM_SETCHECK, 0, 0);
                 }
                 return 0;
             }
         }
         return 0;

     case WM_TIMER://当响铃时间到来时,收到此消息
         KillTimer(hwnd, ID_TIMER); 
         PlaySound((PTSTR)pwaveform, NULL, SND_MEMORY | SND_LOOP | SND_ASYNC); //异步循环播放

         EnableWindow(hwndDTP, FALSE);
         EnableWindow(hwndCheck, FALSE);
         EnableWindow(hwndPush, TRUE);
         hwndFocus = hwndPush; //这里不需要调用SetFocus来设置按钮为焦点窗口,因为后面的ShowWindow会向对话框恢复,
                               //就会调用本窗口过程WM_SETFOCUS去处理。
         ShowWindow(hwnd, SW_RESTORE); //如果窗口最小化,则恢复主窗口。
         SetForegroundWindow(hwnd); //将主窗口设置到前台,并激活,以便接收键盘消息(因为用户要用键盘取消响铃)
                                    
         return 0;

     case WM_DESTROY:
          if (pwaveform)
             free(pwaveform);

          if (IsWindowEnabled(hwndPush))
              PlaySound(NULL, NULL, 0); //停止响铃

          if (SendMessage(hwnd, BM_GETCHECK, 0, 0))
              KillTimer(hwnd, ID_TIMER);
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

LRESULT CALLBACK  SubProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int id,idNext;
    id = GetWindowLong(hwnd, GWL_ID);  //获取子窗口控件ID
    switch (message)
    {
    case WM_CHAR:
            if (wParam == \t) //处理按下Tab键消息
        {
            idNext = id;
            do
            {
                //如果同时按下Shift时,跳两个控件
                idNext = (idNext + (GetKeyState(VK_SHIFT) < 0 ? 2 : 1)) % 3;
            } while (!IsWindowEnabled(GetDlgItem(GetParent(hwnd),idNext)));
            SetFocus(GetDlgItem(GetParent(hwnd), idNext));
            return 0;
        }
        break;

    case WM_SETFOCUS:
        hwndFocus = hwnd;
        break;
    }
    //传给子控件旧的窗口过程处理
    return CallWindowProc(SubbedProc[id], hwnd, message, wParam, lParam);

}

22.3 MIDI和音乐(本节未读过)

 

第22章 声音与音乐(3)

标签:

原文地址:http://www.cnblogs.com/5iedu/p/4715233.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!