タグ別アーカイブ: 音声

今度はノコギリ波をつくろう

毎度、いかおです。

前回はサイン波を作成してならせてみせましたが今度はノコギリ波を作ります。

先ず、ノコギリ波はどんな波形かというと・・・・

そこはグーグル先生に聞いて下さい。

【その原理】

「キャリアとモジュレータとの周波数を1:1にするとノコギリ波が作れる」

ということなので、いわゆるFM音源的アプローチで(サイン波はできてるので)作ってみます

先ず、1サイクルのサイン波を作成する。コレは前回の私の投稿であるここを参考にして・・・・

例えば1サイクルのサイン波はこんな感じで作れるかな?

static const float PI = 3.141592f;
static const float SamplingRate = 48000.0f;
static const float Heltz = 440.0f; //ラ〜♪
static const float DegBase = 360.0f;
float width = DegBase / (SamplingRate / Heltz);

float vals[360];
floart deg = 0.0f;
int n = n;
for(int i=0;i < 360){
    if(deg > DegBase)break;
    vals[i] = sin(deg * PI / 180);
    deg = deg + width;
   n++;
}

そしてアドレステーブルを作成する。FM音源はこのアドレステーブルを他のサイン波と加算したりして変調し変調された順番で元のサイン波を取り出す。なんだか無茶な方法に見えるけどしょせん楽器なんでいいか・・・

int addresTable[360];
// アドレステーブルはintにしとこう
for(int i=0;i < n;i++){
    addressTable[i]=i;
}

そして変調だ。元のサイン波と混ぜてしまう

int editedAddressTable[360];
//これもint
for(int i=0;i < n;i++){
    editedAddressTable[i] = vals[i] + addressTable[i];
}

そして取り出す・・・

float answer[360]:
for(int i=0;i < n;i++){
    answer[i] = vals[editedAddressTable[i]];
}
// このanswerがFM変調後の音です

これが本当にノコギリ波になるのか?

次回、作ってみます


周波数440Hzの正弦波をサンプリングレート48Kで作ってみる(実践編)

タグ: , | 投稿日: 投稿者:

毎度いかおです

前回-周波数440Hzの正弦波をサンプリングレート48Kで作ってみる(考察編)-で考えたことを実行してみます。

 

データ的にサイン波になったよ〜パチパチ

 

ではつまらんので実際にWAVを作ります

その前に前回の考察の誤りについて

サンプル取得のステップ幅 = 1回転の長さ / 360

は間違いですね。1つのサンプルでどれだけ角度が変わるかですし、1回転の長さってのも変で、"1回転分のサンプル数"っていうのが正しいですね。

サンプル取得のステップ幅 = 360 / 1回転分のサンプル数

でWAVの作り方はgoogle先生に"wav フォーマット 解析"と聞くと答えて下さります。

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

static const double     PI      =       3.1415926535f;
static const double     Volume  =       2048.0f;
static const double     SampleRate      =       48000.0f;
static const double     Heltz   =       440.0f;
static const double     DegBase =       360.0f;
static const int        SampleSec       =       5;
static double SampleWidth;

typedef struct {
        char            header[4];
        uint32_t        fileLength;
        char            fmtHead[4];
} FileHeader;

typedef struct {
        char            chunkID[4];
        uint32_t        chunkSize;
        uint16_t        formatCode;
        uint16_t        channels;
        uint32_t        sampleRatio;
        uint32_t        sampleBytePerSeccond;
        uint16_t        alignment;
        uint16_t        bitDepth;
} FormatChunk;

typedef struct {
        char    chunkID[4];
        int32_t chunkSize;
} DataChunk;

int main(int argc, char **argv){
        FILE    *fp     =       NULL;
        double  deg     =       0.0f;
        size_t  asize;
        short   *sample =       NULL;
        long    i;
        size_t  sumSize =       0;

        FileHeader      fileHeader;
        FormatChunk     formatChunk;
        DataChunk       dataChunk;

        fileHeader.fileLength = (sizeof(FileHeader) + sizeof(FormatChunk) +
                        sizeof(DataChunk) + sizeof(short) * (int)SampleRate * SampleSec) - 8;
        memcpy(fileHeader.header,       "RIFF", 4);
        memcpy(fileHeader.fmtHead,      "WAVE", 4);

        memcpy(formatChunk.chunkID,     "fmt ", 4);
        formatChunk.chunkSize   =       16;
        formatChunk.formatCode  =       1;
        formatChunk.channels    =       1;
        formatChunk.sampleRatio =       (unsigned long)SampleRate;
        formatChunk.sampleBytePerSeccond        =       (unsigned long)SampleRate * 2;
        formatChunk.alignment           =       2;
        formatChunk.bitDepth    =       16;

        if(argc < 2){
                printf("Argument 1 must be output wav name\n");
                return -2;
        }

        fp = fopen(argv[1], "wb");
        if(fp == NULL){
                printf("file:%s open error\n", argv[1]);
                return -3;
        }
        sample = (short *)malloc(sizeof(short) * SampleRate * SampleSec);
        if(sample == NULL){
                fclose(fp);
                printf("Allocation error(%lu)\n", sizeof(short) * (int)SampleRate * SampleSec);
                return -4;
        }
       // 今回訂正した部分
        SampleWidth = DegBase / (SampleRate / Heltz);
        memcpy(dataChunk.chunkID,       "data", 4);
        dataChunk.chunkSize     =       sizeof(short) * SampleRate * SampleSec;
        for(i=0;i < SampleRate * SampleSec;i++){
    // 結果が-Volume から Volume までの値のためVolume分プラスに寄せます
                sample[i] = (short)(round(Volume * sin(deg * PI / 180)) + Volume);
                deg     =       deg + SampleWidth;
        }
        fwrite((char *)&fileHeader, 1, sizeof(FileHeader), fp);
        fwrite((char *)&formatChunk, 1, sizeof(FormatChunk), fp);
        fwrite((char *)&dataChunk, 1, sizeof(DataChunk), fp);
        fwrite((char *)sample, 1, sizeof(short) * (int)SampleRate * SampleSec, fp);
        free(sample);
        fclose(fp);
        return  0;
}

それから、ボリュームですが128では小さい(これでも小さいが・・)ので2048にしてます。

できたのが、これです

おお、ラの音じゃん。


周波数440Hzの正弦波をサンプリングレート48Kで作ってみる(考察編)

タグ: | 投稿日: 投稿者:

まいど、いかおです

表題の件、考えてみます。間違ってたらツッコミをよろしくお願いします。

サイン波ですからsin/cos/tanのsinを使いますよね。これを1秒間に440回転させればいいんです。

ここでサンプリングレートが48Kですから、1回転の長さ(サンプル数)は

1回転の長さ=48000/440

この長さで1回転させるのでサンプル取得のステップ幅は

サンプル取得のステップ幅 = 1回転の長さ / 360

で、コード的にはこんな感じなのか?

// 1秒分の440Hzのサイン波作成
// サンプルはunsigned shortで作ってみる(16bit)
// 音量はどうしよう・・・とりあえず128
static const double PI =  3.1415926535;
static const short vol = 128;
double sampleWidth = (48000 / 440) / 360;
double deg = 0.0f;

unsigned short sample[48000]:

for(int i=0;i < 48000;i++){
    sample[i] = (unsigned short)vol * sin(deg * PI /180);
    deg = deg + (48000 / 440) / 360;
}

次回、実際にやってみて検証します。


音声の倍速再生

タグ: , | 投稿日: 投稿者:

毎度、いかおです

前回の続きで倍速再生について、特に音声の切り詰めかたを考えてみた。

・音声をある一定の長さできる

・それをつなげる

・のりしろを作る

まずは、これを図にしてみました

baisoku

1番上が元の波形(だと思って!)で、矢印がついてる部分がサンプル対象です。

2番めはサンプル対象をくっつけた図。オレンジの線はその間のサンプル

3番めはのりしろをフェードアウト/フェードインしたところです。ここで赤い線の様になってショックノイズを低減させます

フェードイン/アウト コード例】

#define NORISHIRO 100 // 例えばのりしろは100個
.
.
.
// 音声デコードがされたら
avcodec_decode_audio4(audioCodecCtx, decodedAudio, &amp;amp;amp;decodedSize, &amp;amp;amp;packet);
if (decodedSize > 0){
    size_t packetSize;
    // flgならsample出す
    if(flg){
        // m_sampleCount のりしろ長さ
        packetSize = decodedAudio->nb_samples * sizeof(short) * CHANNEL;
        short *samp = (short *)decodedAudio->data[0];
        flg = false;
        // サンプルの中に左右交互にデータがある(プラナーでない)
        for(int i=0;i < m_sampleCount;i++){
            samp[(i * 2)] = (short)(((float)m_bef[(i * 2)] * (((float)m_sampleCount - (float)i - 1.0f) / (float)m_sampleCount)) +
            ((float)samp[(i * 2)] * (((float)i + 1 ) / (float)m_sampleCount)));
            samp[(i * 2) + 1] = (short)(((float)m_bef[(i * 2) + 1] * (((float)m_sampleCount - (float)i - 1.0f) / (float)m_sampleCount)) +
           ((float)samp[(i * 2) + 1] * (((float)i + 1 ) / (float)m_sampleCount)));
        }
        // ここが再生データ
        decodedAudio->data[0];
        // これが再生データの長さ
        packetSize;
    } else {
        // ! flgならsample保存(フェードアウトに利用)
        if(decodedAudio->nb_samples > NORISHIRO){
            m_sampleCount = NORISHIRO;
        } else {
            m_sampleCount = decodedAudio->nb_samples;
        }
        memcpy((char *)m_bef, (char *)decodedAudio-&gt;data[0], m_sampleCount * sizeof(short) * 2);
        flg = true;
    }
}
.
.
.

ひとまずはこれでさほどノイズが気にならなくなりました。

1度に採れるサンプル数にもよりますが、のりしろは長くとった方がキレイに再生できます


動画の倍速再生の考え方

タグ: , | 投稿日: 投稿者:

こんにちは毎度お騒がせします、いかおです

早送りと遅送り(?) まず、映像だけ考えていきますと・・・・・

1.再生時にフレームレートを偽る

→毎秒30フレームの動画であれば、これを毎秒60フレームの動画として再生すれば2倍速、毎秒15フレームで再生すれば0.5倍速になる。

2.フレームを間引いたり、水増しする

→再生対象フレームを半分にすると2倍速、同じフレームを2回づつ再生すると0.5倍速になる。

1の方法は昔のビデオテープの早送りに似た方法ですね。 デバイスその他が対応すれば、サンプリングレートを自在に操って様々な再生に対応できます。 遅くする方は簡単なのですが、早くする方は場合によって、デバイスが対応しないことがありそうです。

多分、普通は2の方法を採用しますね。ただ、これも2倍、3倍、1/2倍、1/3倍位はたやすいのですが、 1.5倍とか2/3倍とかの割り振りというか、計算は大変そうです。 この様に映像の方は案外簡単に速度変更できます。ま、こういうところは所詮ぱらぱら漫画の延長なので、考え方的にも 楽ですね。

でも、音を考えると意外に難しいのがわかります。

ここで、色んな難しいパターンを排除して、音声の2倍速再生を想像して下さい

【音の2倍速再生をどうするか?】

皆さんならどうします?

映像と同じで音声サンプルを半分間引くと、半分の長さの同じ様な波形ができます。

これは実際、間引いたためのギャップでノイズが多発するのと、そうです、

周波数があがるのです。つまり、音が高くなります。

昔のアナログビデオやカセットテープ(みんな知らないか?)の早送りみたいです。

映像でいくところのフレームレートの偽りと似ています。そんなことなら

最初からサンプリングレートを偽って再生すりゃいいんですよね。

でも、現実的じゃない。じゃ、間引きでいきますか?

「いや、それでいいよね。普通」

っていうなよ絶対。ダメ絶対

音程を上げなくても倍速再生できるんです。

音は実はいろいろ奥が深くて様々な方法があるのですが、概ね

こんな方法が採られます。

・音をある時間的長さのかたまりに分割して考える

・その大きさで間引いて、それぞれをつなぎ合わせる

・つなぐ部分にのりしろを設けて、のりしろ部分で前のかたまりのフェードアウトと次のかたまりのフェードインを合成する

#これはノイズ除去のために行います

実際のコードは次回必ず載せます。

それでは