Rumah pangkalan data tutorial mysql SoundTouch音频处理库源码分析及算法提取(2)

SoundTouch音频处理库源码分析及算法提取(2)

Jun 07, 2016 pm 03:31 PM
s menganalisis berurusan dengan ekstrak Kod sumber algoritma Audio

SoundTouch音频处理库初始化流程剖析 定义一个变量SoundTouch m_SoundTouch; SoundTouch的派生关系 FIFOSamplePipe-FIFOProcessor-SoundTouch (流程[1]) 因此首先构造基类FIFOSamplePipe,接着派生出FIFOProcessor,然后才以FIFOProcessor派生出SoundTouch。

SoundTouch音频处理库初始化流程剖析

定义一个变量SoundTouch m_SoundTouch;

 

SoundTouch的派生关系

FIFOSamplePipe->FIFOProcessor->SoundTouch (流程[1])

因此首先构造基类FIFOSamplePipe,接着派生出FIFOProcessor,然后才以FIFOProcessor派生出SoundTouch。这里不得不提一下老外的C++水平真的很高,在这里基本上把类的继承发挥到了极致。能够分析这样的代码简直就是一种享受。先看一下基类FIFOSamplePipe,如下定义:

class FIFOSamplePipe

{

public:

    // virtual default destructor

    virtual ~FIFOSamplePipe() {}

 

    /// Returns a pointer to the beginning of the output samples.

    /// This function is provided for accessing the output samples directly.

    /// Please be careful for not to corrupt the book-keeping!

    ///

    /// When using this function to output samples, also remember to 'remove' the

    /// output samples from the buffer by calling the

    /// 'receiveSamples(numSamples)' function

    virtual SAMPLETYPE *ptrBegin() = 0;

 

    /// Adds 'numSamples' pcs of samples from the 'samples' memory position to

    /// the sample buffer.

    virtual void putSamples(const SAMPLETYPE *samples,  ///

                            uint numSamples             ///

                            ) = 0;

 

 

    // Moves samples from the 'other' pipe instance to this instance.

    void moveSamples(FIFOSamplePipe &other  ///

         )

    {

        int oNumSamples = other.numSamples();

 

        putSamples(other.ptrBegin(), oNumSamples);

        other.receiveSamples(oNumSamples);

    };

 

    /// Output samples from beginning of the sample buffer. Copies requested samples to

    /// output buffer and removes them from the sample buffer. If there are less than

    /// 'numsample' samples in the buffer, returns all that available.

    ///

    /// /return Number of samples returned.

    virtual uint receiveSamples(SAMPLETYPE *output, ///

                                uint maxSamples                 ///

                                ) = 0;

 

    /// Adjusts book-keeping so that given number of samples are removed from beginning of the

    /// sample buffer without copying them anywhere.

    ///

    /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly

    /// with 'ptrBegin' function.

    virtual uint receiveSamples(uint maxSamples   ///

 

pipe.

                                ) = 0;

 

    /// Returns number of samples currently available.

    virtual uint numSamples() const = 0;

 

    // Returns nonzero if there aren't any samples available for outputting.

    virtual int isEmpty() const = 0;

 

    /// Clears all the samples.

    virtual void clear() = 0;

}

 

这里没有实现FIFOSamplePipe类的构造函数,因此系统隐性的调用了默认的自动生成的FIFOSamplePipe()。当然他应该没有做任何的初始化,同样也不需要做任何的初始化。通过定义virtual ~FIFOSamplePipe() {}虚析构函数,使得new一个子类,例如:FIFOSamplePipe* a = new FIFOProcessor,当a销毁的时候都会执行子类FIFOProcessor的析构函数,保证不管多少层继承都会一次过全部销毁,这是作为一个基类的特点。类的继承和多态果然是C++最为强悍的一部分,有助于编写重复性很高的类。通过看这个基类的声明,我们可以留意到除了定义大多数虚函数之外,他唯独实现了moveSamples这个函数,也就是子类如果没有override moveSamples,都将调用这个方法。他做的处理也相对来说很简单,根据注释,我们不难理解,正是这个函数实现了各个派生类之间的数据共享传递的接口。

// Moves samples from the 'other' pipe instance to this instance.

moveSamples(FIFOSamplePipe &other  ///

)

{

        int oNumSamples = other.numSamples();

 

        putSamples(other.ptrBegin(), oNumSamples);

        other.receiveSamples(oNumSamples);

};

在创建SoundTouch类之前,经过(流程[1])的前面两个步骤,他们都隐形的调用了默认的析构函数,由于基类FIFOSamplePipe没有实现构造函数,我们可以默认他不做任何的初始化,然后FIFOProcessor简单的把成员变量FIFOSamplePipe *output;一个指向基类的指针赋值简单做了一下初始化,让他指向NULL。

FIFOProcessor()

{

output = NULL;

}

现在回到SoundTouch的构造函数,在构造完前面两个类之后,他终于可以调用自己的默认构造函数

SoundTouch::SoundTouch()

{

    // Initialize rate transposer and tempo changer instances

    pRateTransposer = RateTransposer::newInstance();

    pTDStretch = TDStretch::newInstance();

    setOutPipe(pTDStretch);

    rate = tempo = 0;

    virtualPitch =

    virtualRate =

    virtualTempo = 1.0;

    calcEffectiveRateAndTempo();

    channels = 0;

    bSrateSet = FALSE;

}

看一下SoundTouch类的成员变量

class SoundTouch : public FIFOProcessor

{

private:

    /// Rate transposer class instance

    class RateTransposer *pRateTransposer;

 

    /// Time-stretch class instance

    class TDStretch *pTDStretch;

 

    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.

    float virtualRate;

 

    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.

    float virtualTempo;

 

    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.

    float virtualPitch;

 

    /// Flag: Has sample rate been set?

    BOOL  bSrateSet;

 

    /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and

    /// 'virtualPitch' parameters.

    void calcEffectiveRateAndTempo();

 

protected :

    /// Number of channels

    uint  channels;

 

    /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'

    float rate;

 

    /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'

    float tempo;

...

根据构造函数他实例化pRateTransposer,pTDStretch这两个类。

首先看一下RateTransposer类的成员函数newInstance,通过一个宏定义INTEGER_SAMPLES来new一个定点还是浮点处理的类,马上就可以判断不管RateTransposerInteger还是RateTransposerFloat都应该直接从RateTransposer派生。(假设INTEGER_SAMPLES被定义)他将构造一个RateTransposerInteger。

RateTransposer *RateTransposer::newInstance()

{

#ifdef INTEGER_SAMPLES

    return ::new RateTransposerInteger;

#else

    return ::new RateTransposerFloat;

#endif

}

看一下RateTransposerInteger类的定义,不出所料果然由RateTransposer派生

class RateTransposer : public FIFOProcessor

{

protected:

...

    FIFOSampleBuffer storeBuffer;

 

    /// Buffer for keeping samples between transposing & anti-alias filter

    FIFOSampleBuffer tempBuffer;

 

    /// Output sample buffer

    FIFOSampleBuffer outputBuffer;

...

上诉两个类他们和基类之间存在这样的关系:

FIFOSamplePipe->FIFOProcessor->RateTransposer->RateTransposerInteger

这里的构造过程不同的是:RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)

RateTransposer构造函数指明了父类FIFOProcessor的构造形式FIFOProcessor(&outputBuffer)

FIFOProcessor(FIFOSamplePipe *pOutput   ///

)

{

output = pOutput;

}

RateTransposer把类成员变量outputBuffer作为传递函数参数,这里可能大家就会很奇怪,代码里面根本还没有实例化RateTransposer类,他怎么可能存在一个FIFOSampleBuffer outputBuffer;其实正是体现了c++的多态性,这里传入的实际上是一个__vfptr数组,这个数组就是指向实例化各个派生类的这个变量的指针数组。这下子明白了。__vfptr[0]不一定有值,但是__vfptr肯定是一个存在的值。构造完FIFOProcessor,此时要构造RateTransposer,他有三个FIFOSampleBuffer类定义。

...

class FIFOSampleBuffer : public FIFOSamplePipe

...

与基类的继承关系

FIFOSamplePipe->FIFOSampleBuffer

/// Constructor

FIFOSampleBuffer(int numChannels = 2     ///

                                              ///

);

他没有定义不带参的构造函数,因此这个带参数的构造函数将以默认的方式给调用

FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)

{

    assert(numChannels > 0);

    sizeInBytes = 0; // reasonable initial value

    buffer = NULL;

    bufferUnaligned = NULL;

    samplesInBuffer = 0;

    bufferPos = 0;

    channels = (uint)numChannels;

    ensureCapacity(32);     // allocate initial capacity

}

FIFOSampleBuffer的构造函数将被调用三次。

现在终于可以执行RateTransposer的构造函数

// Constructor

RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)

{

    numChannels = 2;

    bUseAAFilter = TRUE;

    fRate = 0;

 

    // Instantiates the anti-alias filter with default tap length

    // of 32

    pAAFilter = new AAFilter(32);

}

首先看一下AAFilter的相关定义

class AAFilter

{

protected:

    class FIRFilter *pFIR;

    /// Low-pass filter cut-off frequency, negative = invalid

    double cutoffFreq;

    /// num of filter taps

    uint length;

    /// Calculate the FIR coefficients realizing the given cutoff-frequency

    void calculateCoeffs();

public:

    AAFilter(uint length);

    ~AAFilter();

    /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling

    /// frequency (nyquist frequency = 0.5). The filter will cut off the

    /// frequencies than that.

    void setCutoffFreq(double newCutoffFreq);

    /// Sets number of FIR filter taps, i.e. ~filter complexity

    void setLength(uint newLength);

    uint getLength() const;

    /// Applies the filter to the given sequence of samples.

    /// Note : The amount of outputted samples is by value of 'filter length'

    /// smaller than the amount of input samples.

    uint evaluate(SAMPLETYPE *dest,

                  const SAMPLETYPE *src,

                  uint numSamples,

                  uint numChannels) const;

};

在其构造函数中初始化了一个指向class FIRFilter的指针

AAFilter::AAFilter(uint len)

{

    pFIR = FIRFilter::newInstance();

    cutoffFreq = 0.5;

    setLength(len);

}

首先我们看看FIRFilter类成员函数newInstance(),嘿嘿,在这里我们发现了一个非常有用的函数detectCPUextensions();通过这个函数我们可以判断cpu到底支持什么类型的多媒体指令集。根据注释我们也可以很快理解。detectCPUextensions收藏了。他的实现就在Cpu_detect_x86_win.cpp的实现中。美中不足的是,他只能检测x86结构体系的CPU。可能我多想了。根据本人电脑的配置(采用的赛扬cpu),所以只支持mmx指令。

FIRFilter * FIRFilter::newInstance()

{

    uint uExtensions;

    uExtensions = detectCPUextensions();

    // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU

#ifdef ALLOW_MMX

    // MMX routines available only with integer sample types

    if (uExtensions & SUPPORT_MMX)

    {

        return ::new FIRFilterMMX;

    }

    else

#endif // ALLOW_MMX

#ifdef ALLOW_SSE

    if (uExtensions & SUPPORT_SSE)

    {

        // SSE support

        return ::new FIRFilterSSE;

    }

    else

#endif // ALLOW_SSE

#ifdef ALLOW_3DNOW

    if (uExtensions & SUPPORT_3DNOW)

    {

        // 3DNow! support

        return ::new FIRFilter3DNow;

    }

    else

#endif // ALLOW_3DNOW

    {

        // ISA optimizations not supported, use plain C version

        return ::new FIRFilter;

    }

}

为此他将通过这个判断构造返回一个FIRFilterMMX类

if (uExtensions & SUPPORT_MMX)

    {

        return ::new FIRFilterMMX;

    }

查看FIRFilterMMX的类定义class FIRFilterMMX : public FIRFilter,他从FIRFilter派生。成员函数uint FIRFilterMMX::evaluateFilterStereo引起了我的高度注意,主要的算法采用MMX指令集来完成某些声音计算。这个就是我们需要的Rate的核心算法。不同指令集的实现,可以参考FIRFilter3DNow,FIRFilterSSE,默认是FIRFilter的evaluateFilterStereo函数的实现。

// mmx-optimized version of the filter routine for stereo sound

uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const

{

    // Create stack copies of the needed member variables for asm routines :

    uint i, j;

    __m64 *pVdest = (__m64*)dest;

 

    if (length

 

    for (i = 0; i

    {

        __m64 accu1;

        __m64 accu2;

        const __m64 *pVsrc = (const __m64*)src;

        const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;

 

        accu1 = accu2 = _mm_setzero_si64();

        for (j = 0; j

        {

            __m64 temp1, temp2;

 

            temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]);  // = l2 l0 r2 r0

            temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]);  // = l3 l1 r3 r1

 

            accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0]));  // += l2*f2+l0*f0

 

r2*f2+r0*f0

            accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1]));  // += l3*f3+l1*f1

 

r3*f3+r1*f1

 

            temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]);  // = l4 l2 r4 r2

 

            accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0]));  // += l3*f2+l1*f0

 

r3*f2+r1*f0

            accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1]));  // += l4*f3+l2*f1

 

r4*f3+r2*f1

 

            // accu1 += l2*f2+l0*f0 r2*f2+r0*f0

            //       += l3*f3+l1*f1 r3*f3+r1*f1

 

            // accu2 += l3*f2+l1*f0 r3*f2+r1*f0

            //          l4*f3+l2*f1 r4*f3+r2*f1

 

            pVfilter += 2;

            pVsrc += 2;

        }

        // accu >>= resultDivFactor

        accu1 = _mm_srai_pi32(accu1, resultDivFactor);

        accu2 = _mm_srai_pi32(accu2, resultDivFactor);

 

        // pack 2*2*32bits => 4*16 bits

        pVdest[0] = _mm_packs_pi32(accu1, accu2);

        src += 4;

        pVdest ++;

    }

 

   _m_empty();  // clear emms state

 

    return (numSamples & 0xfffffffe) - length;

}

因此,如果把SoundTouch移植到arm等没有多媒体指令集的CPU时,应使用FIRFilter的evaluateFilterStere函数。执行完这里,终于可以真正意义上构造我们的RateTransposerInteger()。在构造函数中:

RateTransposerInteger::RateTransposerInteger() : RateTransposer()

{

    // Notice: use local function calling syntax for sake of clarity,

    // to indicate the fact that C++ constructor can't call virtual functions.

    RateTransposerInteger::resetRegisters();

    RateTransposerInteger::setRate(1.0f);

}进行了一些必要的初始化。至此pRateTransposer = RateTransposer::newInstance();实例化完毕。至于pTDStretch = TDStretch::newInstance();下回分晓。

 

 

http://blog.csdn.net/suhetao/archive/2010/08/28/5845667.aspx

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Proses operasi hos perkhidmatan WIN10 yang menduduki terlalu banyak CPU Proses operasi hos perkhidmatan WIN10 yang menduduki terlalu banyak CPU Mar 27, 2024 pm 02:41 PM

1. Mula-mula, kita klik kanan ruang kosong bar tugas dan pilih pilihan [Task Manager], atau klik kanan logo mula, dan kemudian pilih pilihan [Task Manager]. 2. Dalam antara muka Pengurus Tugas yang dibuka, kami klik tab [Perkhidmatan] di hujung kanan. 3. Dalam tab [Perkhidmatan] yang dibuka, klik pilihan [Buka Perkhidmatan] di bawah. 4. Dalam tetingkap [Services] yang terbuka, klik kanan perkhidmatan [InternetConnectionSharing(ICS)], dan kemudian pilih pilihan [Properties]. 5. Dalam tetingkap sifat yang terbuka, tukar [Buka dengan] kepada [Disabled], klik [Apply] dan kemudian klik [OK]. 6. Klik logo mula, kemudian klik butang tutup, pilih [Mulakan Semula], dan selesaikan mula semula komputer.

CLIP-BEVFormer: Selia secara eksplisit struktur BEVFormer untuk meningkatkan prestasi pengesanan ekor panjang CLIP-BEVFormer: Selia secara eksplisit struktur BEVFormer untuk meningkatkan prestasi pengesanan ekor panjang Mar 26, 2024 pm 12:41 PM

Ditulis di atas & pemahaman peribadi penulis: Pada masa ini, dalam keseluruhan sistem pemanduan autonomi, modul persepsi memainkan peranan penting Hanya selepas kenderaan pemanduan autonomi yang memandu di jalan raya memperoleh keputusan persepsi yang tepat melalui modul persepsi boleh Peraturan hiliran dan. modul kawalan dalam sistem pemanduan autonomi membuat pertimbangan dan keputusan tingkah laku yang tepat pada masanya dan betul. Pada masa ini, kereta dengan fungsi pemanduan autonomi biasanya dilengkapi dengan pelbagai penderia maklumat data termasuk penderia kamera pandangan sekeliling, penderia lidar dan penderia radar gelombang milimeter untuk mengumpul maklumat dalam modaliti yang berbeza untuk mencapai tugas persepsi yang tepat. Algoritma persepsi BEV berdasarkan penglihatan tulen digemari oleh industri kerana kos perkakasannya yang rendah dan penggunaan mudah, dan hasil keluarannya boleh digunakan dengan mudah untuk pelbagai tugas hiliran.

Melaksanakan Algoritma Pembelajaran Mesin dalam C++: Cabaran dan Penyelesaian Biasa Melaksanakan Algoritma Pembelajaran Mesin dalam C++: Cabaran dan Penyelesaian Biasa Jun 03, 2024 pm 01:25 PM

Cabaran biasa yang dihadapi oleh algoritma pembelajaran mesin dalam C++ termasuk pengurusan memori, multi-threading, pengoptimuman prestasi dan kebolehselenggaraan. Penyelesaian termasuk menggunakan penunjuk pintar, perpustakaan benang moden, arahan SIMD dan perpustakaan pihak ketiga, serta mengikuti garis panduan gaya pengekodan dan menggunakan alat automasi. Kes praktikal menunjukkan cara menggunakan perpustakaan Eigen untuk melaksanakan algoritma regresi linear, mengurus memori dengan berkesan dan menggunakan operasi matriks berprestasi tinggi.

Terokai prinsip asas dan pemilihan algoritma bagi fungsi isihan C++ Terokai prinsip asas dan pemilihan algoritma bagi fungsi isihan C++ Apr 02, 2024 pm 05:36 PM

Lapisan bawah fungsi C++ sort menggunakan isihan gabungan, kerumitannya ialah O(nlogn), dan menyediakan pilihan algoritma pengisihan yang berbeza, termasuk isihan pantas, isihan timbunan dan isihan stabil.

Bolehkah kecerdasan buatan meramalkan jenayah? Terokai keupayaan CrimeGPT Bolehkah kecerdasan buatan meramalkan jenayah? Terokai keupayaan CrimeGPT Mar 22, 2024 pm 10:10 PM

Konvergensi kecerdasan buatan (AI) dan penguatkuasaan undang-undang membuka kemungkinan baharu untuk pencegahan dan pengesanan jenayah. Keupayaan ramalan kecerdasan buatan digunakan secara meluas dalam sistem seperti CrimeGPT (Teknologi Ramalan Jenayah) untuk meramal aktiviti jenayah. Artikel ini meneroka potensi kecerdasan buatan dalam ramalan jenayah, aplikasi semasanya, cabaran yang dihadapinya dan kemungkinan implikasi etika teknologi tersebut. Kecerdasan Buatan dan Ramalan Jenayah: Asas CrimeGPT menggunakan algoritma pembelajaran mesin untuk menganalisis set data yang besar, mengenal pasti corak yang boleh meramalkan di mana dan bila jenayah mungkin berlaku. Set data ini termasuk statistik jenayah sejarah, maklumat demografi, penunjuk ekonomi, corak cuaca dan banyak lagi. Dengan mengenal pasti trend yang mungkin terlepas oleh penganalisis manusia, kecerdasan buatan boleh memperkasakan agensi penguatkuasaan undang-undang

Ketahui cara mengendalikan aksara khas dan menukar petikan tunggal dalam PHP Ketahui cara mengendalikan aksara khas dan menukar petikan tunggal dalam PHP Mar 27, 2024 pm 12:39 PM

Dalam proses pembangunan PHP, berurusan dengan aksara khas adalah masalah biasa, terutamanya dalam pemprosesan rentetan, aksara khas sering terlepas. Antaranya, menukar aksara khas kepada petikan tunggal adalah keperluan yang agak biasa, kerana dalam PHP, petikan tunggal adalah cara biasa untuk membungkus rentetan. Dalam artikel ini, kami akan menerangkan cara mengendalikan petikan tunggal penukaran aksara khas dalam PHP dan memberikan contoh kod khusus. Dalam PHP, aksara khas termasuk tetapi tidak terhad kepada petikan tunggal ('), petikan berganda ("), segaris ke belakang (), dsb. Dalam rentetan

Algoritma pengesanan yang dipertingkatkan: untuk pengesanan sasaran dalam imej penderiaan jauh optik resolusi tinggi Algoritma pengesanan yang dipertingkatkan: untuk pengesanan sasaran dalam imej penderiaan jauh optik resolusi tinggi Jun 06, 2024 pm 12:33 PM

01Garis prospek Pada masa ini, sukar untuk mencapai keseimbangan yang sesuai antara kecekapan pengesanan dan hasil pengesanan. Kami telah membangunkan algoritma YOLOv5 yang dipertingkatkan untuk pengesanan sasaran dalam imej penderiaan jauh optik resolusi tinggi, menggunakan piramid ciri berbilang lapisan, strategi kepala pengesanan berbilang dan modul perhatian hibrid untuk meningkatkan kesan rangkaian pengesanan sasaran dalam imej penderiaan jauh optik. Menurut set data SIMD, peta algoritma baharu adalah 2.2% lebih baik daripada YOLOv5 dan 8.48% lebih baik daripada YOLOX, mencapai keseimbangan yang lebih baik antara hasil pengesanan dan kelajuan. 02 Latar Belakang & Motivasi Dengan perkembangan pesat teknologi penderiaan jauh, imej penderiaan jauh optik resolusi tinggi telah digunakan untuk menggambarkan banyak objek di permukaan bumi, termasuk pesawat, kereta, bangunan, dll. Pengesanan objek dalam tafsiran imej penderiaan jauh

Cara menyediakan PPT untuk memainkan berbilang audio secara automatik Cara menyediakan PPT untuk memainkan berbilang audio secara automatik Mar 26, 2024 pm 06:21 PM

1. Buka PPT, klik [Sisipkan] pada bar menu, dan kemudian klik [Audio]. 2. Dalam kotak pemilihan fail yang terbuka, pilih fail audio pertama yang ingin anda masukkan. 3. Selepas pemasukan berjaya, ikon pembesar suara akan dipaparkan dalam PPT untuk mewakili fail yang baru dimasukkan Anda boleh memainkan dan mendengarnya serta melaraskan kelantangan untuk mengawal kelantangannya semasa proses penyaringan PPT. 4. Ikuti kaedah yang sama dan masukkan fail audio kedua Pada masa ini, dua ikon pembesar suara akan dipaparkan dalam PPT, masing-masing mewakili dua fail audio. 5. Klik untuk memilih ikon fail audio pertama, dan kemudian klik menu [Main]. 6. Dalam Mula dalam bar alat, pilih [Main Merentas Slaid] untuk menetapkan audio ini untuk dimainkan dalam setiap slaid tanpa campur tangan manusia. 7. Ikuti langkah dalam langkah 6

See all articles