trouble with switching the stack frame - gcc

Why does the following code crash under Windows 10? It gets stuck in yield() in the setjmp() call. What rules did I violate? I think I never return from functions where setjmp() is called. The code works perfectly under linux/amd64.
class coroutine
{
jmp_buf env_in_;
jmp_buf env_out_;
::std::function<void()> f_;
bool running_;
bool terminated_;
::std::unique_ptr<char[]> stack_;
char* const stack_top_;
public:
explicit coroutine(::std::size_t const N = 128 * 1024) :
running_{false},
terminated_{true},
stack_(new char[N]),
stack_top_(stack_.get() + N)
{
}
template <typename F>
explicit coroutine(::std::size_t const N, F&& f) :
coroutine(N)
{
assign(::std::forward<F>(f));
}
auto terminated() const noexcept
{
return terminated_;
}
template <typename F>
void assign(F&& f)
{
running_ = terminated_ = false;
f_ = [this, f = ::std::forward<F>(f)]() mutable
{
// stack switch
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
asm volatile(
"movq %%rsp, %0"
:
: "rm" (stack_top_)
: "rsp"
);
#elif defined(i386) || defined(__i386) || defined(__i386__)
asm volatile(
"movl %%esp, %0"
:
: "rm" (stack_top_)
: "esp"
);
#else
#error "can't switch stack frame"
#endif
f(*this);
running_ = false;
terminated_ = true;
yield();
};
}
void yield() noexcept
{
if (setjmp(env_out_))
{
return;
}
else
{
longjmp(env_in_, 1);
}
}
void resume() noexcept
{
if (setjmp(env_in_))
{
return;
}
else if (running_)
{
longjmp(env_out_, 1);
}
else
{
running_ = true;
f_();
}
}
};
Here is the test program:
#include <iostream>
#include "coroutine.hpp"
struct A
{
~A()
{
::std::cout << "destroyed" << ::std::endl;
}
};
int main()
{
coroutine c(1024 * 1024);
c.assign([](coroutine& c)
{
A a;
for (int i{}; i != 3; ++i)
{
::std::cout << i << ::std::endl;
c.yield();
}
}
);
while (!c.terminated())
{
c.resume();
}
return 0;
}

Related

Can I send a stream from blob data in a database to PlaySound (MMSystem) rather than supplying a file name?

I need to be able to supply a stand alone system for a medical application that will be distributed free of charge to home users of blood pressure monitors, it is being designed to run off a memory stick and taken to doctors, pharmacists, hospitals, I would like to have a database file of spoken instructions for data entry fields for those who are not computer savvy.
The system is being developed to capture a large amount of observed symptomatic data from the user in the home which can then be taken to a doctor to open in the system and see the observation data as taken at the time for actual review and diagnosis, it is intended for those who are interested in helping themselves by letting their doctors or any other health practitioner understand by knowing what the patient experienced during the pain, feelings and other important information a doctor may rely on that they have identified.
At the moment I have
String file = frmMDI->dlg->InitialDir + "\\sounds\\" + "ObservationDateTimeField.wav";
speech->Send(file);
What this does is speak out the instruction for what is expected in the field when it has received the focus, it works fine as it is but would like to get the wav from the database so there is minimal files being distributed via usb.
in the OnEnter method, speech is a custom control that manages my needs, simply the PlaySound(...) requirement for .wav files, other controls work out how and when to send instruction.
Edit: a
add screen shot of observations window
Screen capture of main observation entry
I would like to have this as open source but I have no idea how to get it there, it is a development of ideas spanning 20 years, my code may be left wanting but it all works and has done so for a long time.
How do I go about it, if it can be done?
I have not had time to try too many things like sending a stream instead of a file, playsound works fine from a .wav sound file
Edit: Thanks to Spektre for time and code, very much appreciated.
PlaySound() cannot play audio from a stream. It can play from a file, a block of memory, or an EXE/DLL resource.
I would not recommend storing your WAV audio in database blobs. Use files or resources instead. But, if you must use a database, you can use the TDataSet::CreateBlobStream() method to get a read-only TStream to access the blob data, and then you can Read() that data into an allocated memory buffer, or CopyFrom() it into a TMemoryStream, and then you can have PlaySound() play from the memory of that buffer/stream.
If you really need to play streaming audio, you will have to use waveOutOpen()/waveOutPrepareHeader()/waveOutWrite() directly, or use more modern APIs like DirectSound or XAudio2 instead.
from my experience WAVEIN/WAVEOUT is the best sound api on win for this purpose... DirectSound is(was) buggy and very big latency so I stopped using it for good years ago...
Here my ancient C++ lib I originally wrote for my oscilloscope,spectral analyzator,signal generator apps but using it everywhere even in my ZXSpectrum emulator:
waveout.h:
//---------------------------------------------------------------------------
//--- WAVE IN/OUT class ver: 4.02 -------------------------------------------
//---------------------------------------------------------------------------
#ifndef _waveout_h
#define _waveout_h
//---------------------------------------------------------------------------
#include <mmsystem.h>
#include "fifo.h"
#include "lock.h"
//---------------------------------------------------------------------------
void CALLBACK wave_in_event(HWAVEIN hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
void CALLBACK wave_out_event(HWAVEOUT hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
//---------------------------------------------------------------------------
class wave_in
{
public:
bool _init,_fifo;
FIFO<BYTE> fifo;
WAVEHDR *hdr;
HWAVEIN hw;
WAVEFORMATEX buff_format;
DWORD buff_size;
DWORD freq; WORD chanels,bits,samples,buffers;
BYTE **buff;
int adr,num;
void CALLBACK (*event)(HWAVEIN hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
// void (*onreceive)(wave_in *wi,BYTE *data,int size);
void (__closure *onreceive)(wave_in *wi,BYTE *data,int size);
wave_in()
{
hdr=NULL;
buff=NULL;
buffers=0;
buff_size=0;
_init=false;
adr=0;
num=0;
event=wave_in_event;
onreceive=NULL;
}
~wave_in()
{
_free();
}
wave_in(wave_in& a) { *this=a; }
wave_in* operator = (const wave_in *a) { *this=*a; return this; }
//wave_in* operator = (const wave_in &a) { ...copy... return this; }
void _free()
{
adr=0;
num=0;
if (_init) { waveInClose(hw); _init=false; }
#ifdef _mmap_h
if (buff) for (int i=0;i<buffers;i++) if (buff[i]) mmap_del(buff[i]);
if (buff) mmap_del(buff);
if (hdr ) mmap_del(hdr );
#endif
if (buff)
{
for (int i=0;i<buffers;i++) if (buff[i]) delete[] buff[i];
delete[] buff;
buff=NULL;
}
if (hdr) { delete[] hdr; hdr=NULL; }
}
void init(DWORD _freq,WORD _chanels,WORD _bits,WORD _samples,WORD _buffers=5)
{
int i,ret;
_free();
buffers=_buffers;
if (buffers<1) buffers=1;
hdr=new WAVEHDR[buffers];
buff=new BYTE*[buffers];
#ifdef _mmap_h
if (hdr ) mmap_new(hdr ,buffers*sizeof(WAVEHDR));
if (buff) mmap_new(buff,buffers*sizeof(BYTE*));
#endif
freq =_freq;
chanels =_chanels;
bits =_bits;
samples =_samples;
buff_size=(chanels*bits*samples)>>3;
samples=(buff_size<<3)/(chanels*bits);
for (i=0;i<buffers;i++) buff[i]=new BYTE[buff_size];
#ifdef _mmap_h
for (i=0;i<buffers;i++) if (buff[i]) mmap_new(buff[i],buff_size);
#endif
buff_format.wFormatTag =WAVE_FORMAT_PCM; // set buffer format
buff_format.nChannels =chanels;
buff_format.nSamplesPerSec =freq;
buff_format.wBitsPerSample =bits;
buff_format.cbSize =0;
buff_format.nAvgBytesPerSec =(freq*chanels*bits)>>3;
buff_format.nBlockAlign =(chanels*bits)>>3;
if (event) ret=waveInOpen(&hw,WAVE_MAPPER,&buff_format,(DWORD_PTR)event,(DWORD_PTR)this,CALLBACK_FUNCTION);
else ret=waveInOpen(&hw,WAVE_MAPPER,&buff_format,0,0,CALLBACK_NULL);
if (ret!=MMSYSERR_NOERROR)
{
// waveInGetErrorText(ret,err,255);
return;
}
WAVEHDR hdr0;
hdr0.dwBufferLength=buff_size;
hdr0.dwUser=0;
hdr0.dwFlags=0;
hdr0.dwLoops=0;
hdr0.lpNext=NULL;
for (i=0;i<buffers;i++)
{
hdr[i]=hdr0;
hdr[i].lpData=buff[i];
}
_init=true;
}
void add()
{
if (!_init) return;
int i,ret;
BYTE *p;
p=buff[adr];
ret=waveInPrepareHeader(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveInGetErrorText(ret,err,255);
return;
}
waveInAddBuffer(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveInGetErrorText(ret,err,255);
return;
}
adr++;
if (adr>=buffers) adr=0;
num++;
}
void start()
{
if (!_init) return;
while (num<buffers) add();
waveInStart(hw);
}
void stop()
{
if (!_init) return;
waveInStop(hw);
}
};
//---------------------------------------------------------------------------
class wave_out:public multi_lock
{
public:
bool _init,_fifo;
FIFO<BYTE> fifo;
WAVEHDR *hdr;
HWAVEOUT hw;
WAVEFORMATEX buff_format;
DWORD buff_size;
DWORD freq; WORD chanels,bits,samples,buffers;
BYTE **buff;
int adr,num,err;
void CALLBACK (*event)(HWAVEOUT hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
wave_out()
{
hdr=NULL;
buff=NULL;
buffers=0;
buff_size=0;
_init=false;
adr=0;
num=0;
err=0;
event=wave_out_event;
}
~wave_out()
{
_free();
}
wave_out(wave_out& a) { *this=a; }
wave_out* operator = (const wave_out *a) { *this=*a; return this; }
//wave_out* operator = (const wave_out &a) { ...copy... return this; }
void _free()
{
adr=0;
num=0;
if (_init) { waveOutClose(hw); _init=false; }
#ifdef _mmap_h
if (buff) for (int i=0;i<buffers;i++) if (buff[i]) mmap_del(buff[i]);
if (buff) mmap_del(buff);
if (hdr ) mmap_del(hdr );
#endif
if (buff)
{
for (int i=0;i<buffers;i++) if (buff[i]) delete[] buff[i];
delete[] buff;
buff=NULL;
}
if (hdr) { delete[] hdr; hdr=NULL; }
}
void init(DWORD _freq,WORD _chanels,WORD _bits,WORD _samples,WORD _buffers=10)
{
int i,ret;
_free();
buffers=_buffers;
if (buffers<1) buffers=1;
hdr=new WAVEHDR[buffers];
buff=new BYTE*[buffers];
#ifdef _mmap_h
if (hdr ) mmap_new(hdr ,buffers*sizeof(WAVEHDR));
if (buff) mmap_new(buff,buffers*sizeof(BYTE*));
#endif
freq =_freq;
chanels =_chanels;
bits =_bits;
samples =_samples;
buff_size=(chanels*bits*samples)>>3;
samples=(buff_size<<3)/(chanels*bits);
for (i=0;i<buffers;i++) buff[i]=new BYTE[buff_size];
#ifdef _mmap_h
for (i=0;i<buffers;i++) if (buff[i]) mmap_new(buff[i],buff_size);
#endif
buff_format.wFormatTag =WAVE_FORMAT_PCM; // set buffer format
buff_format.nChannels =chanels;
buff_format.nSamplesPerSec =freq;
buff_format.wBitsPerSample =bits;
buff_format.cbSize =0;
buff_format.nAvgBytesPerSec =(freq*chanels*bits)>>3;
buff_format.nBlockAlign =(chanels*bits)>>3;
if (event) ret=waveOutOpen(&hw,WAVE_MAPPER,&buff_format,(DWORD_PTR)event,(DWORD_PTR)this,CALLBACK_FUNCTION);
else ret=waveOutOpen(&hw,WAVE_MAPPER,&buff_format,0,0,CALLBACK_NULL);
if (ret!=MMSYSERR_NOERROR)
{
// waveOutGetErrorText(ret,err,255);
return;
}
WAVEHDR hdr0;
hdr0.dwBufferLength=buff_size;
hdr0.dwUser=0;
hdr0.dwFlags=WHDR_INQUEUE;
hdr0.dwLoops=0;
hdr0.lpNext=NULL;
for (i=0;i<buffers;i++)
{
hdr[i]=hdr0;
hdr[i].lpData=buff[i];
}
_init=true;
}
void send(BYTE *data)
{
if (!_init) return;
lock();
if (num>buffers)
{
err++;
adr=0;
num=0;
}
DWORD i;
int ret;
BYTE *p;
p=buff[adr];
for (i=0;i<buff_size;i++) p[i]=data[i];
ret=waveOutPrepareHeader(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveOutGetErrorText(ret,err,255);
unlock();
return;
}
waveOutWrite(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveOutGetErrorText(ret,err,255);
unlock();
return;
}
adr++;
if (adr>=buffers) adr=0;
num++;
unlock();
}
void stop()
{
waveOutReset(hw);
}
};
//---------------------------------------------------------------------------
void CALLBACK wave_in_event(HWAVEIN hw,UINT msg,DWORD inst,DWORD p1,DWORD p2)
{
wave_in *w=(wave_in*)(void*)(DWORD_PTR)inst;
if (w==NULL) return;
if (msg==WIM_OPEN); // open wave HW
if (msg==WIM_DATA) // wave data send done
{
int adr0=w->adr-w->num;
while (adr0>=w->buffers) adr0-=w->buffers;
while (adr0< 0) adr0+=w->buffers;
if (w->onreceive) w->onreceive(w,w->buff[adr0],w->buff_size);
w->num--;
}
if (msg==WIM_CLOSE); // close wave HW
}
//---------------------------------------------------------------------------
void CALLBACK wave_out_event(HWAVEOUT hw,UINT msg,DWORD inst,DWORD p1,DWORD p2)
{
wave_out *w=(wave_out*)(void*)(DWORD_PTR)inst;
if (w==NULL) return;
w->lock();
if (msg==WOM_OPEN); // open wave HW
if (msg==WOM_DONE) w->num--; // wave data send done
if (msg==WOM_CLOSE); // close wave HW
w->unlock();
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
support file lock.h:
//---------------------------------------------------------------------------
//--- Multithread lock class ver 1.00 ---------------------------------------
//---------------------------------------------------------------------------
#ifndef _lock_h
#define _lock_h
//---------------------------------------------------------------------------
class single_lock
{
public:
CRITICAL_SECTION hnd;
single_lock() { InitializeCriticalSectionAndSpinCount(&hnd,0x00000400); }
~single_lock() { DeleteCriticalSection(&hnd); }
single_lock(single_lock& a) { *this=a; }
single_lock* operator = (const single_lock *a) { *this=*a; return this; }
// single_lock* operator = (const single_lock &a) { **** }
// thread safe functions
inline void lock() { EnterCriticalSection(&hnd); }
inline void unlock() { LeaveCriticalSection(&hnd); }
};
//---------------------------------------------------------------------------
const int _multi_lock_size=16; // max number of simultanious access
class multi_lock
{
public:
CRITICAL_SECTION hnd;
CRITICAL_SECTION dat[_multi_lock_size];
DWORD adr0,adr1,siz;
multi_lock() { InitializeCriticalSectionAndSpinCount(&hnd,0x00000400); for(int i=0;i<_multi_lock_size;i++) InitializeCriticalSectionAndSpinCount(&dat[i],0x00000400); adr0=0; adr1=0; siz=0; }
~multi_lock() { DeleteCriticalSection(&hnd); for(int i=0;i<_multi_lock_size;i++) DeleteCriticalSection(&dat[i]); }
multi_lock(multi_lock& a) { *this=a; }
multi_lock* operator = (const multi_lock *a) { *this=*a; return this; }
// multi_lock* operator = (const multi_lock &a) { **** }
// thread safe functions
inline void lock()
{
EnterCriticalSection(&hnd);
if (siz<_multi_lock_size)
{
siz++;
EnterCriticalSection(&dat[adr1]);
adr1++; if (adr1>=_multi_lock_size) adr1=0;
}
// else error();
LeaveCriticalSection(&hnd);
}
inline void unlock()
{
EnterCriticalSection(&hnd);
if (siz>0)
{
siz--;
LeaveCriticalSection(&dat[adr0]);
adr0++; if (adr0>=_multi_lock_size) adr0=0;
}
// else error();
LeaveCriticalSection(&hnd);
}
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
support file FIFO.h:
//---------------------------------------------------------------------------
//--- FIFO template class ver 2.08 ------------------------------------------
//---------------------------------------------------------------------------
#ifndef _fifo_h
#define _fifo_h
//---------------------------------------------------------------------------
//static bool _enable_fifo_debug=false;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
template <class T> class FIFO
{
public:
T *dat;
int adr0,adr1,size;
CRITICAL_SECTION lock;
FIFO() { dat=NULL; InitializeCriticalSectionAndSpinCount(&lock,0x00000400); alloc(16); }
~FIFO() { _free(); DeleteCriticalSection(&lock); }
FIFO(FIFO& a) { *this=a; }
FIFO* operator = (const FIFO *a){ *this=*a; return this; }
FIFO* operator = (const FIFO &a){ EnterCriticalSection(&a.lock); EnterCriticalSection(&lock); _alloc(a.size); adr0=a.adr0; adr1=a.adr1; for (int i=0;i<size;i++) dat[i]=a.dat[i]; LeaveCriticalSection(&lock); LeaveCriticalSection(&a.lock); return this; }
// already locked functions
inline int _adr_inc(int a) volatile { a++; if (a>=size) a=0; return a; }
inline int _adr_dec(int a) volatile { if (a!=adr0) a--; if (a<0) a=size-1; return a; }
inline void _alloc(int _size)volatile { if (dat) delete[] dat; dat=NULL; size=_size; adr0=0; adr1=0; dat=new T[size]; if (dat==NULL) size=0; _reset(); }
inline void _free() volatile { if (dat) delete[] dat; dat=NULL; size= 0; adr0=0; adr1=0; }
inline void _reset() volatile { adr0=0; adr1=0; }
inline void _in(T x) volatile { if (_is_full()) return; dat[adr1]=x; adr1=_adr_inc(adr1); }
inline T _out() volatile { if (_is_empty()){ T null; return null; } T x=dat[adr0]; adr0=_adr_inc(adr0); return x; }
inline T _peek_first() volatile { if (_is_empty()){ T null; return null; } T x=dat[adr0]; return x; }
inline T _peek_last() volatile { if (_is_empty()){ T null; return null; } int a=_adr_dec(adr1); T x=dat[a]; return x; }
inline bool _is_empty() volatile { bool ret=(adr0==adr1); return ret; }
inline bool _is_full() volatile { int a=_adr_inc(adr1); bool ret=(a==adr0); return ret; }
inline int _get_size() volatile { if (_is_empty()) return 0; if (_is_full()) return size; if (adr0<adr1) return adr1-adr0; else return size+adr1-adr0; }
// thread safe functions
void _lock() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); }
void _unlock() volatile { LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
void alloc(int _size) volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); _alloc(_size); LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
void reset() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); _reset(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
void in(T x) volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); _in(x); LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
T out() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); T x=_out(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
T peek_first() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); T x=_peek_first(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
T peek_last() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); T x=_peek_last(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
bool is_empty() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); bool x=_is_empty(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
bool is_full() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); bool x=_is_full(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
int get_size() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); int x=_get_size(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
here simple usage (extracted from my generator hope I did not forget anything):
// globals and init
const int _size=20*1024;
wave_out wo;
WORD buffer[_size]; // your PCM sound data matching the init operands
wo.init(44100,2,16,_size,10); // sampling_freq,channels,bits,buffer size,buffers
// this in some timer or thread (fast enbough)
while (wo.num<4)
{
// here prepare buff[] data
wo.send((BYTE*)buff);
}
// force to stop on app exit or when needed
wo.stop();
The stuff was compiled on BDS2006 C++ Builder so in case you use newer compiler you might need to tweak some stuff...had not time will to port this to new compiler yet so if the case see this.
wave_out is for sound playback and wave_in is for recording both are using preferred windows sound device selected in control panel of Windows. To enable smooth playback just make sure that at least 4 buffers are filled in the sound que while (wo.num<4)... otherwise sound glitches might occur
You might also need to decode WAV files so here another ancient lib of mine RIFF.h:
//---------------------------------------------------------------------------
//--- RIFF WAVE format: 1.01 ------------------------------------------------
//---------------------------------------------------------------------------
#ifndef _RIFF_h
#define _RIFF_h
//---------------------------------------------------------------------------
// 8bit PCM is unsigned
// 16bit PCM is signed 2'os complement little endian (big endian is RIFX)
//---------------------------------------------------------------------------
struct _wave_chunk
{
DWORD ids;
DWORD len;
_wave_chunk(){ ids=' '; len=0; }
_wave_chunk(_wave_chunk& a){ *this=a; }; ~_wave_chunk(){}; _wave_chunk* operator = (const _wave_chunk *a) { *this=*a; return this; }; /*_wave_chunk* operator = (const _wave_chunk &a) { ...copy... return this; };*/
};
struct _wave_hdr
{
DWORD ids; // "RIFF"
DWORD len;
DWORD tps; // "WAVE"
_wave_hdr(){ ids='FFIR'; len=0; tps='EVAW'; }
_wave_hdr(_wave_hdr& a){ *this=a; }; ~_wave_hdr(){}; _wave_hdr* operator = (const _wave_hdr *a) { *this=*a; return this; }; /*_wave_hdr* operator = (const _wave_hdr &a) { ...copy... return this; };*/
};
struct _wave_fmt
{
DWORD ids; // "fmt "
DWORD len; // 16,18,40
WORD format; // 1 = PCM linear quantization
/* 0x0001 WAVE_FORMAT_PCM PCM
0x0003 WAVE_FORMAT_IEEE_FLOAT IEEE float
0x0006 WAVE_FORMAT_ALAW 8-bit ITU-T G.711 A-law
0x0007 WAVE_FORMAT_MULAW 8-bit ITU-T G.711 ยต-law
0xFFFE WAVE_FORMAT_EXTENSIBLE Determined by SubFormat */
WORD chanels;
DWORD samplerate;
DWORD byterate;
WORD blockalign;
WORD bits;
WORD ext_len; // extension length 0,22
WORD ext_validbits;
DWORD ext_channelmask;
BYTE ext_subformat[16];
_wave_fmt(){ ids=' tmf'; len=16; format=1; chanels=1; samplerate=44100; bits=8; ext_len=0; ext_validbits=0; ext_channelmask=0; for (int i=0;i<16;i++) ext_subformat[i]=0; compute(); }
_wave_fmt(_wave_fmt& a){ *this=a; }; ~_wave_fmt(){}; _wave_fmt* operator = (const _wave_fmt *a) { *this=*a; return this; }; /*_wave_fmt* operator = (const _wave_fmt &a) { ...copy... return this; };*/
void compute()
{
byterate=(chanels*samplerate*bits)/8;
blockalign=(chanels*bits)/8;
}
};
struct _wave_dat
{
DWORD ids; // "data"
DWORD len;
_wave_dat(){ ids='atad'; len=0; }
_wave_dat(_wave_dat& a){ *this=a; }; ~_wave_dat(){}; _wave_dat* operator = (const _wave_dat *a) { *this=*a; return this; }; /*_wave_dat* operator = (const _wave_dat &a) { ...copy... return this; };*/
};
//---------------------------------------------------------------------------
class wave
{
public:
AnsiString name;
int hnd;
bool readonly;
_wave_hdr hdr;
_wave_fmt fmt;
_wave_dat dat;
wave();
~wave();
void create(AnsiString _name);
void write(BYTE *data,DWORD size);
bool open(AnsiString _name);
DWORD read(BYTE *data,DWORD size);
void close();
};
//---------------------------------------------------------------------------
wave::wave()
{
name=0;
hnd=-1;
readonly=true;
}
//---------------------------------------------------------------------------
wave::~wave()
{
close();
}
//---------------------------------------------------------------------------
void wave::create(AnsiString _name)
{
close();
readonly=true;
// hdr=_wave_hdr();
// fmt=_wave_fmt();
// dat=_wave_dat();
hdr.len=sizeof(hdr)-8;
dat.len=0;
fmt.compute();
name=_name;
hnd=FileCreate(name);
if (hnd<0) return;
FileWrite(hnd,&hdr,sizeof(hdr));
FileWrite(hnd,&fmt,fmt.len+8);
FileWrite(hnd,&dat,sizeof(dat));
readonly=false;
}
//---------------------------------------------------------------------------
bool wave::open(AnsiString _name)
{
close();
readonly=true;
name=_name;
hnd=FileOpen(name,fmOpenRead);
if (hnd<0) return false;
if (FileRead(hnd,&hdr,sizeof(hdr))<sizeof(hdr)){ close(); return false; }
if (hdr.ids!='FFIR') return false;
if (hdr.tps!='EVAW') return false;
_wave_chunk chk;
DWORD sz=sizeof(chk),l;
for(;;)
{
if (FileRead(hnd,&chk,sz)<sz){ close(); return false; }
if (chk.ids==' tmf')
{
fmt.ids=chk.ids;
fmt.len=chk.len;
if (FileRead(hnd,((BYTE*)&fmt)+sz,chk.len)<chk.len){ close(); return false; }
}
else if (chk.ids=='atad')
{
dat.ids=chk.ids;
dat.len=chk.len;
return true;
}
else FileSeek(hnd,int(chk.len),1);
}
}
//---------------------------------------------------------------------------
void wave::write(BYTE *data,DWORD size)
{
if (hnd<0) return;
hdr.len+=size;
dat.len+=size;
if (!readonly) FileWrite(hnd,data,size);
}
//---------------------------------------------------------------------------
DWORD wave::read(BYTE *data,DWORD size)
{
if (hnd<0) return 0;
return FileRead(hnd,data,size);
}
//---------------------------------------------------------------------------
void wave::close()
{
name="";
if (hnd<0) return;
FileSeek(hnd,0,0);
if (!readonly) FileWrite(hnd,&hdr,sizeof(hdr));
FileClose(hnd);
hnd=-1;
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
And usage:
// globals
wave wav;
wave_out wo;
BYTE *buff;
// init
wav.open("tetris2.wav"); // any file ...
wo.init(wav.fmt.samplerate,wav.fmt.chanels,wav.fmt.bits,dt*wav.fmt.samplerate/1000,10);
buff=new BYTE[wo.buff_size];
// timer 20ms ...
while (wo.num<4)
{
wav.read(buff,wo.buff_size);
wo.send(buff);
}
// exit
wo.stop();
wav.close();
delete[] buff;
the wav.read(...) returns number of BYTEs read so once it hit less than buffer size or even equals to zero it means you already on end of wavefile ... Now as you will have the wav in memory just rewrite the file access to memory access ...

g++ optimizes out nullpointer checks

I have a function that is working if I compile with O0 flag but crashes on a function called on a nullptr if compiled with O2.
If I add some macros to disable optimizations around that function it will work properly.
https://i.imgur.com/ObYiiEl.png
if (LPPARTY pkParty = GetParty())
{
struct FPartyBuff
{
const CSkillProto* pkSk;
DWORD casterPID;
int iAmount1, iDur1;
int iAmount2, iDur2;
FPartyBuff(const CSkillProto* pkSkill, DWORD caster, int amount1, int dur1, int amount2, int dur2)
: pkSk(pkSkill), casterPID(caster), iAmount1(amount1), iDur1(dur1), iAmount2(amount2), iDur2(dur2) {}
void operator() (LPCHARACTER ch)
{
bool bOverride = true;
if (ch && ch->GetPlayerID() != casterPID)
{
if (pkSk->bPointOn != POINT_NONE)
{
ch->AddAffect(pkSk->dwVnum, pkSk->bPointOn, iAmount1, pkSk->dwAffectFlag, iDur1, 0, bOverride, false, casterPID);
bOverride = false;
}
if (pkSk->bPointOn2 != POINT_NONE)
{
ch->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag, iDur2, 0, bOverride, false, casterPID);
bOverride = false;
}
}
}
};
if (pkVictim && pkParty->IsMember(pkVictim->GetPlayerID()))
{
FPartyBuff f(pkSk, GetPlayerID(), iAmount, iDur, iAmount2, iDur2);
pkParty->ForEachNearMember(f);
}
}
But without them this part of the code calls IsMember on pkParty even when it is a nullpointer.
LPPARTY is defined as CParty*
Why is it happening?

boost asio io_context.run() segmentation error

I am trying to make simple server that remembers and operates some variables with receive short instructions.
I didn't complete this server, and I am trying to test connecting to the server.
But when I try to connect the server, it occurs segmentation fault.
It seems that be occured at io_context.run() function.
I don't know exact cause of this error in spite of reading asio's reference page.
Please help me..
I think that you don't have to read code of data(data.hpp).
This is server code.
//server.cpp
#include <iostream>
#include "network/sc_network.hpp"
int main(int argc, char *argv[])
{
try
{
if(argc != 2)
{
std::cerr << "Usage: server <port>\n";
return 1;
}
boost::asio::io_context io_context;
tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[1]));
server server(io_context, endpoint);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
This is client code.
//client.cpp
#include <iostream>
#include <thread>
#include <cstdlib>
#include <boost/asio.hpp>
#include "network/data/data.hpp"
using boost::asio::ip::tcp;
class client{
private:
boost::asio::io_context& io_context_;
tcp::socket socket_;
oper_data *data_;
void do_connect(const tcp::resolver::results_type& endpoints)
{
boost::asio::async_connect(socket_, endpoints,
[this](boost::system::error_code ec, tcp::endpoint)
{
if(!ec)
{
boost::asio::async_read(socket_,
boost::asio::buffer(data_, sizeof(oper_data)),
[this](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
boost::asio::async_write(socket_,
boost::asio::buffer(data_,sizeof(oper_data)),
[this](boost::system::error_code ec, std::size_t)
{
});
}
else
{
socket_.close();
}
});
}
else
{
socket_.close();
}
});
}
public:
client(boost::asio::io_context& io_context,
const tcp::resolver::results_type& endpoints)
: io_context_(io_context),
socket_(io_context)
{
do_connect(endpoints);
}
void write(const oper_data& data)
{
boost::asio::post(io_context_,
[this, data]()
{
});
}
};
int main(int argc, char *argv[])
{
try
{
if(argc != 3)
{
std::cerr << "Usage: client <host> <port>\n";
return 1;
}
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(argv[1], argv[2]);
client c(io_context, endpoints);
std::thread t([&io_context](){ io_context.run(); });
char line[128];
while (std::cin.getline(line, 128))
{
oper_data data;
//processing the line with deviding in 3 words.
}
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
this is sc_network.hpp
//sc_network.hpp
#include <boost/asio.hpp>
#include <memory>
#include <utility>
#include "data/data.hpp"
using boost::asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
private:
tcp::socket socket_;
data_proc data_proc_;
public:
session(tcp::socket socket)
: socket_(std::move(socket)){}
void start()
{
oper_data *input_data;
boost::asio::async_read(socket_,
boost::asio::buffer(input_data, sizeof(oper_data)),
[this, input_data](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
data_proc_.set_data(*input_data);
data_proc_.oper_process();
start();
}
else
{
return;
}
});
}
};
class server
{
private:
tcp::acceptor acceptor_;
void do_accept()
{
acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket)
{
if(!ec)
{
session ex_session(std::move(socket));
}
do_accept();
});
}
public:
server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
};
this is data.hpp.
//data.hpp
#include <deque>
#include <cstring>
#include "favdew_utility.hpp"
#define max_oper_size 5
#define max_oper_buf max_oper_size + 1
struct oper_data {
char oper_[max_oper_buf] = "\0";
char *operand_;
char *oper_num_;
};
typedef struct oper_data oper_data;
class data_store {
private:
char *var_name_;
char *var_value_;
public:
data_store()
: var_name_(NULL), var_value_(NULL) {}
data_store(const char *var_name, const char *var_value)
{
std::size_t var_name_size = strlen(var_name) + 1;
var_name_ = new char[var_name_size];
strncpy(var_name_, var_name, strlen(var_name));
std::size_t var_value_size = strlen(var_value) + 1;
var_value_ = new char[var_value_size];
strncpy(var_value_, var_value, strlen(var_value));
}
char *var_name() { return var_name_; }
char *var_value() { return var_value_; }
void set_value(const char *var_value) {
var_value_ = new char[strlen(var_value) + 1];
strncpy(var_value_, var_value, strlen(var_value));
}
};
typedef std::deque<data_store> data_queue;
class data_proc {
private:
oper_data data_;
data_queue proc_queue;
void var()
{
if (data_store *var = this->get_var(data_.operand_)) {
var->set_value(data_.oper_num_);
}
else {
data_store input_data(data_.operand_, data_.oper_num_);
this->proc_queue.push_back(input_data);
}
}
bool sum()
{
data_store *var = this->get_var(data_.operand_);
if ( (var) && isNumber(var->var_value()))
{
const int input_data = std::atoi(var->var_value()) +
std::atoi(this->data_.oper_num_);
var->set_value(std::to_string(input_data).c_str());
return true;
}
else
return false;
}
bool dif()
{
data_store *var = this->get_var(data_.operand_);
if ((var) && isNumber(var->var_value()))
{
const int input_data = std::atoi(var->var_value()) -
std::atoi(this->data_.oper_num_);
var->set_value(std::to_string(input_data).c_str());
return true;
}
else
return false;
}
public:
data_proc()
{
oper_data input_data;
//<input_data.oper_> is already initialized with "\0"
std::memset(input_data.operand_, 0, sizeof(char *));
std::memset(input_data.oper_num_, 0, sizeof(char *));
}
data_proc(const char *oper, const char *operand, const char *oper_num)
{
strncpy(data_.oper_, oper, max_oper_size);
std::size_t operand_size = strlen(operand) + 1;
data_.operand_ = new char[operand_size];
strncpy(data_.operand_, operand, strlen(operand));
std::size_t oper_num_size = strlen(oper_num) + 1;
data_.oper_num_ = new char[oper_num_size];
strncpy(data_.oper_num_, oper_num, strlen(oper_num));
}
inline void set_data(oper_data data)
{
this->data_ = data;
}
void set_data(const char *oper, const char *operand, const char *oper_num)
{
strncpy(data_.oper_, oper, max_oper_size);
std::size_t operand_size = strlen(operand) + 1;
data_.operand_ = new char[operand_size];
strncpy(data_.operand_, operand, strlen(operand));
std::size_t oper_num_size = strlen(oper_num) + 1;
data_.oper_num_ = new char[oper_num_size];
strncpy(data_.oper_num_, oper_num, strlen(oper_num));
}
data_store *get_var(const char *var_name)
{
const std::size_t queue_size = this->proc_queue.size();
for (std::size_t i=0; i < queue_size; i++) {
if (!strcmp(this->proc_queue[i].var_name(), var_name)) {
return &proc_queue[i];
}
}
return NULL;
}
bool oper_process()
{
const char *oper = this->data_.oper_;
if (!strcmp(oper, "var")) {
var();
return true;
}
else if (!strcmp(oper, "sum")) {
sum();
return true;
}
else if (!strcmp(oper, "dif")) {
dif();
return true;
}
else {
return false;
}
}
};
this is favdew_utility.hpp
#include <string>
#include <cstdlib>
bool isNumber(const char *str)
{
std::size_t length = strlen(str);
for (std::size_t i = 0; i < length; i++)
{
if (!('0' < str[i] && str[i] < '9'))
return false;
continue;
}
return true;
}
bool isEmpty(void *buffer)
{
if (!buffer || *(char *)buffer == '\0')
return true;
else
return false;
}
There are many issues, just pointing out a few:
The declaration
session ex_session(std::move(socket));
This creates a local (stack) variable that inherits from enable_shared_from_this. Using shared_from_this will be Undefined Behaviour
Session gets immediately destructed and start() appears to be never called
If session::start() were called, it would fail because it starts an async operation without guarding the lifetime of the session instance:
boost::asio::async_read(socket_,
boost::asio::buffer(input_data, sizeof(oper_data)),
[this, input_data](boost::system::error_code ec, std::size_t) { ....
At the very least you need to capture the shared pointer to the session:
auto self = shared_from_this();
boost::asio::async_read(socket_,
boost::asio::buffer(input_data, sizeof(oper_data)),
[this, self, input_data](boost::system::error_code ec, std::size_t)
Even worse, input_data is never initialized. Again: Undefined Behaviour. Even if you did initialize it, you'd have to manage lifetime; why not make it a member of the session, instead of dynamically allocating (or forgetting to, as you have now)?
Caution: No, you cannot stack-allocate inside start() not even if you capture it in the lambda, because the async operations will not complete before start() exits.
Same in client: data_ is never initialized. Boom.
Even if you had it correctly allocated, using it as an asio::buffer() treats it as a POD.
Since, however, data_proc happily aggregates a data_queue which is std::deque<> it obviously IS NOT POD. More Undefined Behaviour.
What you probably need is to serialize your datastructures, instead of hoping that copying some bytes of memory is going to magically "work". It won't!
See e.g. sending/receiving a struct in boost::asio
Note While you're at is, use C++ instead of C? All the raw pointers and char* are complexity that you don't need, and it is handing your dozens of footguns or ends or rope that you're gonna hurt yourself more with.
In client.cpp you have:
std::thread t([&io_context](){ io_context.run(); });
char line[128];
while (std::cin.getline(line, 128))
{
oper_data data;
//processing the line with deviding in 3 words.
}
Soooo many things...
use std::getline, not std::istream::getline
the thread needs to be joined (https://en.cppreference.com/w/cpp/thread/thread/~thread)
if all you do is block for input, why have the thread?
io_context.run(); // replaces all of the above
data_store is also not POD, but it is also a living memory-leak. All the new-ed memory is never freed.
Note that, the way it's written, the struct might APPEAR to be POD, but logically it isn't (Rule Of Three). Basically, you wrote it in C, not C++. This foregoes all abstractions that C++ has, and now the compiler cannot tell that the struct refers to non-owned resources.
Mind you, this gives me the impression that oper_data might have similar issues (though at first I assumed that operand_ and _oper_num are supposed to point inside the fixed-size buffer oper_[])
Summarizing:
You're way ahead of yourself. Start much simpler. Use C++ (std::string, never use new/delete, actually use std::make_shared if you want to enable_shared_from_this).
You'll be much happier. Feel free to come back with simpler questions when you get stuck, ideally the SSCCE would be a (few) dozen or so lines.

std::map<my_enum, base_class> insert error: base_class is an inaccessibile base of derived_class

This little program has to write an xml file.
Building the code I get the following error:
K:\Sergio\cpp\xml\sergio\cbp6s\main.cpp|32|error: 'base_tag' is an inaccessible base of 'tag'
In short, I have two classes derived from base_tag (xml_declaration and tag) and I want insert (or emplace) in a std::map some std::pair elements.
Building, the first insert works (std::pair<order::declaration, xml_declaration>), but the second fails (std::pair<order::root, tag_object>).
Between the object are derived from base_tag
Where am I wrong?
File tag.hpp :
#ifndef _TAG_HPP_
#define _TAG_HPP_
#include <string>
#include <vector>
#include <utility>
enum class tag_type
{
closing = -1,
autoclosed = 0,
opening = 1
};
using attribute = std::pair<std::string, std::string>;
class base_tag
{
public:
base_tag();
virtual ~base_tag();
virtual std::string get();
bool attribute_exists(std::string);
std::string get_attribute_value(std::string name);
bool add_attribute(std::string name, std::string value);
protected:
std::vector<std::pair<std::string, std::string>> _attributes;
};
// ------------------------------------------------------------
class xml_declaration : public base_tag
{
public:
xml_declaration();
~xml_declaration();
std::string get();
};
// ----------------------------------------------------------
class tag : base_tag
{
public:
tag(std::string name);
tag(std::string name, tag_type tt );
std::string get();
void set_ident(size_t ident);
protected:
std::string _name;
tag_type _tt;
};
#endif // _TAG_HPP_
File tag.cpp
#include "tag.hpp"
base_tag::base_tag()
{
}
base_tag::~base_tag()
{
_attributes.clear();
}
bool base_tag::attribute_exists(std::string name)
{
bool res = false;
for(auto & i : _attributes)
{
if (i.first == name)
res = true;
}
return res;
}
bool base_tag::add_attribute(std::string name, std::string value)
{
bool res = false;
if(!attribute_exists(name))
{
attribute a = std::make_pair(name, value);
_attributes.push_back(a);
res = true;
}
return res;
}
std::string base_tag::get()
{
return u8"<invalid_tag/>";
}
// -------------------------------------------------------
xml_declaration::xml_declaration(): base_tag()
{
add_attribute("version", "1.0");
add_attribute("encoding", "UTF-8");
add_attribute("standalone", "yes");
}
xml_declaration::~xml_declaration()
{ }
std::string xml_declaration::get()
{
std::string res = u8"<?xml";
for(auto & i : _attributes)
{
res.push_back(' ');
res += i.first;
res += u8"=\"";
res += i.second;
res += u8"\"";
}
res += u8" ?>";
return res;
}
// -------------------------------------------------------------
tag::tag(std::string name):base_tag(), _name(name)
{
_tt = tag_type::autoclosed;
}
tag::tag(std::string name, tag_type tt ): base_tag(), _name(name),
_tt(tt)
{ }
std::string tag::get()
{
std::string res = u8"";
bool with_attributes = !(_attributes.empty());
switch(_tt)
{
case tag_type::autoclosed : {
res = u8"<";
res += _name;
if(with_attributes)
{
for(auto & i : _attributes)
{
res.push_back(' ');
res += i.first;
res += u8"=\"";
res += i.second;
res += u8"\"";
}
};
res += u8"/>";
break;
}
case tag_type::opening : {
res = u8"<";
res += _name;
for(auto & i : _attributes)
{
res.push_back(' ');
res += i.first;
res += u8"=\"";
res += i.second;
res += u8"\"";
}
res += u8">";
break;
}
case tag_type::closing : {
res = u8"</";
res += _name;
res.push_back('>');
}
default : break;
}
return res;
}
File main.cpp
#include <iostream>
#include <map>
#include <utility>
#include "tag.hpp"
using namespace std;
enum class order
{
declaration = 0,
root = 1,
file_version = 4,
project = 10,
project_closing = 998,
root_closing = 1000
};
int main()
{
std::map<order, base_tag> tree;
xml_declaration decl;
cout << decl.get() << endl;
tag t1("project_file", tag_type::opening);
tag t2("project_file", tag_type::closing);
tree.insert(std::pair<order, base_tag>(order::declaration,
decl));
tree.insert(std::pair<order, base_tag>(order::root, t1));
tree.insert(std::pair<order, base_tag>(order::root, t2));
// tree.emplace(std::pair<order, base_tag>(order::root_closing, t1));
cout << tree.size() << endl;
return 0;
}
I'm using Code::Blocks with GCC 5.1.0 (on Windows 10).
As the error message says, tag inherits base_tag privately. If you change its headline into
class tag: public base_tag;
(same as your xml_declaration which inherits base_tag publicly) then it will officially be-a base tag.
A more serious problem is that you try to store instances of inherited classes in a container of a base class by value. What happens then is, objects get sliced and lose their whole derived functionality; you put an object of a derived class into a map, but you actually store an object of a based class in it (that's the reason some people tend to say polymorphic base classes should necessarily be abstract.) Use (smart) pointers or reference_wrappers as map's mapped type.

Error in storing outer class object in inner class C++

I was implementing the ring buffer and have encountered an error. What does it mean to store a reference of outer class(class ring) object(m_ring) in inner class(class iterator) and when I remove the reference(&) the program compiles correctly but crashes. Please explain what is happening.(See the comment in Ring.h) Sorry for bad English.
// Ring.h
#ifndef RING.H
#define RING.H
#include <iostream>
using namespace std;
template<class T>
class ring {
unsigned int m_size;
int m_pos;
T *m_values;
public:
class iterator;
public:
ring(unsigned int size) : m_size(size), m_pos(0)
{
m_values = new T[m_size];
}
~ring()
{
delete[] m_values;
}
void add(const T &val)
{
m_values[m_pos] = val;
m_pos++;
m_pos %= m_size;
}
T& get(int pos)
{
return m_values[pos];
}
iterator begin()
{
return iterator(0, *this);
}
iterator end()
{
return iterator(m_size, *this);
}
};
template<class T>
class ring<T>::iterator {
int m_pos;
ring &m_ring; // Removing & gives garbage output.
public:
iterator(int pos, ring& aRing) : m_pos(pos), m_ring(aRing){}
bool operator!=(const iterator &other) const
{
return other.m_pos != m_pos;
}
iterator &operator++(int)
{
m_pos++;
return *this;
}
iterator &operator++()
{
m_pos++;
return *this;
}
T &operator*()
{
// return m_ring.m_values[m_pos];
return m_ring.get(m_pos);
}
};
#endif // RING
Driver program :
// Ring_Buffer_Class.cpp
#include <iostream>
#include "ring.h"
using namespace std;
int main()
{
ring<string> textring(3);
textring.add("one");
textring.add("two");
textring.add("three");
textring.add("four");
// C++ 98
for(ring<string>::iterator it = textring.begin(); it != textring.end(); it++)
{
cout << *it << endl;
}
cout << endl;
// C++11
for(string value : textring)
{
cout << value << endl;
}
return 0;
}
I also observed that removing ~ring() (Destructor) results into correct output.
Expected output :
four
two
three
four
two
three

Resources