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

[从头学声学] 第207节 声学的原理

时间:2016-05-07 09:58:00      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:

剧情提要:
[机器小伟]在[工程师阿伟]的陪同下进行着声学神通的修炼。
这次要研究的是[声学的原理]。

正剧开始:


星历2016年05月06日 13:54:48, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究[声学的原理]。


技术分享


技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

这个音高频率表是这样算出来的:

[32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55.0, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110.0, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220.0, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440.0, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880.0, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760.0, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520.0, 3729.31, 3951.066]

def tmp():
    #公比 半音
    q = 2**(1/12);
    #A4 = (+9)
    A4 = 440;
    #C1 = (-36)
    C1 = A4/q**45;

    toneFrequence = [];
    for i in range(-36, 48):
        toneFrequence.append(round(A4*q**(i-9), 3));

    print(toneFrequence);


技术分享


>>> 203.91*5+90.22
1109.77
>>> 203.91*5+90.22*2
1199.99

>>> 
[440, 469.865, 495.0, 528.598, 556.875, 594.672, 626.484, 669.006, 704.795, 752.632, 792.894, 846.711, 892.006]

#三分损益法(黄钟大吕音)
def tmp():
    #公比 半音
    q = 2**(1/1200);
    #A4 = (+9)
    A4 = 440;
    tmpfreq  = A4;
    
    toneFrequence = [];
    for i in range(13):        
        toneFrequence.append(round(tmpfreq, 3));
        if (i%2==0):
            tmpfreq *= q**(113.69);
        else:
            tmpfreq *= q**(90.22);
    print(toneFrequence);

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享


技术分享

技术分享


技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享技术分享

技术分享

技术分享

技术分享


阿伟给小伟做了一个乐音遍历工具,可以听出国际谱中的所有音符。

本来可以传到酷狗的,但想了想,还是传优酷了,尽管很短,

还要看很长时间的广告。


点击打开链接 -- 乐音音符


idleWave = [b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00'];


#把十进制数按照小尾字节序切割
def littleEndian(number, byte = 4):
    result = [0]*byte;

    for i in range(byte):
        result[i] = number%256;
        number//=256;
    return result;




    

#把UltraEdit中的值字串转化为hex序列组
def hexExpr(string):
    resultString = '';
    size = len(string);
    for i in range(size):
        if (i == 0 ):
            resultString += '0x'+string[i];
        elif (string[i] == ' '):
            resultString += ', 0x';
        else:
            resultString += string[i];
    print(resultString);


###
# @usage   写.wav文件,能把声波数据阵列用二进制写成.wav。
# @author  mw
# @date    2016年04月28日  星期四  14:31:34 
# @param
# @return
#
###
def writeWav(index , filename):
    
    byteArray = [];
    dataArray = [];

    mode = 2;
    
    #样本数据阵列
    sampleArray = [];

    if mode == 1:
        sampleArray = waveDataChoose(index, filename);
    elif mode == 2:
        sampleArray = waveDataChoose_2(filename);

    #样本数据点数
    N = len(sampleArray);
    times = 2;
    dataSize = N*times;
    
    fileSize = dataSize+44; #44为格式头部分所用字节数
    
    #RIFF WAVE CHUNK
    RIFF_ID = [0x52, 0x49, 0x46, 0x46];  #'RIFF'
    RIFF_Size = littleEndian(fileSize-8, 4); #文件总字节数减去8
    RIFF_Type = [0x57, 0x41,0x56, 0x45, 0x66, 0x6D, 0x74, 0x20]; #'WAVEfat '

    #Format Chunk
    Format_10_17 = [0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00];#过滤4+格式2+声道2=8个字节
    Format_18_1B = [0x11, 0x2B, 0x00, 0x00]; #采样频率0x2B11 = 11025
    Format_1C_1F = [0x22, 0x56, 0x00, 0x00]; #比持率 = 频率*通道*样本位 = 22050
    Format_20_23 = [0x02, 0x00, 0x10, 0x00]; #块对齐 = 通道数* 样本位数 = 1*2 = 2    

    #Fact Chunk(optional)

    #Data Chunk
    Data_24_27 = [0x64, 0x61, 0x74, 0x61]; #'DATA'标记
    Data_Size = littleEndian(fileSize-44, 4); #下面的Data部分的字节数,文件总字节数-44


    #RIFF WAVE CHUNK
    '''
    for i in range(4):
        byte = struct.pack('B', RIFF_ID[i]);
        byteArray.append(byte);
    '''

    RIFF = [b'R', b'I', b'F', b'F'];
    for i in range(4):
        byteArray.append(RIFF[i]);

    for i in range(4):
        byte = struct.pack('B', RIFF_Size[i]);
        byteArray.append(byte);

    '''
    for i in range(8):
        byte = struct.pack('B', RIFF_Type[i]);
        byteArray.append(byte);

    #Format Chunk
    for i in range(8):
        byte = struct.pack('B', Format_10_17[i]);
        byteArray.append(byte);

    for i in range(4):
        byte = struct.pack('B', Format_18_1B[i]);
        byteArray.append(byte);

    for i in range(4):
        byte = struct.pack('B', Format_1C_1F[i]);
        byteArray.append(byte);

    for i in range(4):
        byte = struct.pack('B', Format_20_23[i]);
        byteArray.append(byte);

    
    #Data Chunk
    for i in range(4):
        byte = struct.pack('B', Data_24_27[i]);
        byteArray.append(byte);
    '''

    #Format_28_2B是数据块大小,formatHead是它前面的所有部分
    formatHead = [b'W', b'A', b'V', b'E', b'f', b'm', b't', b' ',                   b'\x10', b'\x00', b'\x00', b'\x00', b'\x01', b'\x00', b'\x01', b'\x00',                   b'\x11', b'+', b'\x00', b'\x00',                   b'"', b'V', b'\x00', b'\x00',                   b'\x02', b'\x00', b'\x10', b'\x00',                   b'd', b'a', b't', b'a'];

    for i in range(len(formatHead)):
        byteArray.append(formatHead[i]);

    for i in range(4):
        byte = struct.pack('B', Data_Size[i]);
        byteArray.append(byte);


    #写出到文件
    print('文件写入开始。>>>');

    s = '';
    if mode == 1:
        s = filename[index]+'.wav';
    elif mode == 2:
        s = 'randMusic'+str(index)+'.wav';
        
    fout= open(s, 'wb');
    size = len(byteArray);
    
    for i in range(size):
        fout.write(byteArray[i]);       
    
    size = len(sampleArray);
    sizeIdle = len(idleWave);
    

    
    for j in range(times):
        for i in range(size):
            fout.write(sampleArray[i]);

    fout.close();
    print('文件写入完毕。');


#生成声音样本,返回样本矩阵
def sampleGen(N, freq):
    #设立20000个数值点,约可听2秒
    sampleArray = [];

    coef = 2*math.pi*freq/11025;
    #音色调节
    weight = [1, 2.55, 2.13, 1.98, 1.57, 1.23];
    total = sum(weight);
   
    
    for i in range(N):
        xvalue = coef*i;
        
        yvalue = (weight[0]*math.sin(xvalue) + weight[1]*math.sin(xvalue*2)+ weight[2]*math.sin(xvalue*3) +                 weight[3]*math.sin(xvalue*4) + weight[4]*math.sin(xvalue*5)+ weight[5]*math.sin(xvalue*6))/total;
        if (yvalue < 0):
            yvalue *= 32768;
        else:
            yvalue *= 32767;
        sampleArray.append(round(yvalue));
    return sampleArray;


def waveDataGen(freq):
    N = 200;

    sampleArray = sampleGen(N, freq);
    dataArray = [];
    
    for i in range(N):
        value = littleEndian(sampleArray[i], 2);
        for j in range(2):
            byte = struct.pack('B', value[j]);
            dataArray.append(byte);    

    return dataArray;

def genIdle():
    dataArray = [];
    
    for i in range(200):
        value = littleEndian(0, 2);
        for j in range(2):
            byte = struct.pack('B', value[j]);
            dataArray.append(byte);    

    print(dataArray);

#波形选择
def waveDataChoose(index, filename):
    import wavedata;
    
    tmpdata = eval('wavedata.'+filename[index]);

    sampledata = [];

    for i in range(1, 21):
        for j in range(15):
            sampledata += idleWave;

        for j in range(i):
            sampledata += tmpdata;

        for j in range(15):
            sampledata += idleWave;

    return sampledata; 

def waveDataChoose_2(filename):
    import wavedata;

    size = len(filename);    

    sampledata = [];
    
    for i in range(300):
        #index_1 = random.randint(24, size-1-36);
        idleCircle = random.randint(2, 8);
        longIdleCircle = random.randint(8, 20);
        musicCircle = random.randint(2, 15);
        
        tmpdata = eval('wavedata.'+filename[i%size]);

        for j in range(musicCircle):
            sampledata += tmpdata;

        for j in range(idleCircle):
            sampledata += idleWave;

        if (i%longIdleCircle == 0):
            for j in range(longIdleCircle):
                sampledata += idleWave;

    for i in range(30):
        sampledata += idleWave;

        
    return sampledata;
    

#调用入口, 生成wav文件
def tmp(filename):
    size = len(filename);
    
    for i in range(size):
        if i > 300:
            break;
        
        writeWav(i, filename);

def tmp_2(index, filename):
    writeWav(index, filename);

#生成声波数据
def tmp2():
    print('生成波形开始。>>>');
    
    fout= open('output.txt', 'w');

    frequence = [32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55.0, 58.27, 61.735,                 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110.0, 116.541, 123.471,                 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220.0, 233.082, 246.942,                 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440.0, 466.164, 493.883,                 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880.0, 932.328, 987.767,                 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760.0, 1864.655, 1975.533,                 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520.0, 3729.31, 3951.066];

    size = len(frequence);
    
    for i in range(size):
        dataStr = 'musicfreq_'+str(frequence[i]).replace('.', 'p') + ' = [';
        fout.write(dataStr);

        data = waveDataGen(frequence[i]);
        size_1 = len(data);

        for n in range(size_1):
            fout.write(str(data[n]));
            if (n < size_1-1):
                fout.write(', ');

        fout.write('];');
            
        fout.write('\r\n');

    fout.close();
    print('生成波形结束,请到output.txt查收。');



#打印文件名             
def tmp3():
    filename = [];
    
    frequence = [32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55.0, 58.27, 61.735,             65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110.0, 116.541, 123.471,             130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220.0, 233.082, 246.942,             261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440.0, 466.164, 493.883,             523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880.0, 932.328, 987.767,             1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760.0, 1864.655, 1975.533,             2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520.0, 3729.31, 3951.066];

    size = len(frequence);
    
    for i in range(size):
        dataStr = 'musicfreq_'+str(frequence[i]).replace('.', 'p');
        filename.append(dataStr);

    print(filename);


if __name__ == '__main__':    
    part = 1;

    if (part == 3):
        tmp3();
    elif (part == 2):
        tmp2();
    elif (part == 1):
        import wavename;
        filename = wavename.wavename;
        
        tmp_2(3, filename);
        


技术分享


技术分享

点击打开链接 -- 元音发音


#生成声音样本,返回样本矩阵
def sampleGen_2(N, freq1, freq2):
    #设立20000个数值点,约可听2秒
    sampleArray = [];

    coef = 2*math.pi/11025;

    #音色调节
    weight = [1.53, 1];
    total = sum(weight);
    
    for i in range(N):
        xcoef_1 = coef*i*freq1;
        xcoef_2 = coef*i*freq2;
        
        yvalue = (weight[0]*math.sin(xcoef_1)+ weight[1]*math.sin(xcoef_2))/total;
        
        if (yvalue < 0):
            yvalue *= 32768;
        else:
            yvalue *= 32767;
        sampleArray.append(round(yvalue));
    return sampleArray;


def waveDataGen_2(freq1, freq2):
    N = 200;

    sampleArray = sampleGen_2(N, freq1, freq2);
    dataArray = [];
    
    for i in range(N):
        value = littleEndian(sampleArray[i], 2);
        for j in range(2):
            byte = struct.pack('B', value[j]);
            dataArray.append(byte);    

    return dataArray;                                                          

#生成声波数据
def tmp2_2():
    print('生成波形开始。>>>');
    
    fout= open('output.txt', 'w');

    frequence = [[240,2400],
                 [235,2100],
                 [390,2300],
                 [370,1900],
                 [610,1900],
                 [585,1710],
                 [850, 1610],
                 [820, 1530],
                 [750, 940],
                 [700, 760],
                 [600, 1170],
                 [500, 700],
                 [460, 1310],
                 [360, 640],
                 [300, 1390],
                 [250, 595]];
    
        
    size = len(frequence);
    
    for i in range(size):
        dataStr = 'primaryTone_'+ str(frequence[i][0])+'_'+str(frequence[i][1]) + ' = [';
                                                               
        fout.write(dataStr);

        data = waveDataGen_2(frequence[i][0], frequence[i][1]);
        size_1 = len(data);

        for n in range(size_1):
            fout.write(str(data[n]));
            if (n < size_1-1):
                fout.write(', ');

        fout.write('];');
            
        fout.write('\r\n');

    fout.close();
    print('生成波形结束,请到output.txt查收。');
    
#生成声波数据
def tmp3_2():
    filename = [];

    frequence = [[240,2400],
                 [235,2100],
                 [390,2300],
                 [370,1900],
                 [610,1900],
                 [585,1710],
                 [850, 1610],
                 [820, 1530],
                 [750, 940],
                 [700, 760],
                 [600, 1170],
                 [500, 700],
                 [460, 1310],
                 [360, 640],
                 [300, 1390],
                 [250, 595]];
        
    size = len(frequence);
    
    for i in range(size):
        dataStr = 'primaryTone_'+ str(frequence[i][0])+'_'+str(frequence[i][1]);                                                               
        filename.append(dataStr);
    
    print(filename);

    
if __name__ == '__main__':    
    part = 1;

    if (part == 3):
        tmp3_2();
    elif (part == 2):
        tmp2_2();
    elif (part == 1):
        import wavename;
        filename = wavename.wavename;
        
        tmp_2(5, filename);


技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

本节到此结束,欲知后事如何,请看下回分解。

[从头学声学] 第207节 声学的原理

标签:

原文地址:http://blog.csdn.net/mwsister/article/details/51331074

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