SLIDESHOW@klopix

Slideshow app generates Image+Sound playlist schedule to compose a slideshow.

Features
→ Block structure (block is a combination of picture set and sound set)
→ Folder or list file enumeration
→ Per block/ per image/ mixed kinds of block duration types
→ [Option] Sound block for entire slideshow (means that block sound won't be taken, instead a global sound block is gonna be used for all the blocks in the slideshow)
→ Images: *.bmp, *.dib, *.png, *.tga, *.jpg
→ Sounds: *.wav
→ Fullscreen preview

Resources I've used
→ MS DDxSoundServer (COM)
→ WaveFile Parser (COM)
→ StretchImage/ ConvertImage object (COM)
→ Lite XML lib
→ MS MFC

Links
Changelog
Wave Parser

 
 

Dec 10 2009
Seeking

It is all pretty clear from the image:
(1) I find file,
(2) chunk, and
(3) position in chunk
from which I should start taking samples.


Relevant variables here:
(1) samples per second,
(2) sample size in bytes,
(3) chunk size and offset from beginning of file in bytes.

Dec 4 2009
Silent blocks II

To stop playing means not to provide a timestamp for the silent wave. So, all in all I gotta do is, I MUST explicitly understand about every new timestamp whether it is SILENT or REGULAR.

REGULAR means that a wave underlying it, is playable. SILENT means that the wave is either unsupported or there is no wave at all.

CPlayWav::feed_samples(): m_WaveList.CopySamples(..., idx_wave);
if (idx_wave != m_idx_timestamp)
{
   get timestamp t;
   if (t.type == SILENT) don't add, but shift current m_total_duration;
   else add(t);
}

And I don't have to stop feeding samples if new timestamp is silent. FIFO recognizes that gap between two waves and keep fed samples until it meets new regular timestamp. So, algo after all is changed slightly. Hooray! :)

Dec 3 2009
Silent blocks

Entire slideshow is built up of many blocks. And some of 'em may have an option to be SILENT. It means during such a block there is no sound playback. Now how do I implement that option in FIFO?

Remember we have (1) timestamps and (2) samples to provide for FIFO to work. CPlayWav uses CWaveList currently as continuous source of samples via CopySamples() which returns also sometimes a timestamp to add to FIFO. Now let's assume CWaveList reached "silent block" which means that current file has path equal to "" and its duration is positive (for example 102.5 seconds). How do CPlayWav and CWaveList communicate over this?

(1) I have to stop feeding samples for a while. (2) I shouldn't add a timestamp for silent period. (3) What's the interface gonna look like?

Dec 2 2009
Fixed restart

There was a ghost bug on restaring wave-playback with new wave list. I couldn't find an exact condition and cause. But it's FIFO.

FIFO can accept first timestamp only once. If I set first timestamp (the one which time is 0.0) many times then behaviour is unpredictable (in pretty much all the cases every subsequent first timestamp goes after previous first timestamp, so there are MANY timestamps one after another instead of one and only). And what I did is I made sure, that (1) first timestamp is added only once and (2) FIFO is filled up only after play button is pressed (otherwise I would stock it up with irrelevant samples from old wave list and there would be no room for new desired ones).

So, FIFO: only one first stamp and samples only after play button pushing.

Nov 23 2009
Wave file playback (via DDSSoundServer)

Objective is to play a sequence of wave files without making a stop or any interruption.

Resources:
WaveParser: returns positions&sizes of wave sample chunks.
DDSSoundFIFO:
    · running/stopped state queue,
    · has two most important API functions: AddData(raw_samples_data, size), AddTimestamp(TimeStampParam_t& p). Second one is to setup a moment in FIFO when new formatted (basically sample size) samples are to be played. First one is to actually add those samples. Now, I MUST add samples BEFORE they are to be played in FIFO. That's why FIFO has depth.


Solution

CReadWav is to incapsulate (hide) chunk structure of wave file, so that I can easily get samples out: int CopySamples(int max, void* pBuf). It returns amount of samples copied into buffer pBuf.

It contains two buffers: active (A) and passive (P). While I give out samples from A, I fillup samples into P. When there is no more samples left in A, I swap these buffers and repeat it all over again. Important step to do is to fillup A on start.

CWaveList is to provide samples of the whole wave file sequence. Now, a tricky piece of work here is adding timestamps: every time a new wave file samples is about to be added into FIFO, I gotta put new timestamp into FIFO (with sample size, duration, etc). So, the int CopySamples(int max, void* pBuf, BOOL& new_timestamp) function should setup a flag that says a new timestamp has to be added.

So, usage of CWaveList looks like this:
while (!m_WaveList.NoMoreSamples())
{
    m_pFifo->get_FreeTime(free_time);
    int copied = m_WaveList.CopySamples(free_time * m_WaveList.SamplesPerSec(), pBuf, new_timestamp);
    if (new_timestamp)
    {
        TimestampParam_t t;
        m_WaveList->Timestamp(t);
        m_pFifo->AddTimestamp(t);
    }
    m_pFifo->AddData(pBuf, copied * m_WaveList.SampleSize());
}


Debug trace

(where [X] means that buffer number X is active and has yy.y percent data samples. As time goes on, percentage goes down to zero and eventually I swap buffers and get data from filled up one, while filling empty buffer).

Ivan Yurlagin,