From e3e3b99e8e40d896081fe816128222780f9d0d6c Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 30 Nov 2009 18:54:41 +0000 Subject: [PATCH] - First version of ReactOS Sound Record Application by Marco Pagliaricci (IRC: rendar) svn path=/trunk/; revision=44331 --- .../base/applications/sndrec32/audio_def.hpp | 34 + .../applications/sndrec32/audio_format.cpp | 24 + .../applications/sndrec32/audio_format.hpp | 147 +++ .../applications/sndrec32/audio_membuffer.cpp | 501 ++++++++ .../applications/sndrec32/audio_membuffer.hpp | 338 ++++++ .../applications/sndrec32/audio_producer.cpp | 12 + .../applications/sndrec32/audio_producer.hpp | 112 ++ .../applications/sndrec32/audio_receiver.cpp | 17 + .../applications/sndrec32/audio_receiver.hpp | 103 ++ .../sndrec32/audio_resampler_acm.cpp | 387 ++++++ .../sndrec32/audio_resampler_acm.hpp | 99 ++ .../applications/sndrec32/audio_wavein.cpp | 880 ++++++++++++++ .../applications/sndrec32/audio_wavein.hpp | 271 +++++ .../applications/sndrec32/audio_waveout.cpp | 889 ++++++++++++++ .../applications/sndrec32/audio_waveout.hpp | 186 +++ .../base/applications/sndrec32/bitmap1.bmp | Bin .../base/applications/sndrec32/but_end.bmp | Bin 0 -> 1046 bytes .../base/applications/sndrec32/but_play.bmp | Bin 0 -> 1046 bytes .../base/applications/sndrec32/but_rec.bmp | Bin 0 -> 1046 bytes .../base/applications/sndrec32/but_start.bmp | Bin 0 -> 1046 bytes .../base/applications/sndrec32/but_stop.bmp | Bin 0 -> 1046 bytes .../base/applications/sndrec32/kkaudio.hpp | 18 + .../sndrec32/reactOS_sndrec32.ico | Bin 0 -> 23558 bytes reactos/base/applications/sndrec32/resource.h | 44 + reactos/base/applications/sndrec32/small.ico | Bin 0 -> 23558 bytes .../base/applications/sndrec32/sndrec32.cpp | 1042 +++++++++++++++++ reactos/base/applications/sndrec32/sndrec32.h | 96 ++ .../applications/sndrec32/sndrec32.rbuild | 20 + .../base/applications/sndrec32/sndrec32.rc | 179 +++ reactos/base/applications/sndrec32/stdafx.h | 23 + .../base/applications/sndrec32/targetver.h | 24 + 31 files changed, 5446 insertions(+) create mode 100644 reactos/base/applications/sndrec32/audio_def.hpp create mode 100644 reactos/base/applications/sndrec32/audio_format.cpp create mode 100644 reactos/base/applications/sndrec32/audio_format.hpp create mode 100644 reactos/base/applications/sndrec32/audio_membuffer.cpp create mode 100644 reactos/base/applications/sndrec32/audio_membuffer.hpp create mode 100644 reactos/base/applications/sndrec32/audio_producer.cpp create mode 100644 reactos/base/applications/sndrec32/audio_producer.hpp create mode 100644 reactos/base/applications/sndrec32/audio_receiver.cpp create mode 100644 reactos/base/applications/sndrec32/audio_receiver.hpp create mode 100644 reactos/base/applications/sndrec32/audio_resampler_acm.cpp create mode 100644 reactos/base/applications/sndrec32/audio_resampler_acm.hpp create mode 100644 reactos/base/applications/sndrec32/audio_wavein.cpp create mode 100644 reactos/base/applications/sndrec32/audio_wavein.hpp create mode 100644 reactos/base/applications/sndrec32/audio_waveout.cpp create mode 100644 reactos/base/applications/sndrec32/audio_waveout.hpp create mode 100644 reactos/base/applications/sndrec32/bitmap1.bmp create mode 100644 reactos/base/applications/sndrec32/but_end.bmp create mode 100644 reactos/base/applications/sndrec32/but_play.bmp create mode 100644 reactos/base/applications/sndrec32/but_rec.bmp create mode 100644 reactos/base/applications/sndrec32/but_start.bmp create mode 100644 reactos/base/applications/sndrec32/but_stop.bmp create mode 100644 reactos/base/applications/sndrec32/kkaudio.hpp create mode 100644 reactos/base/applications/sndrec32/reactOS_sndrec32.ico create mode 100644 reactos/base/applications/sndrec32/resource.h create mode 100644 reactos/base/applications/sndrec32/small.ico create mode 100644 reactos/base/applications/sndrec32/sndrec32.cpp create mode 100644 reactos/base/applications/sndrec32/sndrec32.h create mode 100644 reactos/base/applications/sndrec32/sndrec32.rbuild create mode 100644 reactos/base/applications/sndrec32/sndrec32.rc create mode 100644 reactos/base/applications/sndrec32/stdafx.h create mode 100644 reactos/base/applications/sndrec32/targetver.h diff --git a/reactos/base/applications/sndrec32/audio_def.hpp b/reactos/base/applications/sndrec32/audio_def.hpp new file mode 100644 index 00000000000..da57f3f4b64 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_def.hpp @@ -0,0 +1,34 @@ +#ifndef _AUDIO_DEF__H_ +#define _AUDIO_DEF__H_ + + +#include + +// +// Defaults +// + +#define _AUDIO_DEFAULT_FORMAT A44100_16BIT_STEREO +#define _AUDIO_DEFAULT_WAVEINBUFFERS 8 +#define _AUDIO_DEFAULT_WAVEINBUFSECS 0.1f +#define _AUDIO_DEFAULT_WAVEOUTBUFFERS 8 +#define _AUDIO_DEFAULT_WAVEOUTBUFSECS 0.1f +#define _AUDIO_DEFAULT_BUFSECS 1.0f + + +// +// Namespace stuff +// + +#define _AUDIO_NAMESPACE_START_ namespace snd { +#define _AUDIO_NAMESPACE_END_ }; +// +// Platform depend stuff +// + +#include +#include //Windows MultiMedia (WINMM) audio apis +#include //codecs stuff +#include //codecs stuff + +#endif //ifdef _AUDIO_DEF__H_ diff --git a/reactos/base/applications/sndrec32/audio_format.cpp b/reactos/base/applications/sndrec32/audio_format.cpp new file mode 100644 index 00000000000..316f54bd8ad --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_format.cpp @@ -0,0 +1,24 @@ +/* + * PROJECT: ReactOS Sound Record Application + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sndrec32/audio_format.cpp + * PURPOSE: Audio Format + * PROGRAMMERS: Marco Pagliaricci + */ + + +#include "stdafx.h" +#include "audio_format.hpp" + +_AUDIO_NAMESPACE_START_ + +// +// Standard audio formats (declared as +// externs in `audio_format.hpp') +// + +audio_format UNNKOWN_FORMAT( 0, 0, 0); +audio_format A44100_16BIT_STEREO( 44100, 16, 2 ); + +_AUDIO_NAMESPACE_END_ + diff --git a/reactos/base/applications/sndrec32/audio_format.hpp b/reactos/base/applications/sndrec32/audio_format.hpp new file mode 100644 index 00000000000..1f620b2e3f2 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_format.hpp @@ -0,0 +1,147 @@ +#ifndef _AUDIOFORMAT__H_ +#define _AUDIOFORMAT__H_ + + + +#include "audio_def.hpp" + + + + +_AUDIO_NAMESPACE_START_ + + + + + + + +class audio_format +{ + protected: + + + unsigned int samples_psec; + unsigned short int bits_psample; + unsigned short int chan; + + + public: + + + // + // Ctors + // + + audio_format( unsigned int samples_per_second, + unsigned short int bits_per_sample, unsigned short int channels ) + + : samples_psec( samples_per_second ), bits_psample( bits_per_sample ), + chan( channels ) + + { } + + + + + + + + // + // Dtor + // + + virtual ~audio_format( void ) + { } + + + + + + + + // + // Operators + // + + bool operator==( audio_format & eq ) const + { + // + // The same audio format is when samples per second, + // bit per sample, and channels mono/stereo are equal. + // + + return (( samples_psec == eq.samples_psec ) + && ( bits_psample == eq.bits_psample ) && ( chan == eq.chan )); + } + + + + + + + + + // + // Public Functions + // + + unsigned int sample_rate( void ) const + { return samples_psec; } + + + unsigned short int bits( void ) const + { return bits_psample; } + + + unsigned short int channels( void ) const + { return chan; } + + + unsigned int byte_rate( void ) const + { return ( samples_psec * chan * ( bits_psample / 8 )); } + + + unsigned int block_align( void ) const + { return ( chan * ( bits_psample / 8 )); } + + + + unsigned int samples_in_seconds( float seconds ) const + { + + return ( unsigned int ) + ((( float )samples_psec * ( float ) chan ) * seconds ); + + } + + unsigned int samples_in_bytes ( unsigned int bytes ) const + { + + return ( bytes / (( bits_psample / 8 ) * chan )); + + } + +}; + + + + +extern audio_format UNKNOWN_FORMAT; +extern audio_format A44100_16BIT_STEREO; + + + + + + + +_AUDIO_NAMESPACE_END_ + + + + + + + +#endif //ifdef _AUDIOFORMAT__H_ diff --git a/reactos/base/applications/sndrec32/audio_membuffer.cpp b/reactos/base/applications/sndrec32/audio_membuffer.cpp new file mode 100644 index 00000000000..0f6580e27d3 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_membuffer.cpp @@ -0,0 +1,501 @@ +/* + * PROJECT: ReactOS Sound Record Application + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sndrec32/audio_membuffer.cpp + * PURPOSE: Audio MemBuffer + * PROGRAMMERS: Marco Pagliaricci + */ + +#include "stdafx.h" +#include "audio_membuffer.hpp" + +_AUDIO_NAMESPACE_START_ + + +void + audio_membuffer::alloc_mem_( unsigned int bytes ) +{ + + // + // Some checking + // + + if ( bytes == 0 ) + return; + + + + + + // + // Checks previsiously alloc'd memory + // and frees it. + // + + if ( audio_data ) + delete[] audio_data; + + + + // + // Allocs new memory and zeros it. + // + + audio_data = new BYTE[ bytes ]; + + + memset( audio_data, 0, bytes * sizeof( BYTE )); + + + + // + // Sets the correct buffer size + // + + buf_size = bytes; + + + init_size = bytes; + + + +} + + +void + audio_membuffer::free_mem_( void ) +{ + + if ( audio_data ) + delete[] audio_data; + + buf_size = 0; + audio_data = 0; + +} + + +void + audio_membuffer::resize_mem_( unsigned int new_size ) +{ + + + if ( new_size == 0 ) + return; + + + // + // The new_size, cannot be <= of the + // `bytes_received' member value of the + // parent class `audio_receiver'. + // We cannot touch received audio data, + // so we have to alloc at least + // bytes_received+1 bytes. + // + // But we can truncate unused memory, so + // `new_size' can be < of `buf_size'. + // + + if ( new_size <= bytes_received ) + return; + + + + + BYTE * new_mem; + + + + // + // Allocs new memory and zeros it. + // + + + new_mem = new BYTE[ new_size ]; + + memset( new_mem, 0, new_size * sizeof( BYTE )); + + + + if ( audio_data ) + { + + + // + // Copies received audio data, and discard + // unused memory. + // + + memcpy( new_mem, audio_data, bytes_received ); + + + + // + // Frees old memory. + // + + delete[] audio_data; + + + + + + // + // Commit new memory. + // + + audio_data = new_mem; + buf_size = new_size; + + + + + } else { + + audio_data = new_mem; + buf_size = new_size; + } + + + if ( buffer_resized ) + buffer_resized( new_size ); + +} + + + + +void + audio_membuffer::truncate_( void ) +{ + + // + // If `buf_size' is already = to the + // `bytes_received' of audio data, then + // this operation is useless; simply return. + // + + if ( bytes_received == buf_size ) + return; + + + + if ( audio_data ) + { + + + // + // Allocs a new buffer. + // + + BYTE * newbuf = new BYTE[ bytes_received ]; + + + + + // + // Copies audio data. + // + + memcpy( newbuf, audio_data, bytes_received ); + + + + // + // Frees old memory. + // + + delete[] audio_data; + + + + // + // Commit the new buffer. + // + + audio_data = newbuf; + buf_size = bytes_received; + + + + // + // Buffer truncation successfull. + // Now the buffer size is exactly big + // as much audio data was received. + // + + + } + + +} + + + + + + +////////////////////////////////////// +/////// Public Functions /////////// +////////////////////////////////////// + + + + +void + audio_membuffer::clear( void ) +{ + + free_mem_(); + + bytes_received = 0; +} + + + +void + audio_membuffer::reset( void ) +{ + + + // + // Frees memory and reset + // to initial state. + // + + clear(); + + + + // + // Alloc memory of size specified + // at the constructor. + // + + alloc_mem_( init_size ); + + +} + +void + audio_membuffer::alloc_bytes( unsigned int bytes ) +{ + + alloc_mem_( bytes ); + +} + + + + +void + audio_membuffer::alloc_seconds( unsigned int secs ) +{ + + alloc_mem_( aud_info.byte_rate() * secs ); + +} + + +void + audio_membuffer::alloc_seconds( float secs ) +{ + + alloc_mem_(( unsigned int )(( float ) aud_info.byte_rate() * secs )); + +} + + + + +void + audio_membuffer::resize_bytes( unsigned int bytes ) +{ + + resize_mem_( bytes ); + +} + + + +void + audio_membuffer::resize_seconds( unsigned int secs ) +{ + + resize_mem_( aud_info.byte_rate() * secs ); + +} + + +void + audio_membuffer::resize_seconds( float secs ) +{ + + resize_mem_(( unsigned int ) + (( float )aud_info.byte_rate() * secs ) + ); + +} + + + + + + +/////////////////////////////////////// +/////// Inherited Functions ///////// +/////////////////////////////////////// + + + + + + + +void + audio_membuffer::audio_receive + ( unsigned char * data, unsigned int size ) +{ + + + // + // If there isn't a buffer, allocs memory for + // it of size*2, and copies audio data arrival. + // + + if (( audio_data == 0 ) || ( buf_size == 0 )) + { + alloc_mem_( size * 2 ); + + memcpy( audio_data, data, size ); + + return; + + } + + + + + + // + // If buffer's free memory is < of `size', + // we have to realloc buffer memory of + // buf_size*2, while free memory is enough + // to contain `size' bytes. + // + // In this case free memory is represented + // by `buf_size - bytes_recorded'. + // + + unsigned int tot_mem = buf_size, + free_mem = buf_size - bytes_received; + + + if ( free_mem < size ) + { + + // + // Calcs new buffer size. + // TODO: flags for other behaviour? + + while ( free_mem < size ) + { + tot_mem *= 2; + + free_mem = tot_mem - bytes_received; + } + + + + // + // Resize buffer memory. + // + + resize_mem_( tot_mem ); + + } + + + // + // Now we have enough free space in the + // buffer, so let's copy audio data arrivals. + // + + memcpy( audio_data + bytes_received, data, size ); + + + + + if ( audio_arrival ) + audio_arrival( aud_info.samples_in_bytes( size )); + + + +} + + +unsigned int + audio_membuffer::read( BYTE * out_buf, unsigned int bytes ) +{ + + // + // Some checking + // + + if ( !audio_data ) + return 0; + + + if ( bytes_played_ >= bytes_received ) + return 0; + + + + unsigned int to_play = + bytes_received - bytes_played_; + + + unsigned int to_copy = + bytes > to_play ? to_play : bytes; + + + // + // Copies the audio data out. + // + + if (( out_buf ) && ( to_copy ) && ( audio_data )) + memcpy( out_buf, audio_data + bytes_played_, to_copy ); + + + // + // Increments the number of total bytes + // played (audio data gone out from the + // `audio_producer' object). + // + + bytes_played_ += bytes; + + + if ( audio_arrival ) + audio_arrival( aud_info.samples_in_bytes( bytes )); + + + // + // Returns the exact size of audio data + // produced. + // + + return to_copy; +} + + +bool + audio_membuffer::finished( void ) +{ + if ( bytes_played_ < bytes_received ) + return false; + else + return true; +} + +_AUDIO_NAMESPACE_END_ diff --git a/reactos/base/applications/sndrec32/audio_membuffer.hpp b/reactos/base/applications/sndrec32/audio_membuffer.hpp new file mode 100644 index 00000000000..4dd27212c57 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_membuffer.hpp @@ -0,0 +1,338 @@ +#ifndef _AUDIOMEMBUFFER__H_ +#define _AUDIOMEMBUFFER__H_ + + + +#include "audio_def.hpp" +#include "audio_receiver.hpp" +#include "audio_format.hpp" +#include "audio_producer.hpp" + + + + +_AUDIO_NAMESPACE_START_ + + + +class audio_membuffer : public audio_receiver, public audio_producer +{ + + + + + + protected: + + BYTE * audio_data; + audio_format aud_info; + unsigned int buf_size; + unsigned int init_size; + + + + // + // Protected Functions + // + + + //allocs N bytes for the audio buffer. + void alloc_mem_( unsigned int ); + + + //frees memory + void free_mem_( void ); + + + //resizes memory, and copies old + //audio data to new-size memory + void resize_mem_( unsigned int ); + + + //truncates and discards unused memory. + //`buf_size' will be the same as `bytes_received'. + void truncate_( void ); + + + + + public: + + + void ( * audio_arrival )( unsigned int ); + void ( * buffer_resized ) ( unsigned int ); + + + // + // Ctors + // + + audio_membuffer( void ) + : audio_data( 0 ), aud_info( _AUDIO_DEFAULT_FORMAT ), + buf_size( 0 ), init_size( 0 ) + { + + // + // Allocs memory for at least 1 or some seconds + // of recording. + // + init_size = ( unsigned int ) + (( float )aud_info.byte_rate() * _AUDIO_DEFAULT_BUFSECS ); + + + alloc_mem_( init_size ); + + + } + + + + audio_membuffer( audio_format aud_fmt ) + : audio_data( 0 ), aud_info( aud_fmt ), buf_size( 0 ), + init_size( 0 ) + { + + // + // Allocs memory for at least 1 or some seconds + // of recording. + // + init_size = ( unsigned int ) + (( float )aud_info.byte_rate() * _AUDIO_DEFAULT_BUFSECS ); + + + alloc_mem_( init_size ); + + } + + + + + audio_membuffer( audio_format aud_fmt, unsigned int seconds ) + : audio_data( 0 ), aud_info( aud_fmt ), buf_size( 0 ), + init_size( 0 ) + { + + // + // Allocs memory for audio recording + // the specified number of seconds. + // + init_size = aud_info.byte_rate() * seconds; + alloc_mem_( init_size ); + + } + + + + audio_membuffer( audio_format aud_fmt, float seconds ) + : audio_data( 0 ), aud_info( aud_fmt ), buf_size( 0 ), + init_size( 0 ) + { + + // + // Allocs memory for audio recording + // the specified number of seconds. + // + init_size = ( unsigned int )(( float ) aud_info.byte_rate() * + seconds <= 0 ? 1 : seconds ); + + + alloc_mem_( init_size ); + + } + + + + + audio_membuffer( unsigned int bytes ) + : audio_data( 0 ), aud_info( _AUDIO_DEFAULT_FORMAT ), + buf_size( 0 ), init_size( 0 ) + { + + // + // Allocs memory for the specified bytes + // + init_size = bytes; + alloc_mem_( init_size ); + + } + + + + + // + // Dtor + // + + virtual ~audio_membuffer( void ) + { + + // + // Frees memory and reset values. + // + + clear(); + + } + + + + + + + + + + // + // Public functions + // + + + + //returns the audio buffer size in bytes. + unsigned int mem_size( void ) const + { return buf_size; } + + + //returns how many audio data has been + //received, in bytes. + unsigned int bytes_recorded( void ) const + { return bytes_received; } + + + //returns the integer number of seconds + //that the buffer can record + unsigned int seconds_total( void ) const + { return buf_size / aud_info.byte_rate(); } + + + //returns the integer number of seconds + //that the buffer can record + unsigned int seconds_recorded( void ) const + { return bytes_received / aud_info.byte_rate(); } + + + //returns the float number of seconds + //that the buffer can record + float fseconds_total( void ) const + { return ( float )(( float ) buf_size / + ( float ) aud_info.byte_rate()); } + + + //returns the float number of seconds + //that has been recorded + float fseconds_recorded( void ) const + { return ( float )(( float ) bytes_received / + ( float ) aud_info.byte_rate()); } + + + unsigned int total_samples( void ) const + { + + return ( aud_info.samples_in_seconds( fseconds_total() )); + + } + + + unsigned int samples_received( void ) const + { + + + return ( aud_info.samples_in_bytes( bytes_received )); + + } + + + + //returns a pointer to the audio buffer + BYTE * audio_buffer( void ) const + { return audio_data; } + + + + //frees memory and resets values. + void clear( void ); + + + audio_format & audinfo( void ) { return aud_info; } + + + //discard audio data, resets values, + //but, instead of clear() which frees memory, + //reset the memory to the initial size, ready + //for receiving "new" audio data. + void reset( void ); + + + //truncates and discards unused memory. + //`buf_size' will be the same as `bytes_received'. + void truncate( void ) + { truncate_( ); }//TODO: fare truncate N bytes + + + //if there is a buffer, discards current buffer + //memory and realloc a new memory buffer with a + //new size expressed in bytes. + void alloc_bytes( unsigned int ); + + + + //if there is a buffer, discards current buffer + //memory and realloc a new memory buffer with a + //new size expressed in seconds, integer and float. + void alloc_seconds( unsigned int ); + void alloc_seconds( float ); + + + + //resizes in bytes the current buffer, + //without discarding previsiously audio data received. + void resize_bytes( unsigned int ); + + + //resizes in seconds the current buffer, + //without discarding previsiously audio data received. + void resize_seconds( unsigned int ); + void resize_seconds( float ); + + + + + + + + + + // + // Inherited Functions from `audio_receiver' + // + + void audio_receive( unsigned char *, unsigned int ); + + + + + // + // Inherited Functions from `audio_buffer' + // + + + unsigned int read( BYTE *, unsigned int ); + bool finished( void ); + + + +}; + + + + + + + +_AUDIO_NAMESPACE_END_ + + + + + +#endif //ifdef _AUDIOMEMBUFFER__H_ diff --git a/reactos/base/applications/sndrec32/audio_producer.cpp b/reactos/base/applications/sndrec32/audio_producer.cpp new file mode 100644 index 00000000000..6afcbb4271b --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_producer.cpp @@ -0,0 +1,12 @@ +/* + * PROJECT: ReactOS Sound Record Application + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sndrec32/audio_producer.cpp + * PURPOSE: Audio Format + * PROGRAMMERS: Marco Pagliaricci + */ + + +#include "StdAfx.h" +#include "audio_producer.hpp" + diff --git a/reactos/base/applications/sndrec32/audio_producer.hpp b/reactos/base/applications/sndrec32/audio_producer.hpp new file mode 100644 index 00000000000..8fe534854ca --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_producer.hpp @@ -0,0 +1,112 @@ +#ifndef _AUDIOAUDBUF__H_ +#define _AUDIOAUDBUF__H_ + + + +#include "audio_def.hpp" + + +_AUDIO_NAMESPACE_START_ + + +class audio_producer +{ + + + protected: + + + unsigned int bytes_played_; + + + + + + public: + + + // + // Ctors + // + + audio_producer ( ) : bytes_played_( 0 ) + { } + + + + + + + + + + // + // Dtor + // + + virtual ~audio_producer( void ) + { } + + + + + // + // Public Functions + // + + + //reads N bytes from the buffer + virtual unsigned int read( BYTE *, unsigned int ) = 0; + + virtual bool finished ( void ) = 0; + + + + + unsigned int bytes_played( void ) const + { + return bytes_played_; + } + + + void set_position( unsigned int pos ) + { + bytes_played_ = pos; + } + + void set_position_start( void ) + { + bytes_played_ = 0 ; + } + + + + void forward( unsigned int bytes ) + { + bytes_played_ += bytes ; + } + + + void backward( unsigned int bytes ) + { + bytes_played_ += bytes ; + } + + void ( * play_finished )( void ); + + + + +}; + + + + +_AUDIO_NAMESPACE_END_ + + + + + + +#endif //ifdef _AUDIOAUDBUF__H_ diff --git a/reactos/base/applications/sndrec32/audio_receiver.cpp b/reactos/base/applications/sndrec32/audio_receiver.cpp new file mode 100644 index 00000000000..77b7c3f3d50 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_receiver.cpp @@ -0,0 +1,17 @@ +/* + * PROJECT: ReactOS Sound Record Application + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sndrec32/audio_producer.cpp + * PURPOSE: Audio Format + * PROGRAMMERS: Marco Pagliaricci + */ + +#include "stdafx.h" +#include "audio_receiver.hpp" + + + + +_AUDIO_NAMESPACE_START_ + +_AUDIO_NAMESPACE_END_ diff --git a/reactos/base/applications/sndrec32/audio_receiver.hpp b/reactos/base/applications/sndrec32/audio_receiver.hpp new file mode 100644 index 00000000000..6d6e693cee1 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_receiver.hpp @@ -0,0 +1,103 @@ +#ifndef _AUDIORECEIVER_DEF__H_ +#define _AUDIORECEIVER_DEF__H_ + + + +#include "audio_def.hpp" + + + + +_AUDIO_NAMESPACE_START_ + + + + +//TODO: differenziare audio_receiver da audio_sink? +//TODO: creare un audio_receiver Tee + + + + + +class audio_receiver +{ + + // + // The `audio_wavein' class, while is + // recording audio, has to access to + // protected members of `audio_receiver' + // such as `bytes_received' protected + // variable. + // + + friend class audio_wavein; + + + + + + + protected: + + + unsigned int bytes_received; + unsigned int status; + + + + public: + + + // + // Ctors + // + + audio_receiver( void ) + : bytes_received( 0 ) + { } + + + + + + // + // Dtor + // + + virtual ~audio_receiver( void ) + { } + + + + + // + // Public Functions + // + + virtual void audio_receive( unsigned char *, unsigned int ) = 0; + + //virtual void start_rec( void ) = 0; + //virtual void stop_rec( void ) = 0; + + + + void set_b_received( unsigned int r ) + { bytes_received = r; } +}; + + + + + + + +_AUDIO_NAMESPACE_END_ + + + + + + + +#endif //ifdef _AUDIORECEIVER_DEF__H_ diff --git a/reactos/base/applications/sndrec32/audio_resampler_acm.cpp b/reactos/base/applications/sndrec32/audio_resampler_acm.cpp new file mode 100644 index 00000000000..fa2617ac177 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_resampler_acm.cpp @@ -0,0 +1,387 @@ +/* + * PROJECT: ReactOS Sound Record Application + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sndrec32/audio_resampler_acm.cpp + * PURPOSE: Audio Resampler + * PROGRAMMERS: Marco Pagliaricci + */ + +#include "stdafx.h" +#include "audio_resampler_acm.hpp" + +_AUDIO_NAMESPACE_START_ + + + ///////////////////////////////////////// + /////// Private Functions //////// + ///////////////////////////////////////// + + + void + audio_resampler_acm::init_( void ) +{ + + + + // + // Zeroing structures + // + + ZeroMemory( &acm_header, sizeof( ACMSTREAMHEADER )); + ZeroMemory( &wformat_src, sizeof( WAVEFORMATEX )); + ZeroMemory( &wformat_dst, sizeof( WAVEFORMATEX )); + + + + + // + // Setting structures sizes + // + + acm_header.cbStruct = sizeof( ACMSTREAMHEADER ); + wformat_src.cbSize = sizeof( WAVEFORMATEX ); + wformat_dst.cbSize = sizeof( WAVEFORMATEX ); + + + + + // + // Setting WAVEFORMATEX structure parameters + // according to `audio_format' in/out classes + // + + wformat_src.wFormatTag = WAVE_FORMAT_PCM; + wformat_src.nSamplesPerSec = audfmt_in.sample_rate(); + wformat_src.nChannels = audfmt_in.channels(); + wformat_src.wBitsPerSample = audfmt_in.bits(); + wformat_src.nAvgBytesPerSec = audfmt_in.byte_rate(); + wformat_src.nBlockAlign = audfmt_in.block_align(); + + + wformat_dst.wFormatTag = WAVE_FORMAT_PCM; + wformat_dst.nSamplesPerSec = audfmt_out.sample_rate(); + wformat_dst.nChannels = audfmt_out.channels(); + wformat_dst.wBitsPerSample = audfmt_out.bits(); + wformat_dst.nAvgBytesPerSec = audfmt_out.byte_rate(); + wformat_dst.nBlockAlign = audfmt_out.block_align(); + + + + // + // Init acm structures completed successfull + // +} + + + + + + + + + + + +///////////////////////////////////////// +/////// Public Functions //////// +///////////////////////////////////////// + + + + +void + audio_resampler_acm::open( void ) +{ + + + MMRESULT err; + + + // + // Opens ACM stream + // + + err = acmStreamOpen( &acm_stream, 0, &wformat_src, &wformat_dst, + 0, 0, 0, ACM_STREAMOPENF_NONREALTIME ); + + + if ( err != MMSYSERR_NOERROR ) + { + //TODO: throw error + printf("acmOpen error: %i\n", err); + + } + + + + // + // Calcs source buffer lenght + // + + src_buflen = ( unsigned int ) + (( float )audfmt_in.byte_rate() * ( float )buf_secs ); + + + + + + + // + // Calcs destination source buffer lenght + // with help of ACM apis + // + + err = acmStreamSize( acm_stream, + src_buflen, &dst_buflen, ACM_STREAMSIZEF_SOURCE ); + + + if ( err != MMSYSERR_NOERROR ) + { + //TODO: throw error + printf("acmSize error\n"); + + } + + + + // + // Initialize ACMSTREAMHEADER structure, + // and alloc memory for source and destination + // buffers. + // + + acm_header.fdwStatus = 0; + acm_header.dwUser = 0; + + + acm_header.pbSrc = ( LPBYTE ) new BYTE [ src_buflen ]; + acm_header.cbSrcLength = src_buflen; + acm_header.cbSrcLengthUsed = 0; + acm_header.dwSrcUser = src_buflen; + + + acm_header.pbDst = ( LPBYTE ) new BYTE [ dst_buflen ]; + acm_header.cbDstLength = dst_buflen; + acm_header.cbDstLengthUsed = 0; + acm_header.dwDstUser = dst_buflen; + + + + + // + // Give ACMSTREAMHEADER initialized correctly to the + // driver. + // + + err = acmStreamPrepareHeader( acm_stream, &acm_header, 0L ); + + if ( err != MMSYSERR_NOERROR ) + { + //TODO: throw error + printf("prep. header error\n"); + } + + + + + // + // ACM stream successfully opened. + // + + stream_opened = true; + +} + + + + +void + audio_resampler_acm::close( void ) +{ + + + MMRESULT err; + + + if ( acm_stream ) + { + + if ( acm_header.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED ) + { + + acm_header.cbSrcLength = src_buflen; + acm_header.cbDstLength = dst_buflen; + + err = acmStreamUnprepareHeader( acm_stream, &acm_header, 0L ); + + + if ( err != MMSYSERR_NOERROR ) + { + + // + // Free buffer memory + // + + if ( acm_header.pbSrc != 0 ) + delete[] acm_header.pbSrc; + + if ( acm_header.pbDst != 0 ) + delete[] acm_header.pbDst; + + + // + // Re-init structures + // + + init_(); + + // + // Updating status + // + + stream_opened = false; + + + //TODO: throw error + + } + } + + + err = acmStreamClose( acm_stream, 0 ); + acm_stream = 0; + + if ( err != MMSYSERR_NOERROR ) + { + + // + // Free buffer memory + // + + if ( acm_header.pbSrc != 0 ) + delete[] acm_header.pbSrc; + + if ( acm_header.pbDst != 0 ) + delete[] acm_header.pbDst; + + + // + // Re-init structures + // + + init_(); + + + // + // Updating status + // + + stream_opened = false; + + + //TODO: throw error! + + } + + + }//if acm_stream != 0 + + + + + + + // + // Free buffer memory + // + + if ( acm_header.pbSrc != 0 ) + delete[] acm_header.pbSrc; + + if ( acm_header.pbDst != 0 ) + delete[] acm_header.pbDst; + + + // + // Re-init structures + // + + init_(); + + + // + // Updating status + // + + stream_opened = false; + + + + // + // ACM sream successfully closed. + // + + +} + + + + +void + audio_resampler_acm::audio_receive( unsigned char * data, unsigned int size ) +{ + + MMRESULT err; + + // + // Checking for acm stream opened + // + + if ( stream_opened ) + { + + + // + // Copy audio data from extern to + // internal source buffer + // + + memcpy( acm_header.pbSrc, data, size ); + + + acm_header.cbSrcLength = size; + acm_header.cbDstLengthUsed = 0; + + err = acmStreamConvert( acm_stream, &acm_header, ACM_STREAMCONVERTF_BLOCKALIGN ); + + if ( err != MMSYSERR_NOERROR ) + { + //TODO: throw error + printf("acm convert error\n"); + + } + + + // + // Wait for sound conversion + // + + while(( ACMSTREAMHEADER_STATUSF_DONE & acm_header.fdwStatus ) == 0 ); + + + printf("Processed successfully %lu bytes of audio.\n", acm_header.cbDstLengthUsed ); + + + + // + // Copy resampled audio, to destination buffer. + // + + //memcpy( pbOutputData, acm_header.pbDst, acm_header.cbDstLengthUsed ); + + + } + +} + +_AUDIO_NAMESPACE_END_ diff --git a/reactos/base/applications/sndrec32/audio_resampler_acm.hpp b/reactos/base/applications/sndrec32/audio_resampler_acm.hpp new file mode 100644 index 00000000000..bce7b32ae9e --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_resampler_acm.hpp @@ -0,0 +1,99 @@ +#ifndef _AUDIORESAMPLERACM__H_ +#define _AUDIORESAMPLERACM__H_ + + + +#include "audio_def.hpp" +#include "audio_receiver.hpp" +#include "audio_format.hpp" + + + + +_AUDIO_NAMESPACE_START_ + + + +//TODO: inherit from a base resampler? +class audio_resampler_acm : public audio_receiver +{ + + private: + void init_( void ); + + + protected: + + + HACMSTREAM acm_stream; + ACMSTREAMHEADER acm_header; + DWORD src_buflen; + DWORD dst_buflen; + bool stream_opened; + + audio_format audfmt_in; + audio_format audfmt_out; + + float buf_secs; + + WAVEFORMATEX wformat_src; + WAVEFORMATEX wformat_dst; + + + + + public: + + + // + // Ctors + // + + audio_resampler_acm( audio_format fmt_in, audio_format fmt_out ) + : acm_stream( 0 ), src_buflen( 0 ), dst_buflen( 0 ), + stream_opened( false ), audfmt_in( fmt_in ), audfmt_out( fmt_out ), + buf_secs( _AUDIO_DEFAULT_BUFSECS ) + + { + + + init_(); + + + } + + + + + + // + // Dtor + // + + ~audio_resampler_acm( void ) + { } + + + + // + // Public functions + // + + void open( void ); + void close( void ); + + + + void audio_receive( unsigned char *, unsigned int ); + + + +}; + + +_AUDIO_NAMESPACE_END_ + + + + +#endif //ifdef _AUDIORESAMPLERACM_H_ diff --git a/reactos/base/applications/sndrec32/audio_wavein.cpp b/reactos/base/applications/sndrec32/audio_wavein.cpp new file mode 100644 index 00000000000..4d92f24e4e1 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_wavein.cpp @@ -0,0 +1,880 @@ +/* +* PROJECT: ReactOS Sound Record Application +* LICENSE: GPL - See COPYING in the top level directory +* FILE: base/applications/sndrec32/audio_wavein.cpp +* PURPOSE: Audio WaveIn +* PROGRAMMERS: Marco Pagliaricci +*/ + +#include "stdafx.h" +#include "audio_wavein.hpp" + + + +_AUDIO_NAMESPACE_START_ + + + void + audio_wavein::init_( void ) +{ + ZeroMemory(( LPVOID ) &wave_format, + sizeof( WAVEFORMATEX )); + + wave_format.cbSize = sizeof( WAVEFORMATEX ); + + wavein_handle = 0; + recthread_id = 0; + wakeup_recthread = 0; + + buf_secs = _AUDIO_DEFAULT_WAVEINBUFSECS; + + + status = WAVEIN_NOTREADY; +} + + +void + audio_wavein::alloc_buffers_mem_( unsigned int buffs, float secs ) +{ + + + unsigned int + onebuf_size = 0, tot_size = 0; + + + // + // Release old memory + // + + if ( main_buffer ) + delete[] main_buffer; + + + if ( wave_headers ) + delete[] wave_headers; + + + + // + // Calcs size of the buffers + // + + onebuf_size = ( unsigned int ) + (( float )aud_info.byte_rate() * secs ); + + + tot_size = onebuf_size * buffs; + + + + + // + // Allocs memory for the audio buffers + // + + main_buffer = new BYTE [ tot_size ]; + + + + // + // Allocs memory for the `WAVEHDR' structures. + // + + wave_headers = ( WAVEHDR * ) + new BYTE [ sizeof( WAVEHDR ) * buffs ]; + + + + // + // Zeros memory. + // + + ZeroMemory( main_buffer, tot_size ); + + ZeroMemory( wave_headers, + sizeof( WAVEHDR ) * buffs ); + + + // + // Updates total size of the buffers. + // + + mb_size = tot_size; + +} + + +void + audio_wavein::free_buffers_mem_( void ) +{ + + + // + // Frees memory + // + + if ( main_buffer ) + delete[] main_buffer; + + + if ( wave_headers ) + delete[] wave_headers; + + + main_buffer = 0; + wave_headers = 0; + +} + + +void + audio_wavein::init_headers_( void ) +{ + + + + // + // If there is no memory for memory or + // headers, simply return. + // + + if (( !wave_headers ) || ( !main_buffer )) + return; + + + // + // This is the size for one buffer + // + + DWORD buf_sz = mb_size / buffers; + + + + // + // This is the base address for one buffer + // + + BYTE * buf_addr = main_buffer; + + + // + // Initializes headers. + // + + for ( unsigned int i = 0; i < buffers; ++i ) + { + wave_headers[ i ].dwBufferLength = mb_size / buffers; + wave_headers[ i ].lpData = ( LPSTR ) buf_addr; + + buf_addr += buf_sz; + } + +} + + +void + audio_wavein::prep_headers_( void ) +{ + MMRESULT err; + bool error = false; + + + // + // If there is no memory for memory or + // headers, throw error. + // + + if (( !wave_headers ) + || ( !main_buffer ) || ( !wavein_handle )) + {} //TODO: throw error! + + + + for ( unsigned int i = 0; i < buffers; ++i ) + { + err = waveInPrepareHeader( wavein_handle, + &wave_headers[ i ], sizeof( WAVEHDR )); + + + if ( err != MMSYSERR_NOERROR ) + error = true; + + } + + + if ( error ) + MessageBox( 0, TEXT("waveInPrepareHeader Error."), 0, 0 ); + + + +} + +void + audio_wavein::unprep_headers_( void ) +{ + MMRESULT err; + bool error = false; + + + + // + // If there is no memory for memory or + // headers, throw error. + // + + if (( !wave_headers ) + || ( !main_buffer ) || ( !wavein_handle )) + {} //TODO: throw error! + + + + for ( unsigned int i = 0; i < buffers; ++i ) + { + err = waveInUnprepareHeader( wavein_handle, + &wave_headers[ i ], sizeof( WAVEHDR )); + + + if ( err != MMSYSERR_NOERROR ) + error = true; + + } + + + if ( error ) + MessageBox( 0, TEXT("waveInUnPrepareHeader Error."), 0, 0 ); + +} + + +void + audio_wavein::add_buffers_to_driver_( void ) +{ + MMRESULT err; + bool error = false; + + + + // + // If there is no memory for memory or + // headers, throw error. + // + + if (( !wave_headers ) + || ( !main_buffer ) || ( !wavein_handle )) + {} //TODO: throw error! + + + + + for ( unsigned int i = 0; i < buffers; ++i ) + { + err = waveInAddBuffer( wavein_handle, + &wave_headers[ i ], sizeof( WAVEHDR )); + + + if ( err != MMSYSERR_NOERROR ) + error = true; + + } + + + if ( error ) + MessageBox( 0, TEXT("waveInAddBuffer Error."), 0, 0 ); + +} + + + +void + audio_wavein::close( void ) +{ + + + + + // + // If wavein object is already in the status + // NOTREADY, nothing to do. + // + + if ( status == WAVEIN_NOTREADY ) + return; + + + + // + // If the wavein is recording, + // then stop recording and close it. + // + + if ( status == WAVEIN_RECORDING ) + stop_recording(); + + + // + // Updating status. + // + + status = WAVEIN_NOTREADY; + + + + + // + // Wakeing up recording thread, so it + // can receive the `MM_WIM_CLOSE' message + // then dies. + // + if ( wakeup_recthread ) + SetEvent( wakeup_recthread ); + + + + // + // Closing wavein stream + // + + while (( waveInClose( wavein_handle )) + != MMSYSERR_NOERROR ) Sleep( 1 ); + + + + // + // Release buffers memory. + // + + free_buffers_mem_(); + + + // + // Re-initialize variables to the + // initial state. + // + + init_(); + +} + + +void + audio_wavein::open( void ) +{ + + MMRESULT err; + HANDLE recthread_handle = 0; + + + // + // Checkin the status of the object + // + + if ( status != WAVEIN_NOTREADY ) + {} //TODO: throw error + + + + // + // Creating the EVENT object that will be signaled + // when the recording thread has to wake up. + // + + wakeup_recthread = + CreateEvent( 0, FALSE, FALSE, 0 ); + + + data_flushed_event = + CreateEvent( 0, FALSE, FALSE, 0 ); + + + + if (( !wakeup_recthread ) || ( !data_flushed_event )) + { + + + status = WAVEIN_ERR; + + MessageBox( 0, TEXT("Thread Error."), 0, 0 ); + + //TODO: throw error + } + + + + // + // Inialize buffers for recording audio + // data from the wavein audio line. + // + + alloc_buffers_mem_( buffers, buf_secs ); + init_headers_(); + + + + + + + // + // Sound format that will be captured by wavein + // + + wave_format.wFormatTag = WAVE_FORMAT_PCM; + + wave_format.nChannels = aud_info.channels(); + wave_format.nSamplesPerSec = aud_info.sample_rate(); + wave_format.wBitsPerSample = aud_info.bits(); + wave_format.nBlockAlign = aud_info.block_align(); + wave_format.nAvgBytesPerSec = aud_info.byte_rate(); + + + + // + // Creating the recording thread + // + + recthread_handle = + CreateThread( NULL, + 0, + audio_wavein::recording_procedure, + ( PVOID ) this, + 0, + &recthread_id + ); + + + + // + // Checking thread handle + // + + if ( !recthread_handle ) + { + + // + // Updating status + // + + status = WAVEIN_ERR; + + MessageBox( 0, TEXT("Thread Error."), 0, 0 ); + //TODO: throw error + + } + + + // + // We don't need the thread handle anymore, + // so we can close it from now. (We'll just + // need the thread ID for the `waveInOpen' API) + // + + CloseHandle( recthread_handle ); + + + + // + // Opening audio line wavein + // + + err = waveInOpen( &wavein_handle, + 0, + &wave_format, + recthread_id, + 0, + CALLBACK_THREAD + ); + + + if ( err != MMSYSERR_NOERROR ) + { + + + // + // Updating status + // + + status = WAVEIN_ERR; + + if ( err == WAVERR_BADFORMAT ) + MessageBox( 0, TEXT("waveInOpen Error"), 0, 0 ); + + + //TODO: throw error + } + + + // + // Update object status + // + + status = WAVEIN_READY; + + + + // + // Now `audio_wavein' object is ready + // for audio recording! + // +} + + + +void + audio_wavein::start_recording( void ) +{ + + MMRESULT err; + BOOL ev; + + + + if (( status != WAVEIN_READY ) + && ( status != WAVEIN_STOP )) + {} //TODO: throw error + + + + + // + // Updating to the recording status + // + + status = WAVEIN_RECORDING; + + + + + // + // Let's prepare header of type WAVEHDR that + // we will pass to the driver with our + // audio informations, and buffer informations. + // + + prep_headers_(); + + + + // + // The waveInAddBuffer function sends an input buffer + // to the given waveform-audio input device. + // When the buffer is filled, the application is notified. + // + + add_buffers_to_driver_(); + + + + + + // + // Signaling event for waking up + // the recorder thread. + // + + ev = SetEvent( wakeup_recthread ); + + + if ( !ev ) + { + + + MessageBox( 0, TEXT("Event Error."), 0, 0 ); + + } + + + // + // Start recording + // + + + err = waveInStart( wavein_handle ); + + + if ( err != MMSYSERR_NOERROR ) + { + + // + // Updating status + // + + status = WAVEIN_ERR; + + MessageBox( 0, TEXT("waveInStart Error."), 0, 0 ); + + + //TODO: throw error + + } + +} + + + +void + audio_wavein::stop_recording( void ) +{ + + + MMRESULT err; + DWORD wait; + + + if ( status != WAVEIN_RECORDING ) + return; + + + + status = WAVEIN_FLUSHING; + + + if ( data_flushed_event ) + wait = WaitForSingleObject( + data_flushed_event, INFINITE + ); + + + + // + // waveInReset will make all pending buffer as done. + // + + err = waveInReset( wavein_handle ); + + + if ( err != MMSYSERR_NOERROR ) + { + + //TODO: throw error + + MessageBox( 0, TEXT("waveInReset Error."), 0, 0 ); + + + + } + + + + // + // Stop recording. + // + + err = waveInStop( wavein_handle ); + + + if ( err != MMSYSERR_NOERROR ) + { + + //TODO: throw error + + MessageBox( 0, TEXT("waveInStop Error."), 0, 0 ); + + + + } + + + // + // The waveInUnprepareHeader function cleans up the + // preparation performed by the waveInPrepareHeader function. + // + + unprep_headers_(); + + + + + + + + + + + + status = WAVEIN_STOP; + +} + + + +DWORD WINAPI + audio_wavein::recording_procedure( LPVOID arg ) +{ + + + MSG msg; + WAVEHDR * phdr; + DWORD wait; + audio_wavein * _this = ( audio_wavein * ) arg; + + + + + // + // Check the arg pointer + // + + if ( _this == 0 ) + return 0; + + + + // + // The thread can go to sleep for now. + // It will be wake up only when there is audio data + // to be recorded. + // + + if ( _this->wakeup_recthread ) + wait = WaitForSingleObject( + _this->wakeup_recthread, INFINITE + ); + + + + + + + // + // If status of the `audio_wavein' object + // is not ready or recording the thread can exit. + // + + if (( _this->status != WAVEIN_READY ) && + ( _this->status != WAVEIN_RECORDING )) + return 0; + + + + + + + + // + // Entering main polling loop + // + + while ( GetMessage( &msg, 0, 0, 0 )) + { + + switch ( msg.message ) + { + + case MM_WIM_DATA: + + phdr = ( WAVEHDR * ) msg.lParam; + + if (( _this->status == WAVEIN_RECORDING ) + || ( _this->status == WAVEIN_FLUSHING )) + { + + // + // Flushes recorded audio data to + // the `audio_receiver' object. + // + + _this->audio_rcvd.audio_receive( + ( unsigned char * )phdr->lpData, + phdr->dwBytesRecorded + ); + + + // + // Updating `audio_receiver' total + // bytes received _AFTER_ calling + // `audio_receive' function. + // + + _this->audio_rcvd.bytes_received += + phdr->dwBytesRecorded; + + + + + // + // If status is not flushing data, then + // we can re-add the buffer for reusing it. + // Otherwise, if we are flushing pending data, + // we cannot re-add buffer because we don't need + // it anymore + // + + if ( _this->status != WAVEIN_FLUSHING ) + { + + // + // Let the audio driver reuse the buffer + // + + waveInAddBuffer( _this->wavein_handle, + phdr, sizeof( WAVEHDR )); + + + } else { + + // + // If we are flushing pending data, we have + // to prepare to stop recording. + // Set WAVEHDR flag to 0, and fires the event + // `data_flushed_event', that will wake up + // the main thread that is sleeping into + // wavein_in::stop_recording() member function, + // waiting the last `MM_WIM_DATA' message that + // contain pending data. + // + + + + + phdr->dwFlags = 0; + + SetEvent( _this->data_flushed_event ); + + + // + // The recording is gooing to stop, so the + // recording thread can go to sleep! + // + + wait = WaitForSingleObject( + _this->wakeup_recthread, INFINITE ); + + } + + + }//if WAVEIN_RECORDING || WAVEIN_FLUSHING + + break; + + + + + + + + + + case MM_WIM_CLOSE: + + // + // The thread can exit now. + // + + return 0; + + break; + + + + } //end switch( msg.message ) + + } //end while( GetMessage( ... )) + + return 0; +} + + + + + + +_AUDIO_NAMESPACE_END_ diff --git a/reactos/base/applications/sndrec32/audio_wavein.hpp b/reactos/base/applications/sndrec32/audio_wavein.hpp new file mode 100644 index 00000000000..3c73077729e --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_wavein.hpp @@ -0,0 +1,271 @@ +#ifndef _AUDIOWAVEIN_H_ +#define _AUDIOWAVEIN_H_ + + + +#include "audio_def.hpp" +#include "audio_format.hpp" +#include "audio_receiver.hpp" + + + +_AUDIO_NAMESPACE_START_ + + + + +enum audio_wavein_status { WAVEIN_NOTREADY, WAVEIN_READY, + WAVEIN_RECORDING, WAVEIN_ERR, + WAVEIN_STOP, WAVEIN_FLUSHING + + }; + + + + + +class audio_wavein +{ + private: + + + + // + // The new recording thread sends message to this procedure + // about open recording, close, and sound data recorded + // + + static DWORD WINAPI recording_procedure( LPVOID ); + + // + // When this event is signaled, then the previsiously created + // recording thread will wake up and start recording audio + // and will pass audio data to an `audio_receiver' object. + // + + HANDLE wakeup_recthread; + HANDLE data_flushed_event; + + + + + protected: + + +//TODO: puts these structs in private?! + + + + + // + // Audio wavein device stuff + // + + WAVEFORMATEX wave_format; + WAVEHDR * wave_headers; + HWAVEIN wavein_handle; + + + + + + audio_format aud_info; + + audio_receiver & audio_rcvd; + + + + // + // Audio Recorder Thread id + // + + DWORD recthread_id; + + + + + // + // Object status + // + + audio_wavein_status status; + + + + + + + + // + // How many seconds of audio + // can record the internal buffer + // before flushing audio data + // to the `audio_receiver' class? + // + + float buf_secs; + + + // + // The temporary buffers for the audio + // data incoming from the wavein device + // and its size, and its total number. + // + + BYTE * main_buffer; + unsigned int mb_size; + + unsigned int buffers; + + + + + + // + // Protected Functions + // + + + //initialize all structures and variables. + void init_( void ); + + void alloc_buffers_mem_( unsigned int, float ); + void free_buffers_mem_( void ); + + void init_headers_( void ); + void prep_headers_( void ); + void unprep_headers_( void ); + void add_buffers_to_driver_( void ); + + + + + + + + public: + + + // + // Ctors + // + + audio_wavein( + const audio_format & a_info, audio_receiver & a_receiver ) + + : wave_headers( 0 ), + aud_info( a_info ), audio_rcvd( a_receiver ), + status( WAVEIN_NOTREADY ), main_buffer( 0 ), mb_size( 0 ), + buffers( _AUDIO_DEFAULT_WAVEINBUFFERS ) + { + + // + // Initializing internal wavein data + // + + + init_(); + + aud_info = a_info; + } + + + + + + + + // + // Dtor + // + + ~audio_wavein( void ) + { + + //close(); TODO! + + } + + + + // + // Public functions + // + + void open( void ); + void close ( void ); + + + void start_recording( void ); + void stop_recording( void ); + + + + audio_wavein_status current_status ( void ) const + { + return status; + } + + float buffer_secs( void ) const + { return buf_secs; } + + + void buffer_secs( float bsecs ) + { + // + // Some checking + // + + if ( bsecs <= 0 ) + return; + + + // + // Set seconds lenght for each + // buffer. + // + + buf_secs = bsecs; + } + + + unsigned int total_buffers( void ) const + { return buffers; } + + + + void total_buffers( unsigned int tot_bufs ) + { + + // + // Some checking + // + + if ( tot_bufs == 0 ) + return; + + + // + // Sets the number of total buffers. + // + + buffers = tot_bufs; + } + + + audio_format format( void ) const + { return aud_info; } + + + +}; + + + + +_AUDIO_NAMESPACE_END_ + + + + +#endif //ifdef _AUDIOWAVEIN_H_ diff --git a/reactos/base/applications/sndrec32/audio_waveout.cpp b/reactos/base/applications/sndrec32/audio_waveout.cpp new file mode 100644 index 00000000000..18405b3d0b3 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_waveout.cpp @@ -0,0 +1,889 @@ +/* + * PROJECT: ReactOS Sound Record Application + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sndrec32/audio_waveout.cpp + * PURPOSE: Audio WaveOut + * PROGRAMMERS: Marco Pagliaricci + */ + + +#include "stdafx.h" +#include "audio_waveout.hpp" + + +_AUDIO_NAMESPACE_START_ + + + +void +audio_waveout::init_( void ) +{ + + ZeroMemory(( LPVOID ) &wave_format, + sizeof( WAVEFORMATEX )); + + wave_format.cbSize = sizeof( WAVEFORMATEX ); + + waveout_handle = 0; + + playthread_id = 0; + wakeup_playthread = 0; + + buf_secs = _AUDIO_DEFAULT_WAVEOUTBUFSECS; + + + status = WAVEOUT_NOTREADY; + +} + + + + +void +audio_waveout::alloc_buffers_mem_( unsigned int buffs, float secs ) +{ + + + unsigned int + onebuf_size = 0, tot_size = 0; + + + // + // Release old memory + // + + if ( main_buffer ) + delete[] main_buffer; + + + if ( wave_headers ) + delete[] wave_headers; + + + + // + // Calcs size of the buffers + // + + onebuf_size = ( unsigned int ) + (( float )aud_info.byte_rate() * secs ); + + + tot_size = onebuf_size * buffs; + + + + + // + // Allocs memory for the audio buffers + // + + main_buffer = new BYTE [ tot_size ]; + + + + // + // Allocs memory for the `WAVEHDR' structures. + // + + wave_headers = ( WAVEHDR * ) + new BYTE [ sizeof( WAVEHDR ) * buffs ]; + + + + // + // Zeros memory. + // + + ZeroMemory( main_buffer, tot_size ); + + ZeroMemory( wave_headers, + sizeof( WAVEHDR ) * buffs ); + + + // + // Updates total size of the buffers. + // + + mb_size = tot_size; +} + + +void +audio_waveout::init_headers_( void ) +{ + + + + // + // If there is no memory for memory or + // headers, simply return. + // + + if (( !wave_headers ) || ( !main_buffer )) + return; + + + // + // This is the size for one buffer + // + + DWORD buf_sz = mb_size / buffers; + + + + // + // This is the base address for one buffer + // + + BYTE * buf_addr = main_buffer; + + + + ZeroMemory( wave_headers, sizeof( WAVEHDR ) * buffers ); + + + // + // Initializes headers. + // + + for ( unsigned int i = 0; i < buffers; ++i ) + { + + // + // Sets the correct base address and + // lenght for the little buffer. + // + + wave_headers[ i ].dwBufferLength = mb_size / buffers; + wave_headers[ i ].lpData = ( LPSTR ) buf_addr; + + // + // Unsets the WHDR_DONE flag. + // + + wave_headers[ i ].dwFlags &= ~WHDR_DONE; + + + + // + // Sets the WAVEHDR user data with an + // unique little buffer ID# + // + + wave_headers[ i ].dwUser = ( unsigned int ) i; + + + + // + // Increments little buffer base address. + // + + buf_addr += buf_sz; + } + +} + + +void +audio_waveout::prep_headers_( void ) +{ + MMRESULT err; + bool error = false; + + + // + // If there is no memory for memory or + // headers, throw error. + // + + if (( !wave_headers ) + || ( !main_buffer ) || ( !waveout_handle )) + {} //TODO: throw error! + + + + for ( unsigned int i = 0; i < buffers; ++i ) + { + err = waveOutPrepareHeader( waveout_handle, + &wave_headers[ i ], sizeof( WAVEHDR )); + + + if ( err != MMSYSERR_NOERROR ) + error = true; + + } + + + if ( error ) + {} //TODO: throw error indicating which + //header i-th is errorneous + + + +} + +void +audio_waveout::unprep_headers_( void ) +{ + MMRESULT err; + bool error = false; + + + + // + // If there is no memory for memory or + // headers, throw error. + // + + if (( !wave_headers ) + || ( !main_buffer ) || ( !waveout_handle )) + {} //TODO: throw error! + + + + for ( unsigned int i = 0; i < buffers; ++i ) + { + err = waveOutUnprepareHeader( waveout_handle, + &wave_headers[ i ], sizeof( WAVEHDR )); + + + if ( err != MMSYSERR_NOERROR ) + error = true; + + } + + + if ( error ) + {} //TODO: throw error indicating which + //header i-th is errorneous + +} + + + + + + + + + +void +audio_waveout::free_buffers_mem_( void ) +{ + + + + // + // Frees memory + // + + if ( main_buffer ) + delete[] main_buffer; + + + if ( wave_headers ) + delete[] wave_headers; + + + main_buffer = 0; + wave_headers = 0; + + + + +} + + + + + + + + + + + + + + +void +audio_waveout::open( void ) +{ + + MMRESULT err; + HANDLE playthread_handle = 0; + + + // + // Checkin the status of the object + // + + if ( status != WAVEOUT_NOTREADY ) + {} //TODO: throw error + + + // + // Creating the EVENT object that will be signaled + // when the playing thread has to wake up. + // + + wakeup_playthread = + CreateEvent( 0, FALSE, FALSE, 0 ); + + if ( !wakeup_playthread ) + { + + + status = WAVEOUT_ERR; + + //TODO: throw error + } + + + + // + // Inialize buffers for recording audio + // data from the wavein audio line. + // + + alloc_buffers_mem_( buffers, buf_secs ); + init_headers_(); + + + + + + + // + // Sound format that will be captured by wavein + // + + wave_format.wFormatTag = WAVE_FORMAT_PCM; + + wave_format.nChannels = aud_info.channels(); + wave_format.nSamplesPerSec = aud_info.sample_rate(); + wave_format.wBitsPerSample = aud_info.bits(); + wave_format.nBlockAlign = aud_info.block_align(); + wave_format.nAvgBytesPerSec = aud_info.byte_rate(); + + + + // + // Creating the recording thread + // + + playthread_handle = + CreateThread( NULL, + 0, + audio_waveout::playing_procedure, + ( PVOID ) this, + 0, + &playthread_id + ); + + + + // + // Checking thread handle + // + + if ( !playthread_handle ) + { + + // + // Updating status + // + + status = WAVEOUT_ERR; + //TODO: throw error + + } + + + // + // We don't need the thread handle anymore, + // so we can close it from now. (We'll just + // need the thread ID for the `waveInOpen' API) + // + + CloseHandle( playthread_handle ); + + + + // + // Reset the `audio_source' to the start + // position. + // + + audio_buf.set_position_start(); + + + + + // + // Opens the WAVE_OUT device. + // + + err = waveOutOpen( + &waveout_handle, + WAVE_MAPPER, + &wave_format, + playthread_id, + 0, + CALLBACK_THREAD | WAVE_ALLOWSYNC + ); + + + + if ( err != MMSYSERR_NOERROR ) + { + MessageBox(0, _T("waveOutOpen Error"), 0, 0); + //TODO: throw error + + } + + + + + status = WAVEOUT_READY; + + +} + + + +void +audio_waveout::play( void ) +{ + + + MMRESULT err; + unsigned int i; + BOOL ev; + + + if ( !main_buffer ) + { return; } //TODO; throw error, or assert + + + + + // + // If the status is PAUSED, we have to + // resume the audio playing. + // + if ( status == WAVEOUT_PAUSED ) + { + + // + // Updates status. + // + + status = WAVEOUT_PLAYING; + + + // + // Tells to the driver to resume + // audio playing. + // + + waveOutRestart( waveout_handle ); + + + // + // Wakeup playing thread. + // + + ev = SetEvent( wakeup_playthread ); + + return; + + } //if status == WAVEOUT_PAUSED + + + + + + if ( status != WAVEOUT_READY ) + return; + + + + + // + // Prepares WAVEHDR structures. + // + + prep_headers_(); + + + + // + // Sets correct status. + // + + status = WAVEOUT_PLAYING; + + + + // + // Reads the audio from the start. + // + + audio_buf.set_position_start(); + + + + + // + // Reads the first N bytes from the audio + // buffer, where N = the total size of all + // little buffers. + // + + audio_buf.read( main_buffer, mb_size ); + + + + + + + // + // Wakeup the playing thread. + // + + ev = SetEvent( wakeup_playthread ); + + + + + // + // Sends all the little buffers to the + // audio driver, so it can play the sound + // data. + // + + for ( i = 0; i < buffers; ++ i ) + { + + + err = waveOutWrite( waveout_handle, &wave_headers[ i ], sizeof( WAVEHDR )); + + if ( err != MMSYSERR_NOERROR ) + { + + + MessageBox(0, _T("waveOutWrite Error"), 0, 0); + + //TODO: throw error + } + + } + +} + + +void +audio_waveout::pause( void ) +{ + + MMRESULT err; + + + // + // If the waveout object is not playing audio, + // do nothing. + // + + if ( status == WAVEOUT_PLAYING ) + { + + // + // Updating status. + // + + status = WAVEOUT_PAUSED; + + + // + // Tells to audio driver to pause audio. + // + + err = waveOutPause( waveout_handle ); + + + if ( err != MMSYSERR_NOERROR ) + { + + MessageBox(0, _T("waveOutPause Error"), 0, 0); + //TODO: throw error + + } + + } + +} + + +void +audio_waveout::stop( void ) +{ + + MMRESULT err; + + + status = WAVEOUT_STOP; + + + err = waveOutReset( waveout_handle ); + + + + if ( err != MMSYSERR_NOERROR ) + { + + MessageBox(0, _T("err waveout reset.\n"),_T("ERROR"), 0); + //TODO: throw error + + } + + + + // + // Sets the start position of the audio + // buffer. + // + + audio_buf.set_position_start(); + + + unprep_headers_(); + + + init_headers_(); + + + status = WAVEOUT_READY; + +} + +void +audio_waveout::close( void ) +{ + + MMRESULT err; + + + // + // If the `wave_out' object is playing audio, + // or it is in paused state, we have to call + // the `stop' member function, to flush + // pending buffers. + // + + if (( status == WAVEOUT_PLAYING ) + || ( status== WAVEOUT_PAUSED )) + { + + stop(); + + } + + + + // + // When we have flushed all pending buffers, + // the wave out handle can be successfully closed. + // + + err = waveOutClose( waveout_handle ); + + + if ( err != MMSYSERR_NOERROR ) + { + + MessageBox(0, _T("waveOutClose Error"), 0, 0); + //TODO: throw error + + } + + free_buffers_mem_(); + +} + + +DWORD WINAPI +audio_waveout::playing_procedure( LPVOID arg ) +{ + MSG msg; + WAVEHDR * phdr; + DWORD wait; + MMRESULT err; + audio_waveout * _this = ( audio_waveout * ) arg; + unsigned int read_size; + + + + // + // Check the arg pointer + // + + if ( _this == 0 ) + return 0; + + + + // + // The thread can go to sleep for now. + // It will be wake up only when there is audio data + // to be recorded. + // + + if ( _this->wakeup_playthread ) + wait = WaitForSingleObject( + _this->wakeup_playthread, INFINITE + ); + + + + // + // Entering main polling loop + // + + while ( GetMessage( &msg, 0, 0, 0 )) + { + + switch ( msg.message ) + { + + case MM_WOM_DONE: + + phdr = ( WAVEHDR * ) msg.lParam; + + + // + // If the status of the `wave_out' object + // is different than playing, then the thread + // can go to sleep. + // + + if (( _this->status != WAVEOUT_PLAYING ) + && ( _this->wakeup_playthread )) + { + + wait = WaitForSingleObject( + _this->wakeup_playthread, + INFINITE + ); + } + + //TODO: quando il thread si risveglia, deve + //entrare nel prossimo if o no? o metter un else { ? + + + + if ( phdr->dwFlags & WHDR_DONE ) + { + + read_size = + _this->audio_buf.read( + ( BYTE * ) phdr->lpData, + phdr->dwBufferLength + ); + + + if ( read_size ) + { + phdr->dwBufferLength = read_size; + + phdr->dwFlags &= ~WHDR_DONE; + + err = waveOutWrite( + _this->waveout_handle, + phdr, + sizeof( WAVEHDR ) + ); + + if ( err != MMSYSERR_NOERROR ) + { + MessageBox(0, _T("waveOutWrite Error"), 0, 0); + //TODO: throw error + } + + + } else { + + // + // Here `read_sizep' is 0 + // + + if ( phdr->dwUser == ( _this->buffers - 1 )) + { + + // + // Here `read_size' and the buffer user + // data, that contain a buffer ID#, + // is equal to the number of the total + // buffers - 1. This means that this is the + // _LAST_ little buffer that has been played + // by the audio driver. We can STOP the + // `wave_out' object now, or restart the + // sound playing, if we have a infinite loop. + // + + + _this->stop(); + + // + // Let the thread go to sleep. + // + + if ( _this->audio_buf.play_finished ) + _this->audio_buf.play_finished(); + + + if ( _this->wakeup_playthread ) + wait = WaitForSingleObject( + _this->wakeup_playthread, + INFINITE + ); + + } + + } //if read_size != 0 + + } //( phdr->dwFlags & WHDR_DONE ) + + + break; // end case + + + + case MM_WOM_CLOSE: + // + // The thread can exit now. + // + + return 0; + + break; + + + case MM_WOM_OPEN: + + // + // Do nothing. + // + + break; + + + } //end switch( msg.message ) + + } //end while( GetMessage( ... )) + + return 0; +} + +_AUDIO_NAMESPACE_END_ diff --git a/reactos/base/applications/sndrec32/audio_waveout.hpp b/reactos/base/applications/sndrec32/audio_waveout.hpp new file mode 100644 index 00000000000..fd8debe8168 --- /dev/null +++ b/reactos/base/applications/sndrec32/audio_waveout.hpp @@ -0,0 +1,186 @@ +#ifndef _AUDIOWAVEOUT__H_ +#define _AUDIOWAVEOUT__H_ + + +#include "audio_def.hpp" +#include "audio_format.hpp" +#include "audio_producer.hpp" + + + +_AUDIO_NAMESPACE_START_ + +enum audio_waveout_status { WAVEOUT_NOTREADY, WAVEOUT_READY, + WAVEOUT_PLAYING, WAVEOUT_ERR, + WAVEOUT_PAUSED, WAVEOUT_STOP + + }; + + +class audio_waveout +{ + + friend class audio_buffer; + + + + private: + + + static DWORD WINAPI playing_procedure( LPVOID ); + + + + HANDLE wakeup_playthread; + + + + + protected: + + + WAVEFORMATEX wave_format; + WAVEHDR * wave_headers; + HWAVEOUT waveout_handle; + + + + + + const audio_format & aud_info; + audio_producer & audio_buf; + + + + + + + // + // Audio Playing Thread id + // + + DWORD playthread_id; + + + + + + audio_waveout_status status; + + + + + float buf_secs; + + + + // + // The temporary buffers for the audio + // data outgoing to the waveout device + // and its size, and its total number. + // + + + //base address for entire memory + BYTE * main_buffer; + + //size in bytes for the entire memory + unsigned int mb_size; + + //number of little buffers + unsigned int buffers; + + + + + + + // + // Protected Functions + // + + void init_( void ); + void alloc_buffers_mem_( unsigned int, float ); + void free_buffers_mem_( void ); + + + void init_headers_( void ); + void prep_headers_( void ); + void unprep_headers_( void ); + + + + + + + + public: + + // + // Ctors + // + + audio_waveout( const audio_format & aud_fmt, + audio_producer & a_buf ) + + : wave_headers( 0 ), aud_info( aud_fmt ), + audio_buf( a_buf ), status( WAVEOUT_NOTREADY ), + main_buffer( 0 ), mb_size( 0 ), + buffers( _AUDIO_DEFAULT_WAVEOUTBUFFERS ) + { + + // + // Initializing internal wavein data + // + + + init_(); + + } + + + + + + + // + // Dtor + // + + ~audio_waveout( void ) + { } + + + + + // + // Public Functions + // + + void open ( void ); + void play ( void ); + void pause ( void ); + void stop ( void ); + void close ( void ); + + + audio_waveout_status current_status( void ) + { return status; } + + + + + + + + +}; + + + +_AUDIO_NAMESPACE_END_ + + + + +#endif //ifdef _AUDIOWAVEOUT__H_ diff --git a/reactos/base/applications/sndrec32/bitmap1.bmp b/reactos/base/applications/sndrec32/bitmap1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/reactos/base/applications/sndrec32/but_end.bmp b/reactos/base/applications/sndrec32/but_end.bmp new file mode 100644 index 0000000000000000000000000000000000000000..036ccb115fbc9110f5e728c83ee55107b44bfa5b GIT binary patch literal 1046 zcmeH^F%kkH3`M`AGqzTC_TItH-n&q_El2Sv+zkH@&SnEMasbVeknH;`ki9?72bet> zuk;)JLf@f**Pg}4PMqbG-#?Bqs*tyG}VC_*jN^e$N%2HcG?2yJu+UKFlH2+#0v9J!* zNcB{M0=5q?XMEYSN(6w35K3d^h!`V#2I)wolqZTOKe4P=@yE;W@24|sy+4>ixEYkI c!MGTl*9PbH7me3=RW4Y$V&R5`+j^hCcK}kE+W-In literal 0 HcmV?d00001 diff --git a/reactos/base/applications/sndrec32/but_rec.bmp b/reactos/base/applications/sndrec32/but_rec.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3e7249d64b397bcb82027a37ec1d50f49e1e9f4e GIT binary patch literal 1046 zcmZ?r6=PulgEAng0mRloEDOYp3=oM0%s>tl2momihJXeJ1|VW+Xn;^a63ApYaNq!t z21)z}BZmL~K`bB!LXZ%UD8~m17>1aqKvee=lm{z7(q4|HzZ|FlSsGIw5wu_yhW_Cv4*tl2momihJXeJ1|VW+Xn;^a63ApYaNq!t z21)z}BZmL~K`bB!LXZ%UD8~m17)FvjFl2y$9VtLi{XZ&CS@<9YER=~FzN7N!Api^? E0OoRr%m4rY literal 0 HcmV?d00001 diff --git a/reactos/base/applications/sndrec32/kkaudio.hpp b/reactos/base/applications/sndrec32/kkaudio.hpp new file mode 100644 index 00000000000..285b1d399c4 --- /dev/null +++ b/reactos/base/applications/sndrec32/kkaudio.hpp @@ -0,0 +1,18 @@ +#ifndef _AUDIO__H_ +#define _AUDIO__H_ + + +#include "audio_def.hpp" +#include "audio_wavein.hpp" +#include "audio_waveout.hpp" +#include "audio_resampler_acm.hpp" +#include "audio_format.hpp" +#include "audio_membuffer.hpp" +#include "audio_producer.hpp" +#include "audio_receiver.hpp" + + + + +#endif //ifdef _KKAUDIO__H_ + diff --git a/reactos/base/applications/sndrec32/reactOS_sndrec32.ico b/reactos/base/applications/sndrec32/reactOS_sndrec32.ico new file mode 100644 index 0000000000000000000000000000000000000000..d92d91e87d695a3f14b0c478c845c44ac18ed2bf GIT binary patch literal 23558 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 literal 0 HcmV?d00001 diff --git a/reactos/base/applications/sndrec32/sndrec32.cpp b/reactos/base/applications/sndrec32/sndrec32.cpp new file mode 100644 index 00000000000..b1b6a30a214 --- /dev/null +++ b/reactos/base/applications/sndrec32/sndrec32.cpp @@ -0,0 +1,1042 @@ +/* +* PROJECT: ReactOS Sound Record Application +* LICENSE: GPL - See COPYING in the top level directory +* FILE: base/applications/sndrec32/sndrec32.cpp +* PURPOSE: Application Startup +* PROGRAMMERS: Marco Pagliaricci +*/ + + + +#include "stdafx.h" +#include "sndrec32.h" + +#include "kkaudio.hpp" + + + +HINSTANCE hInst; +TCHAR szTitle[MAX_LOADSTRING]; +TCHAR szWindowClass[MAX_LOADSTRING]; + + +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); + + + +HWND main_win; +HWND slider; +HWND buttons[5]; +HBITMAP butbmps[5]; +WNDPROC buttons_std_proc; + +BOOL butdisabled[5]; +BOOL stopped_flag; +BOOL isnew; + + +DWORD slider_pos; +WORD slider_min; +WORD slider_max; + +long long samples_max; + +OPENFILENAME ofn; +TCHAR file_path[MAX_PATH]; +BOOL path_set; + +using snd::audio_membuffer; +using snd::audio_wavein; +using snd::audio_waveout; + +audio_membuffer * AUD_BUF; +audio_waveout * AUD_OUT; +audio_wavein * AUD_IN; + + +BOOL s_recording; + + +int APIENTRY _tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + + MSG msg; + HACCEL hAccelTable; + + InitCommonControls(); + + + + + + + + + butbmps[0] = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BITMAP2_START )); + butbmps[1] = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BITMAP2_END )); + butbmps[2] = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BITMAP2_PLAY )); + butbmps[3] = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BITMAP2_STOP )); + butbmps[4] = LoadBitmap( hInstance, MAKEINTRESOURCE( IDB_BITMAP2_REC )); + + + + + + + snd::audio_membuffer AUD_buffer( snd::A44100_16BIT_STEREO ); + snd::audio_waveout AUD_waveout( snd::A44100_16BIT_STEREO, AUD_buffer ); + snd::audio_wavein AUD_wavein( snd::A44100_16BIT_STEREO, AUD_buffer ); + + AUD_buffer.play_finished = l_play_finished; + AUD_buffer.audio_arrival = l_audio_arrival; + AUD_buffer.buffer_resized = l_buffer_resized; + + AUD_buffer.alloc_seconds( INITIAL_BUFREC_SECONDS ); + + AUD_IN = &AUD_wavein; + AUD_OUT = &AUD_waveout; + AUD_BUF = &AUD_buffer; + + + + slider_pos = 0; + slider_min = 0; + slider_max = 32767; + + + stopped_flag = FALSE; + path_set = FALSE; + isnew = TRUE; + + + + samples_max = AUD_buffer.total_samples(); + + + + + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_REACTOS_SNDREC32, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + + if (!InitInstance (hInstance, nCmdShow)) + { + MessageBox(0, 0, TEXT("CreateWindow() Error!"), 0); + return FALSE; + } + + hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_REACTOS_SNDREC32)); + + + + + + + s_recording = false; + + + + + AUD_wavein.open(); + AUD_waveout.open(); + + + + + + + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + AUD_waveout.close(); + AUD_wavein.close(); + + AUD_buffer.clear(); + + + return (int) msg.wParam; +} + + + + +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_REACTOS_SNDREC32LL)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(16); + wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_REACTOS_SNDREC32LL)); + + + return RegisterClassEx(&wcex); +} + +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; + + hWnd = CreateWindow( + szWindowClass, + szTitle, + WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + CW_USEDEFAULT, + CW_USEDEFAULT, + MAINWINDOW_W, + MAINWINDOW_H, + NULL, NULL, + hInstance, NULL + ); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + main_win = hWnd; + + + return TRUE; +} + + +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + RECT rect; + PAINTSTRUCT ps; + HDC hdc; + + + // + // Checking for global pointers to buffer and + // io audio devices. + // + + if (( !AUD_IN ) || ( !AUD_OUT ) || ( !AUD_BUF )) + { + MessageBox( 0, TEXT("Buffer Error"), 0, 0 ); + return 1; + } + + + switch (message) + { + + + case WM_CREATE: + + + + // + // Creating ALL the buttons + // + + for ( int i = 0; i < 5; ++ i ) + { + + buttons[i] = CreateWindow( + TEXT("button"), + TEXT(""), + WS_CHILD|WS_VISIBLE| BS_BITMAP, + BUTTONS_CX + ( i * (BUTTONS_W+((i == 0)?0:BUTTONS_SPACE))), + BUTTONS_CY, BUTTONS_W, BUTTONS_H, hWnd, + (HMENU)i, hInst, 0 + ); + + if ( !buttons[i] ) + { + MessageBox(0, 0, TEXT("CreateWindow() Error!"), 0); + return FALSE; + + } + + butdisabled[ i ] = TRUE; + + + + // + // Realize the button bmp image + // + + SendMessage(buttons[i], BM_SETIMAGE, ( WPARAM )IMAGE_BITMAP, ( LPARAM )butbmps[i]); + + + UpdateWindow( buttons[i] ); + + } + + + // + // Creating the SLIDER window + // + + slider = CreateWindow( + TRACKBAR_CLASS, + TEXT(""), + WS_CHILD|WS_VISIBLE|TBS_NOTICKS|TBS_HORZ|TBS_ENABLESELRANGE, + SLIDER_CX, SLIDER_CY, SLIDER_W, SLIDER_H, hWnd, + (HMENU)SLIDER_ID, hInst, 0 + ); + + + if ( !slider ) + { + MessageBox(0, 0, TEXT("CreateWindow() Error!"), 0); + return FALSE; + + } + + + // + // Sets slider limits + // + + //slider_min = 0; + //slider_max = 100; + + SendMessage( + slider, + TBM_SETRANGE, + (WPARAM)TRUE, + (LPARAM)MAKELONG(slider_min,slider_max) + ); + + + UpdateWindow( slider ); + + + // + // Enables REC button. + // + + butdisabled[ BUTREC_ID ] = FALSE; + + + + + break; + + + + // + // Implements slider logic + // + + case WM_HSCROLL : + { + switch( LOWORD( wParam )) + { + + case SB_ENDSCROLL: + break; + + case SB_PAGERIGHT: + case SB_PAGELEFT: + case TB_THUMBTRACK: + slider_pos = SendMessage(slider, TBM_GETPOS, 0, 0); + break; + + } + + break; + } + + + + + + + case WM_COMMAND: + + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + if (( wmId >= 0 ) && ( wmId < 5 ) && (butdisabled[wmId] == TRUE)) + break; + + switch (wmId) + { + + case ID_NEW: + + if ( !isnew ) + { + + if ( AUD_IN->current_status() == snd::WAVEIN_RECORDING ) + AUD_IN->stop_recording(); + + + if (( AUD_OUT->current_status() == snd::WAVEOUT_PLAYING ) || + ( AUD_OUT->current_status() == snd::WAVEOUT_PAUSED )) + AUD_OUT->stop(); + + + AUD_BUF->reset(); + + butdisabled[ BUTREC_ID ] = FALSE; + butdisabled[ BUTSTART_ID ] = TRUE; + butdisabled[ BUTEND_ID ] = TRUE; + butdisabled[ BUTSTOP_ID ] = TRUE; + butdisabled[ BUTPLAY_ID ] = TRUE; + + samples_max = AUD_BUF->total_samples(); + slider_pos = 0; + + SendMessage(slider, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) slider_pos); + + } + + + + break; + + + + + case ID_FILE_OPEN: + + ZeroMemory( &ofn, sizeof( ofn )); + + ofn.lStructSize = sizeof( ofn ); + ofn.hwndOwner = hWnd; + ofn.lpstrFilter = TEXT("Audio Files (*.wav)\0*.wav\0All Files (*.*)\0*.*\0"); + ofn.lpstrFile = file_path; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = TEXT("wav"); + + if( GetOpenFileName( &ofn )) + { + open_wav( file_path ); + } + + break; + + + + + case ID__ABOUT: + + + + break; + + + case ID_FILE_SAVEAS: + + ZeroMemory( &ofn, sizeof( ofn )); + + ofn.lStructSize = sizeof( ofn ); + ofn.hwndOwner = hWnd ; + ofn.Flags = OFN_OVERWRITEPROMPT; + ofn.lpstrFilter = TEXT("Audio Files (*.wav)\0*.wav\0All Files (*.*)\0*.*\0"); + ofn.lpstrFile = file_path; + ofn.nMaxFile = MAX_PATH; + + ofn.lpstrDefExt = TEXT("wav"); + + if ( GetSaveFileName ( &ofn )) + { + + write_wav( file_path ); + + } + + break; + + case ID_EXIT: + DestroyWindow( hWnd ); + break; + + + // + // Sndrec32 buttons routines + // + + case BUTSTART_ID: + Beep(200,200); + break; + + + case BUTEND_ID: + Beep(300,200); + break; + + case BUTPLAY_ID: + + AUD_OUT->play(); + + butdisabled[ BUTSTART_ID ] = TRUE; + butdisabled[ BUTEND_ID ] = TRUE; + butdisabled[ BUTREC_ID ] = TRUE; + butdisabled[ BUTPLAY_ID ] = TRUE; + + SetTimer( hWnd, 1, 250, 0 ); + + break; + + case BUTSTOP_ID: + if ( s_recording ) + { + s_recording = FALSE; + + AUD_IN->stop_recording(); + + butdisabled[ BUTSTART_ID ] = FALSE; + butdisabled[ BUTEND_ID ] = FALSE; + butdisabled[ BUTREC_ID ] = FALSE; + butdisabled[ BUTPLAY_ID ] = FALSE; + + + + // + // Resetting slider position + // + + slider_pos = 0; + SendMessage(slider, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) slider_pos); + + + samples_max = AUD_BUF->samples_received(); + + EnableMenuItem((HMENU)IDR_MENU1, ID_FILE_SAVEAS, MF_ENABLED ); + + } else { + + AUD_OUT->pause(); + + butdisabled[ BUTSTART_ID ] = FALSE; + butdisabled[ BUTEND_ID ] = FALSE; + butdisabled[ BUTREC_ID ] = FALSE; + butdisabled[ BUTPLAY_ID ] = FALSE; + + } + + KillTimer( hWnd, 1 ); + + break; + + case BUTREC_ID: + + s_recording = TRUE; + + samples_max = AUD_BUF->total_samples(); + + AUD_IN->start_recording(); + + butdisabled[ BUTSTOP_ID ] = FALSE; + butdisabled[ BUTSTART_ID ] = TRUE; + butdisabled[ BUTEND_ID ] = TRUE; + butdisabled[ BUTREC_ID ] = TRUE; + butdisabled[ BUTPLAY_ID ] = TRUE; + + isnew = FALSE; + + + + SetTimer( hWnd, 1, 150, 0 ); + + break; + + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + + + case WM_TIMER: + + if ( stopped_flag ) + { + KillTimer(hWnd, 1); + slider_pos = 0; + + butdisabled[ BUTPLAY_ID ] = FALSE; + + stopped_flag = FALSE; + } + + SendMessage(slider, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) slider_pos); + + + + break; + + + + case WM_PAINT: + + InvalidateRect( hWnd, &rect, TRUE ); + hdc = BeginPaint(hWnd, &ps); + + EndPaint(hWnd, &ps); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +BOOL open_wav( TCHAR * f ) +{ + + + HANDLE file; + + riff_hdr r; + wave_hdr w; + data_chunk d; + + BOOL b; + + DWORD bytes_recorded_in_wav = 0; + DWORD is_read = 0; + + + + + file = CreateFile( + f, + GENERIC_READ, + 0, 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + + + + if ( !file ) + { + MessageBox( + main_win, + TEXT("Cannot open file. CreateFile() error."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + return FALSE; + + } + + + b = ReadFile( file, ( LPVOID ) &r, sizeof ( r ), &is_read, 0 ); + + if ( !b ) + { + DWORD t = GetLastError(); + TCHAR p[100]; + wsprintf(p,TEXT("Errore n: %i"),t); + + MessageBox( + main_win, + //TEXT("Cannot read RIFF header."), + p, + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + return FALSE; + + } + + + b = ReadFile( file, ( LPVOID ) &w, sizeof ( w ), &is_read, 0 ); + + + if ( !b ) + { + + MessageBox( + main_win, + TEXT("Cannot read WAVE header."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + return FALSE; + + } + + + + b = ReadFile( file, ( LPVOID ) &d, sizeof ( d ), &is_read, 0 ); + + if ( !b ) + { + + MessageBox( + main_win, + TEXT("Cannot read WAVE subchunk."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + return FALSE; + + } + + bytes_recorded_in_wav = r.chunksize - 36; + + + /* + unsigned char * gg = (unsigned char*)&bytes_recorded_in_wav; + + gg[0] = gg[3]; + gg[1] = gg[2]; + + bytes_recorded_in_wav = (DWORD) *gg; + + + + TCHAR p [100]; + wsprintf(p,TEXT("bytes: %i"),bytes_recorded_in_wav); + MessageBox(0,p,0,0); + + */ + + if ( bytes_recorded_in_wav == 0 ) + { + + MessageBox( + main_win, + TEXT("Cannot read file. No audio data."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + return FALSE; + + } + + + snd::audio_format openfmt + ( w.SampleRate, w.BitsPerSample, w.NumChannels ); + + + + AUD_BUF->clear(); + + + AUD_BUF->alloc_bytes( bytes_recorded_in_wav ); + + + b = ReadFile( + file, + ( LPVOID ) AUD_BUF->audio_buffer(), + bytes_recorded_in_wav, + &is_read, + 0 + ); + + + AUD_BUF->set_b_received( bytes_recorded_in_wav ); + + + if (( !b ) || ( is_read != bytes_recorded_in_wav )) + { + + MessageBox( + main_win, + TEXT("Cannot read file. Error reading audio data."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + + AUD_BUF->reset(); + return FALSE; + + } + + CloseHandle( file ); + + butdisabled[ BUTPLAY_ID ] = FALSE; + butdisabled[ BUTSTOP_ID ] = FALSE; + butdisabled[ BUTEND_ID ] = FALSE; + butdisabled[ BUTSTART_ID ] = FALSE; + butdisabled[ BUTREC_ID ] = FALSE; + + + + samples_max = AUD_BUF->samples_received(); + + isnew = FALSE; + + return TRUE; + +} + + +BOOL + write_wav( TCHAR * f ) +{ + + HANDLE file; + + + DWORD written; + BOOL is_writ; + int i; + riff_hdr r; + wave_hdr w; + data_chunk d; + + + + file = CreateFile( + f, + GENERIC_WRITE, + 0, 0, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + + + + if ( !file ) + { + i = MessageBox( + main_win, + TEXT("File already exist. Overwrite it?"), + TEXT("Warning"), + MB_YESNO|MB_ICONQUESTION + ); + + if ( i == IDYES ) + { + + file = CreateFile( + f, + GENERIC_WRITE, + 0, 0, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0 + ); + + if ( !file ) + { + MessageBox( + main_win, + TEXT("File Error, CreateFile() failed."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + + return FALSE; + + } + + + } else + return FALSE; + } + + + + + r.magic = 0x46464952; + + + r.format = 0x45564157; + r.chunksize = 36 + AUD_BUF->bytes_recorded(); + + + w.Subchunkid = 0x20746d66; + + w.Subchunk1Size = 16; + w.AudioFormat = 1; + w.NumChannels = AUD_BUF->audinfo().channels(); + w.SampleRate = AUD_BUF->audinfo().sample_rate(); + w.ByteRate = AUD_BUF->audinfo().byte_rate(); + w.BlockAlign = AUD_BUF->audinfo().block_align(); + w.BitsPerSample = AUD_BUF->audinfo().bits(); + + + d.subc = 0x61746164; + d.subc_size = AUD_BUF->bytes_recorded(); + + + + // + // Writing headers + // + + + is_writ = WriteFile( file, ( LPCVOID ) &r, sizeof ( r ), &written, 0 ); + + if ( !is_writ ) + { + MessageBox( + main_win, + TEXT("File Error, WriteFile() failed."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + + return FALSE; + + } + + + is_writ = WriteFile( file, ( LPCVOID ) &w, sizeof ( w ), &written, 0 ); + + if ( !is_writ ) + { + MessageBox( + main_win, + TEXT("File Error, WriteFile() failed."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + + return FALSE; + + } + + + is_writ = WriteFile( file, ( LPCVOID ) &d, sizeof ( d ), &written, 0 ); + + + if ( !is_writ ) + { + MessageBox( + main_win, + TEXT("File Error, WriteFile() failed."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + + return FALSE; + + } + + + + is_writ = WriteFile( + file, + ( LPCVOID ) AUD_BUF->audio_buffer(), + AUD_BUF->bytes_recorded(), + &written, + 0 + ); + + if ( !is_writ ) + { + MessageBox( + main_win, + TEXT("File Error, WriteFile() failed."), + TEXT("ERROR"), + MB_OK|MB_ICONERROR + ); + + CloseHandle( file ); + + return FALSE; + + } + + + CloseHandle( file ); + + return TRUE; +} + + + +void l_play_finished ( void ) +{ + + stopped_flag = true; + + + +} + +void l_audio_arrival ( unsigned int samples_arrival ) +{ + + + slider_pos += (DWORD) (( slider_max * samples_arrival ) / samples_max ); + + +} + +void l_buffer_resized ( unsigned int new_size ) +{ + + + + + +} + +VOID enable_but( DWORD id ) +{ + + + + + +} +VOID disable_but( DWORD id ) +{ + + + +} + + diff --git a/reactos/base/applications/sndrec32/sndrec32.h b/reactos/base/applications/sndrec32/sndrec32.h new file mode 100644 index 00000000000..530e53e93a6 --- /dev/null +++ b/reactos/base/applications/sndrec32/sndrec32.h @@ -0,0 +1,96 @@ +#pragma once + +#include "resource.h" + + + +#define MAX_LOADSTRING 100 + +#define MAINWINDOW_W 350 +#define MAINWINDOW_H 190 + + +#define CONTROLS_CX 10 + +#define INITIAL_BUFREC_SECONDS 30.0f + + +#define BUTSTART_ID 0 +#define BUTEND_ID 1 +#define BUTPLAY_ID 2 +#define BUTSTOP_ID 3 +#define BUTREC_ID 4 +#define SLIDER_ID 5 + +#define BUTTONS_H 30 +#define BUTTONS_W 60 +#define BUTTONS_CY 100 +#define BUTTONS_CX CONTROLS_CX +#define BUTTONS_SPACE 5 + + +#define SLIDER_CX CONTROLS_CX +#define SLIDER_CY 65 +#define SLIDER_H 30 +#define SLIDER_W 320 + + + + +struct riff_hdr +{ + DWORD magic; + DWORD chunksize; + DWORD format; +}; + + +struct wave_hdr +{ + + DWORD Subchunkid; + DWORD Subchunk1Size; + WORD AudioFormat; + WORD NumChannels; + DWORD SampleRate; + DWORD ByteRate; + WORD BlockAlign; + WORD BitsPerSample; +}; + +struct data_chunk +{ + DWORD subc; + DWORD subc_size; + //unsigned char data[]; +}; + + + +// +// Functions prototypes +// +LRESULT CALLBACK +Buttons_proc(HWND, UINT, WPARAM, LPARAM); + + +BOOL +write_wav( TCHAR * ); + +BOOL +open_wav( TCHAR * ); + + +VOID enable_but( DWORD ); +VOID disable_but( DWORD ); + + + +void +l_play_finished ( void ); + +void +l_audio_arrival ( unsigned int ); + +void +l_buffer_resized ( unsigned int ); diff --git a/reactos/base/applications/sndrec32/sndrec32.rbuild b/reactos/base/applications/sndrec32/sndrec32.rbuild new file mode 100644 index 00000000000..291555117e4 --- /dev/null +++ b/reactos/base/applications/sndrec32/sndrec32.rbuild @@ -0,0 +1,20 @@ + + + + . + winmm + user32 + kernel32 + msacm32 + comctl32 + comdlg32 + audio_format.cpp + audio_membuffer.cpp + audio_producer.cpp + audio_receiver.cpp + audio_resampler_acm.cpp + audio_wavein.cpp + audio_waveout.cpp + sndrec32.cpp + sndrec32.rc + diff --git a/reactos/base/applications/sndrec32/sndrec32.rc b/reactos/base/applications/sndrec32/sndrec32.rc new file mode 100644 index 00000000000..e4de736ec11 --- /dev/null +++ b/reactos/base/applications/sndrec32/sndrec32.rc @@ -0,0 +1,179 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#ifndef APSTUDIO_INVOKED +#include "targetver.h" +#endif +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Italiano (Italia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA) +#ifdef _WIN32 +LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_REACTOS_SNDREC32LL ICON "reactOS_sndrec32.ico" +IDI_SMALL ICON "small.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_REACTOS_SNDREC32 ACCELERATORS +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 196, 75 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Informazioni su reactOS_sndrec32" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON 128,IDC_REACTOS_SNDREC32,19,14,21,20 + LTEXT "reactOS_sndrec32, versione 1.0",IDC_STATIC,56,16,114,8,SS_NOPREFIX + LTEXT "Copyright (C) 2009",IDC_STATIC,55,25,114,8 + DEFPUSHBUTTON "OK",IDOK,139,54,50,14,WS_GROUP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 189 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#ifndef APSTUDIO_INVOKED\r\n" + "#include ""targetver.h""\r\n" + "#endif\r\n" + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP2_START BITMAP "but_start.bmp" +IDB_BITMAP2_END BITMAP "but_end.bmp" +IDB_BITMAP2_PLAY BITMAP "but_play.bmp" +IDB_BITMAP2_STOP BITMAP "but_stop.bmp" +IDB_BITMAP2_REC BITMAP "but_rec.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU +BEGIN + POPUP "File" + BEGIN + MENUITEM "New", ID_NEW + MENUITEM "Open...", ID_FILE_OPEN + MENUITEM "Save", ID_FILE_SAVE, GRAYED + MENUITEM "Save As...", ID_FILE_SAVEAS + MENUITEM SEPARATOR + MENUITEM "Exit", ID_EXIT + END + MENUITEM "todo1", 0 + MENUITEM "todo2", 0 + POPUP "?" + BEGIN + MENUITEM "About...", ID__ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_APP_TITLE "reactOS_sndrec32" + IDC_REACTOS_SNDREC32 "REACTOS_SNDREC32" +END + +#endif // Italiano (Italia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/reactos/base/applications/sndrec32/stdafx.h b/reactos/base/applications/sndrec32/stdafx.h new file mode 100644 index 00000000000..69ca28669ec --- /dev/null +++ b/reactos/base/applications/sndrec32/stdafx.h @@ -0,0 +1,23 @@ +// stdafx.h : file di inclusione per file di inclusione di sistema standard +// o file di inclusione specifici del progetto utilizzati di frequente, ma +// modificati raramente +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Escludere gli elementi utilizzati di rado dalle intestazioni di Windows +// File di intestazione di Windows: +#include +#include +#include + +// File di intestazione Runtime C +#include +#include +#include +#include + + +// TODO: fare riferimento qui alle intestazioni aggiuntive richieste dal programma diff --git a/reactos/base/applications/sndrec32/targetver.h b/reactos/base/applications/sndrec32/targetver.h new file mode 100644 index 00000000000..92426c66d27 --- /dev/null +++ b/reactos/base/applications/sndrec32/targetver.h @@ -0,0 +1,24 @@ +#pragma once + +// Le macro seguenti definiscono la piattaforma minima richiesta. La piattaforma minima richiesta +// è costituita dalla versione meno recente di Windows, Internet Explorer e così via contenenti le funzionalità necessarie per eseguire +// l'applicazione. Le macro consentono di attivare tutte le funzionalità disponibili nelle versioni delle piattaforme fino +// alla versione specificata compresa. + +// Modificare le seguenti definizioni se è necessario utilizzare come destinazione una piattaforma prima di quelle specificate di seguito. +// Fare riferimento a MSDN per informazioni aggiornate sui valori corrispondenti per le differenti piattaforme. +#ifndef WINVER // Specifica che la piattaforma minima richiesta è Windows Vista. +#define WINVER 0x0600 // Modificare il valore con quello appropriato per altre versioni di Windows. +#endif + +#ifndef _WIN32_WINNT // Specifica che la piattaforma minima richiesta è Windows Vista. +#define _WIN32_WINNT 0x0600 // Modificare il valore con quello appropriato per altre versioni di Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifica che la piattaforma minima richiesta è Windows 98. +#define _WIN32_WINDOWS 0x0410 // Modificare il valore con quello appropriato per Windows Me o versioni successive. +#endif + +#ifndef _WIN32_IE // Specifica che la piattaforma minima richiesta è Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Modificare il valore con quello appropriato per altre versioni di IE. +#endif