Audio Codec

clipboard.png
clipboard1.png

在移動設(shè)備中没佑,Codec的作用可以歸結(jié)為4種,分別是:

1.對PCM等信號進行D/A轉(zhuǎn)換,把數(shù)字的音頻信號轉(zhuǎn)換為模擬信號
2.對Mic巷帝、Linein或者其他輸入源的模擬信號進行A/D轉(zhuǎn)換匆笤,把模擬的聲音信號轉(zhuǎn)變CPU能夠處理的數(shù)字信號
3.對音頻通路進行控制研侣,比如播放音樂,收聽調(diào)頻收音機炮捧,又或者接聽電話時庶诡,音頻信號在codec內(nèi)的流通路線是不一樣的
4.對音頻信號做出相應(yīng)的處理,例如音量控制咆课,功率放大末誓,EQ控制等等

移動設(shè)備中的ALSA(ASoC)

ASoC--ALSA System on Chip ,是為了更好地支持嵌入式處理器和移動設(shè)備中的音頻Codec的一套軟件體系书蚪。ASoC不能單獨存在喇澡,它建立在標準ALSA驅(qū)動之上,必須和標準的ALSA驅(qū)動框架相結(jié)合才能工作善炫。

Machine

是指某一款機器,可以是某款設(shè)備,某款開發(fā)板,又或者是某款智能手機,由此可以看出Machine幾乎是不可重用的,每個Machine上的硬件實現(xiàn)可能都不一樣,CPU不一樣,Codec不一樣,音頻的輸入撩幽、輸出設(shè)備也不一樣,Machine為CPU、Codec、輸入輸出設(shè)備提供了一個載體.

Platform (Soc)

一般是指某一個SoC平臺,比如pxaxxx,s3cxxxx,omapxxx等等,與音頻相關(guān)的通常包含該SoC中的時鐘窜醉、DMA宪萄、I2S、PCM等等,只要指定了SoC,那么我們可以認為它會有一個對應(yīng)的Platform,它只與SoC相關(guān),與Machine無關(guān),這樣我們就可以把Platform抽象出來,使得同一款SoC不用做任何的改動,就可以用在不同的Machine中.實際上,把Platform認為是某個SoC更好理解.

Codec

字面上的意思就是編解碼器,Codec里面包含了I2S接口榨惰、D/A拜英、A/D、Mixer琅催、PA(功放),通常包含多種輸入(Mic居凶、Line-in、I2S藤抡、PCM)和多個輸出(耳機侠碧、喇叭、聽筒,Line-out),Codec和Platform一樣,是可重用的部件,同一個Codec可以被不同的Machine使用.嵌入式Codec通常通過I2C對內(nèi)部的寄存器進行控制.

在軟件層面缠黍, ASoC也把嵌入式設(shè)備的音頻系統(tǒng)同樣分為3大部分弄兜, Machine, Platform和Codec

Machine驅(qū)動:

跟單板相關(guān)瓷式,綁定Platform和Codec驅(qū)動替饿,即表明使用的是哪個Platform,哪個CPU DAI贸典、DMA视卢、Codec和Codec DAI。

Platform驅(qū)動:

它包含了該SoC平臺的音頻DMA和音頻接口DAI的配置和控制( I2S廊驼, PCM等等), (DAI: Digital Audio Interface)

Codec驅(qū)動:

它包含了一些音頻的控件( Controls)据过,音頻接口, DAMP(動態(tài)音頻電源管理)的定義和某些Codec IO功能妒挎。所有的Codec驅(qū)動都要提供以下特性:
Codec DAI 和 PCM的配置信息蝶俱;
Codec的IO控制方式( I2C, SPI等)饥漫;
Mixer和其他的音頻控件;
Codec的ALSA音頻操作接口罗标;

ASoC把聲卡實現(xiàn)為一個Platform Device,然后利用Platform_device結(jié)構(gòu)中的dev字段:dev.drvdata,它實際上指向一個snd_soc_device結(jié)構(gòu).可以認為snd_soc_device是整個ASoC數(shù)據(jù)結(jié)構(gòu)的根本,

snd_soc_device結(jié)構(gòu)引出了snd_soc_card
snd_soc_card又引出了snd_soc_platform庸队、snd_soc_dai_link和snd_soc_codec結(jié)構(gòu)
,
snd_soc_card代表著Machine驅(qū)動,
snd_soc_platform則代表著Platform驅(qū)動,
snd_soc_codec和soc_codec_device則代表了Codec驅(qū)動,

而snd_soc_dai_link則負責連接Platform和Codec.

ASoC架構(gòu)中的Machine

Machine驅(qū)動,結(jié)構(gòu)alc5623_card闯割, 里面包含dai_link彻消。

Machine驅(qū)動在一個重要的數(shù)據(jù)結(jié)構(gòu)snd_soc_dai_link中,指定了Platform宙拉、 Codec宾尚、 codec_dai、 cpu_dai的名字,稍后Machine驅(qū)動將會利用這些名字去匹配已經(jīng)在系統(tǒng)中注冊的platform煌贴, codec御板, dai,這些注冊的部件都是在另外相應(yīng)的Platform驅(qū)動和Codec驅(qū)動的代碼文件中定義的牛郑,這樣看來怠肋, Machine驅(qū)動的設(shè)備初始化代碼無非就是選擇合適Platform和Codec以及dai,用他們填充以上幾個數(shù)據(jù)結(jié)構(gòu)淹朋,然后注冊Platform設(shè)備即可笙各。

ASoC的platform_driver在以下文件中定義:sound/soc/soc-core.c。
ASoC定義了三個全局的鏈表頭變量:codec_list础芍、dai_list杈抢、platform_list,系統(tǒng)中所有的Codec仑性、DAI惶楼、Platform都在注冊時連接到這三個全局鏈表上

  1. platform總線會匹配這兩個名字相同的device和driver,同時會觸發(fā)soc_probe( alc5623_probe())的調(diào)用虏缸,它正是整個ASoC驅(qū)動初始化的入口鲫懒。

  2. 在soc_probe函數(shù)中會完成以下任務(wù):
    調(diào)用標準的alsa函數(shù)創(chuàng)建聲卡實例 (定義 alc5623_card ,注冊 snd_soc_register_card))

  3. 挨個調(diào)用了codec, dai和platform驅(qū)動的probe函數(shù)

  4. 調(diào)用了soc_new_pcm()函數(shù)用于創(chuàng)建標準alsa驅(qū)動的pcm邏輯設(shè)備

  5. 最后則是調(diào)用標準alsa驅(qū)動的聲卡注冊函數(shù)對聲卡進行注冊

static struct snd_soc_dai_link alc5623_dai_link = {
    .name           = "ASOC-alc5623",
    .stream_name    = "alc5623 HiFi",
    .cpu_dai_name   = DEV_NAME_I2S,         /* nxp_snd_i2s_driver name */
    .platform_name  = DEV_NAME_PCM,         /* nxp_snd_pcm_driver name */
    .codec_dai_name = "alc5621-hifi",       /* alc5623_dai's name */
    .codec_name     = "alc562x-codec.0-001a",       /* alc5623_i2c_driver name + '.' + bus + '-' + address(7bit) */
    .ops            = &alc5623_ops,
    .symmetric_rates = 1,
    .init           = alc5623_dai_init,
    .ops            = &alc5623_ops,
};

static struct snd_soc_card alc5623_card = {
    .name           = "I2S-alc5623",        /* proc/asound/cards */
    .owner          = THIS_MODULE,
    .dai_link       = &alc5623_dai_link,
    .num_links      = 1,
    .suspend_pre    = &alc5623_suspend_pre,
    .resume_pre     = &alc5623_resume_pre,
    .resume_post    = &alc5623_resume_post,
};

ASoC架構(gòu)中的Codec 是一個i2c_driver

描述Codec的最主要的幾個數(shù)據(jù)結(jié)構(gòu)分別是:
snd_soc_codec_driver刽辙,snd_soc_dai_driver

確定snd_soc_codec_driver和snd_soc_dai-driver的實例窥岩,并把它們注冊到系統(tǒng)中,注冊后的codec和dai才能為Machine驅(qū)動所用

其中的snd_soc_dai和snd_soc_dai_driver在ASoC的Platform驅(qū)動中也會使用到宰缤, Platform和Codec的DAI通過snd_soc_dai_link結(jié)構(gòu)颂翼,在Machine驅(qū)動中進行綁定連接。

Codec驅(qū)動的步驟:
定義snd_soc_codec_driver和snd_soc_dai_driver的實例慨灭,然后調(diào)用snd_soc_register_codec函數(shù)對Codec進行注冊朦乏。

static struct snd_soc_dai_driver alc5632_dai = {
    .name = "alc5632-hifi",
    .playback = {
        .stream_name = "HiFi Playback",
        .channels_min = 1,
        .channels_max = 2,
        .rate_min = 8000,
        .rate_max = 48000,
        .rates = SNDRV_PCM_RATE_8000_48000,
        .formats = ALC5632_FORMATS,},
    .capture = {
        .stream_name = "HiFi Capture",
        .channels_min = 1,
        .channels_max = 2,
        .rate_min = 8000,
        .rate_max = 48000,
        .rates = SNDRV_PCM_RATE_8000_48000,
        .formats = ALC5632_FORMATS,},

    .ops = &alc5632_dai_ops,
    .symmetric_rates = 1,
};

static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
    .probe = alc5632_probe,
    .remove = alc5632_remove,
    .suspend = alc5632_suspend,
    .resume = alc5632_resume,
    .set_bias_level = alc5632_set_bias_level,
    .controls = alc5632_snd_controls,
    .num_controls = ARRAY_SIZE(alc5632_snd_controls),
    .dapm_widgets = alc5632_dapm_widgets,
    .num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets),
    .dapm_routes = alc5632_dapm_routes,
    .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
};


    ret = snd_soc_register_codec(&client->dev,
        &soc_codec_device_alc5632, &alc5632_dai, 1);

在snd_soc_register_codec函數(shù)中,
傳入?yún)?shù)snd_soc_codec_driver和snd_soc_dai_driver氧骤, 并創(chuàng)建snd_soc_codec和snd_soc_dai呻疹。
它申請了一個snd_soc_codec結(jié)構(gòu)的實例:確定codec的名字,這個名字很重要筹陵, Machine驅(qū)動定義的snd_soc_dai_link中會指定每個link的codec和dai的名字刽锤,進行匹配綁定時就是通過和這里的名字比較("alc5623-hifi"),從而找到該Codec的朦佩!然后初始化snd_soc_codec結(jié)構(gòu)的各個字段并思,多數(shù)字段的值來自上面定義的snd_soc_codec_driver的實例。
通過snd_soc_register_dais函數(shù)對本Codec的dai進行注冊
在snd_soc_register_dais函數(shù)中為每個snd_soc_dai實例分配內(nèi)存语稠,確定dai的名字宋彼,用snd_soc_dai_driver實例的字段對它進行必要初始化
最后,它把codec實例鏈接到全局鏈表codec_list中,把dai鏈接到全局鏈表dai_list中输涕,并且調(diào)snd_soc_instantiate_cards函數(shù)觸發(fā)Machine驅(qū)動進行一次匹配綁定操作

/* SoC Audio Codec device */  
struct snd_soc_codec {  
    const char *name;  /* Codec的名字*/  
    struct device *dev; /* 指向Codec設(shè)備的指針 */  
    const struct snd_soc_codec_driver *driver; /* 指向該codec的驅(qū)動的指針 */  
    struct snd_soc_card *card;    /* 指向Machine驅(qū)動的card實例 */  
    int num_dai; /* 該Codec數(shù)字接口的個數(shù)音婶,目前越來越多的Codec帶有多個I2S或者是PCM接口 */    
    /* runtime */  
    ......  
    /* codec IO */  
    void *control_data; /* 該指針指向的結(jié)構(gòu)用于對codec的控制,通常和read占贫,write字段聯(lián)合使用 */  
    enum snd_soc_control_type control_type;/* 可以是SND_SOC_SPI桃熄,SND_SOC_I2C,SND_SOC_REGMAP中的一種 */  
    unsigned int (*read)(struct snd_soc_codec *, unsigned int);  /* 讀取Codec寄存器的函數(shù) */  
    int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);  /* 寫入Codec寄存器的函數(shù) */  
    /* dapm */  
    struct snd_soc_dapm_context dapm;  /* 用于DAPM控件 */  
};  
/* codec driver */  
struct snd_soc_codec_driver {  
    /* driver ops */  
    int (*probe)(struct snd_soc_codec *);  /* codec驅(qū)動的probe函數(shù)型奥,由snd_soc_instantiate_card回調(diào) */  
    int (*remove)(struct snd_soc_codec *);    
    int (*suspend)(struct snd_soc_codec *);  /* 電源管理 */  
    int (*resume)(struct snd_soc_codec *);  /* 電源管理 */  
....
}

/*  
 * Digital Audio Interface runtime data.  
 *  
 * Holds runtime data for a DAI.  
 */  
struct snd_soc_dai {  
    const char *name;  /* dai的名字 */  
    struct device *dev;  /* 設(shè)備指針 */  
  
    /* driver ops */  
    struct snd_soc_dai_driver *driver;  /* 指向dai驅(qū)動結(jié)構(gòu)的指針 */  
  
    /* DAI runtime info */  
    unsigned int capture_active:1;      /* stream is in use */  
    unsigned int playback_active:1;     /* stream is in use */  
  
    /* DAI DMA data */  
    void *playback_dma_data;  /* 用于管理playback dma */  
    void *capture_dma_data;  /* 用于管理capture dma */  
  
    /* parent platform/codec */  
    union {  
        struct snd_soc_platform *platform;  /* 如果是cpu dai瞳收,指向所綁定的平臺 */  
        struct snd_soc_codec *codec;  /* 如果是codec dai指向所綁定的codec */  
    };  
    struct snd_soc_card *card;  /* 指向Machine驅(qū)動中的crad實例 */  
};  

/*  
 * Digital Audio Interface Driver.  
 *  
 * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97  
 * operations and capabilities. Codec and platform drivers will register this  
 * structure for every DAI they have.  
 *  
 * This structure covers the clocking, formating and ALSA operations for each  
 * interface.  
 */  
struct snd_soc_dai_driver {  
    /* DAI description */  
    const char *name;  /* dai驅(qū)動名字 */  
  
    /* DAI driver callbacks */  
    int (*probe)(struct snd_soc_dai *dai);  /* dai驅(qū)動的probe函數(shù),由snd_soc_instantiate_card回調(diào) */  
    int (*remove)(struct snd_soc_dai *dai);    
    int (*suspend)(struct snd_soc_dai *dai);  /* 電源管理 */  
    int (*resume)(struct snd_soc_dai *dai);    
  
    /* ops */  
    const struct snd_soc_dai_ops *ops;  /* 指向本dai的snd_soc_dai_ops結(jié)構(gòu) */  
  
    /* DAI capabilities */  
    struct snd_soc_pcm_stream capture;  /* 描述capture的能力 */  
    struct snd_soc_pcm_stream playback;  /* 描述playback的能力 */  
};  
soc-core.c
int snd_soc_register_codec(struct device *dev,
               const struct snd_soc_codec_driver *codec_drv,
               struct snd_soc_dai_driver *dai_drv,
               int num_dai)
{
    size_t reg_size;
    struct snd_soc_codec *codec;
    int ret, i;

    dev_dbg(dev, "codec register %s\n", dev_name(dev));

    codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
    if (codec == NULL)
        return -ENOMEM;

    /* create CODEC component name */
    codec->name = fmt_single_name(dev, &codec->id);
    if (codec->name == NULL) {
        kfree(codec);
        return -ENOMEM;
    }

    if (codec_drv->compress_type)
        codec->compress_type = codec_drv->compress_type;
    else
        codec->compress_type = SND_SOC_FLAT_COMPRESSION;

    codec->write = codec_drv->write;
    codec->read = codec_drv->read;
    codec->volatile_register = codec_drv->volatile_register;
    codec->readable_register = codec_drv->readable_register;
    codec->writable_register = codec_drv->writable_register;
    codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
    codec->dapm.bias_level = SND_SOC_BIAS_OFF;
    codec->dapm.dev = dev;
    codec->dapm.codec = codec;
    codec->dapm.seq_notifier = codec_drv->seq_notifier;
    codec->dapm.stream_event = codec_drv->stream_event;
    codec->dev = dev;
    codec->driver = codec_drv;
    codec->num_dai = num_dai;
    mutex_init(&codec->mutex);

    /* allocate CODEC register cache */
    if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
        reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
        codec->reg_size = reg_size;
        /* it is necessary to make a copy of the default register cache
         * because in the case of using a compression type that requires
         * the default register cache to be marked as __devinitconst the
         * kernel might have freed the array by the time we initialize
         * the cache.
         */
        if (codec_drv->reg_cache_default) {
            codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
                              reg_size, GFP_KERNEL);
            if (!codec->reg_def_copy) {
                ret = -ENOMEM;
                goto fail;
            }
        }
    }

    if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
        if (!codec->volatile_register)
            codec->volatile_register = snd_soc_default_volatile_register;
        if (!codec->readable_register)
            codec->readable_register = snd_soc_default_readable_register;
        if (!codec->writable_register)
            codec->writable_register = snd_soc_default_writable_register;
    }

    for (i = 0; i < num_dai; i++) {
        fixup_codec_formats(&dai_drv[i].playback);
        fixup_codec_formats(&dai_drv[i].capture);
    }

    /* register any DAIs */
    if (num_dai) {
        ret = snd_soc_register_dais(dev, dai_drv, num_dai);
        if (ret < 0)
            goto fail;
    }

    mutex_lock(&client_mutex);
    list_add(&codec->list, &codec_list);
    snd_soc_instantiate_cards();
    mutex_unlock(&client_mutex);

ASoC架構(gòu)中的Platform

Platform驅(qū)動的主要作用是完成音頻數(shù)據(jù)的管理厢汹,最終通過CPU的數(shù)字音頻接口( cpu_dai)把音頻數(shù)據(jù)傳送給Codec進行處理螟深,最終由Codec輸出驅(qū)動耳機或者是喇叭的音信信號。

在具體實現(xiàn)上烫葬, ASoC有把Platform驅(qū)動分為兩個部分: snd_soc_platform_driver和snd_soc_dai_driver界弧。其中, platform_driver負責管理音頻數(shù)據(jù)搭综,把音頻數(shù)據(jù)通過dma或其他操作傳送至cpu dai中垢箕, dai_driver則主要完成cpu一側(cè)的dai的參數(shù)配置,同時也會通過一定的途徑把必要的dma等參數(shù)與snd_soc_platform_driver進行交互兑巾。

snd_soc_platform_driver

platform驅(qū)動一般平臺相關(guān)(nxp-pcm.c)

driver:
ASoC把snd_soc_platform_driver注冊為一個系統(tǒng)的platform_driver
           snd_soc_register_platform()
device:
platform_device_register(&pcm_device);
dai_driver

主要完成cpu一側(cè)的dai的參數(shù)配置
cpu dai 驅(qū)動也定義為platform_device
dai驅(qū)動通常對應(yīng)cpu的一個或幾個I2S/PCM接口

driver:   
nxp-i2s.c platform_driver_register(&i2s_driver);

定義一個snd_soc_dai_driver結(jié)構(gòu)的實例条获;
在對應(yīng)的platform_driver中的probe回調(diào)中通過API:snd_soc_register_dai或者snd_soc_register_dais,注冊snd_soc_dai實例蒋歌;
實現(xiàn)snd_soc_dai_driver結(jié)構(gòu)中的probe帅掘、suspend等回調(diào);
實現(xiàn)snd_soc_dai_driver結(jié)構(gòu)中的snd_soc_dai_ops字段中的回調(diào)函數(shù)堂油;

device : S5p4418/Devices.c   platform_device i2s_device_ch0 ....
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末修档,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子府框,更是在濱河造成了極大的恐慌吱窝,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迫靖,死亡現(xiàn)場離奇詭異癣诱,居然都是意外死亡,警方通過查閱死者的電腦和手機袜香,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲫惶,“玉大人蜈首,你說我怎么就攤上這事。” “怎么了欢策?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵吆寨,是天一觀的道長。 經(jīng)常有香客問我踩寇,道長啄清,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任俺孙,我火速辦了婚禮辣卒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睛榄。我一直安慰自己荣茫,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布场靴。 她就那樣靜靜地躺著啡莉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旨剥。 梳的紋絲不亂的頭發(fā)上咧欣,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音轨帜,去河邊找鬼魄咕。 笑死,一個胖子當著我的面吹牛阵谚,可吹牛的內(nèi)容都是我干的蚕礼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼梢什,長吁一口氣:“原來是場噩夢啊……” “哼奠蹬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗡午,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤囤躁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荔睹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狸演,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年僻他,在試婚紗的時候發(fā)現(xiàn)自己被綠了宵距。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡吨拗,死狀恐怖满哪,靈堂內(nèi)的尸體忽然破棺而出婿斥,到底是詐尸還是另有隱情,我是刑警寧澤哨鸭,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布民宿,位于F島的核電站,受9級特大地震影響像鸡,放射性物質(zhì)發(fā)生泄漏活鹰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一只估、第九天 我趴在偏房一處隱蔽的房頂上張望志群。 院中可真熱鬧,春花似錦仅乓、人聲如沸赖舟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宾抓。三九已至,卻和暖如春豫喧,著一層夾襖步出監(jiān)牢的瞬間石洗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工紧显, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讲衫,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓孵班,卻偏偏與公主長得像涉兽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子篙程,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一.聲音參數(shù)基本概念: 聲音是連續(xù)模擬量枷畏,計算機將它離散化之后用數(shù)字表示,就有了以下幾個名詞術(shù)語虱饿。 樣本長度(sa...
    cs1001閱讀 2,735評論 0 2
  • 前言 今天跟王總聊天拥诡,他狠狠地(形容詞)叼了我,他說你為什么不寫一些比較牛逼的文章氮发,為什么總是寫一些教別人如何安裝...
    da4ac7fb9bd5閱讀 4,953評論 0 49
  • 一.聲音參數(shù)基本概念: 聲音是連續(xù)模擬量渴肉,計算機將它離散化之后用數(shù)字表示,就有了以下幾個名詞術(shù)語爽冕。 樣本長度(sa...
    cs1001閱讀 5,402評論 0 3
  • 程序總體結(jié)構(gòu) 以sound/soc/pxa/corgi.c為例來分析 為了描述聲卡仇祭,定義snd_soc_card實...
    鄭俊飛閱讀 3,066評論 0 1
  • 有的人生來就有溫暖的保護殼,他做了什么覺得困難的事颈畸,不想干了乌奇,又可以縮回殼里嚣艇,如果他什么都不想做,依然可以安穩(wěn)的過...
    RY麥布閱讀 134評論 0 0