📄 sndcpcm.cpp
字号:
// --------------------------------------------------------------------------// Name: sndcpcm.cpp// Purpose:// Date: 08/11/1999// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000// CVSID: $Id: sndcpcm.cpp,v 1.8 2005/09/23 12:47:51 MR Exp $// wxWindows licence// --------------------------------------------------------------------------#include "wx/wxprec.h"#ifndef WX_PRECOMP #include "wx/defs.h" #include "wx/debug.h" #include "wx/log.h"#endif#ifdef __BORLANDC__ #pragma hdrstop#endif#include "wx/mmedia/sndbase.h"#include "wx/mmedia/sndpcm.h"#include "wx/mmedia/sndcpcm.h"wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream& sndio) : wxSoundStreamCodec(sndio){ m_function_in = NULL; m_function_out = NULL; m_prebuffer = NULL; m_prebuffer_size = 0; m_best_size = 0;}wxSoundStreamPcm::~wxSoundStreamPcm(){ if (m_prebuffer) delete[] m_prebuffer;}wxUint32 wxSoundStreamPcm::GetBestSize() const{ return m_best_size;}// -----------------------------------------------------------------------// "Converters" definitions/implementations// -----------------------------------------------------------------------#define DEFINE_CONV(name, input_type, output_type, convert) \static void Convert_##name(const void *buf_in, void *buf_out, wxUint32 len) \{\ register input_type src; \ register const input_type *t_buf_in = (input_type *)buf_in; \ register output_type *t_buf_out = (output_type *)buf_out; \\ while (len > 0) { \ src = *t_buf_in++; \ *t_buf_out++ = convert; \ len -= sizeof(input_type); \ } \}// TODO: define converters for all other formats (32, 24)DEFINE_CONV(8_8_sign, wxUint8, wxUint8, (src ^ 0x80))DEFINE_CONV(8_16, wxUint8, wxUint16, (((wxUint16)src) << 8))DEFINE_CONV(8_16_swap, wxUint8, wxUint16, (src))DEFINE_CONV(8_16_sign, wxUint8, wxUint16, (((wxUint16)(src ^ 0x80)) << 8))DEFINE_CONV(8_16_sign_swap, wxUint8, wxUint16, (src ^ 0x80))DEFINE_CONV(16_8, wxUint16, wxUint8, (wxUint8)(src >> 8))DEFINE_CONV(16_8_sign, wxUint16, wxUint8, (wxUint8)((src >> 8) ^ 0x80))DEFINE_CONV(16_swap_8, wxUint16, wxUint8, (wxUint8)(src & 0xff))DEFINE_CONV(16_swap_8_sign, wxUint16, wxUint8, (wxUint8)((src & 0xff) ^ 0x80))//DEFINE_CONV(24_8, wxUint32, wxUint8, (wxUint8)(src >> 16))//DEFINE_CONV(24_8_sig, wxUint32, wxUint8, (wxUint8)((src >> 16) ^ 0x80))//DEFINE_CONV(32_8, wxUint32, wxUint8, (wxUint8)(src >> 24))DEFINE_CONV(16_sign, wxUint16, wxUint16, (src ^ 0x8000))DEFINE_CONV(16_swap, wxUint16, wxUint16, (((src & 0xff) << 8) | ((src >> 8) & 0xff)))// Problem.DEFINE_CONV(16_swap_16_sign, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x80))// DEFINE_CONV(16_sign_16_swap, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x8000))DEFINE_CONV(16_swap_16_sign_swap, wxUint16, wxUint16, (src ^ 0x80))// -----------------------------------------------------------------------// Main PCM stream converter table// -----------------------------------------------------------------------// Definition// XX -> YY// XX -> YY sign//// XX swapped -> YY// XX swapped -> YY sign//// XX swapped -> YY swapped// XX swapped -> YY swapped sign//// XX stereo -> YY mono// XX stereo -> YY mono sign//// XX swapped stereo -> YY swapped mono// XX swapped stereo -> YY swapped mono sign//// XX swapped stereo -> YY swapped mono// XX swapped stereo -> YY swapped mono signstatic wxSoundStreamPcm::ConverterType s_converters[4][3][2] = { { { NULL, Convert_8_8_sign /* 8 -> 8 sign */ }, { NULL, NULL }, { NULL, NULL } }, { { Convert_8_16, /* 8 -> 16 */ Convert_8_16_sign /* 8 -> 16 sign */ }, { Convert_8_16_swap, /* 8 -> 16 swapped */ Convert_8_16_sign_swap /* 8 -> 16 sign swapped */ }, { NULL, NULL } }, { { Convert_16_8, /* 16 -> 8 */ Convert_16_8_sign /* 16 -> 8 sign */ }, { Convert_16_swap_8, /* 16 swapped -> 8 */ Convert_16_swap_8_sign /* 16 swapped -> 8 sign */ }, { NULL, NULL }, }, { { NULL, /* 16 -> 16 */ Convert_16_sign /* 16 -> 16 sign */ }, { Convert_16_swap, /* 16 swapped -> 16 */ Convert_16_swap_16_sign /* 16 swapped -> 16 sign */ }, { NULL, Convert_16_swap_16_sign_swap /* 16 swapped -> 16 sign swapped */ } }};// This is the buffer size multiplier. It gives the needed size of the output size.static float s_converters_multip[] = {1, 2, 0.5, 1};//// TODO: Read() and Write() aren't really safe. If you give it a buffer which// is not aligned on 2, you may crash (See converter.def).//wxSoundStream& wxSoundStreamPcm::Read(void *buffer, wxUint32 len){ wxUint32 in_bufsize; // We must have a multiple of 2 len &= 0x01; if (!m_function_in) { m_sndio->Read(buffer, len); m_lastcount = m_sndio->GetLastAccess(); m_snderror = m_sndio->GetError(); return *this; } in_bufsize = GetReadSize(len); if (len <= m_best_size) { m_sndio->Read(m_prebuffer, in_bufsize); m_snderror = m_sndio->GetError(); if (m_snderror != wxSOUND_NOERROR) { m_lastcount = 0; return *this; } m_function_in(m_prebuffer, buffer, m_sndio->GetLastAccess()); } else { char *temp_buffer; temp_buffer = new char[in_bufsize]; m_sndio->Read(temp_buffer, in_bufsize); m_snderror = m_sndio->GetError(); if (m_snderror != wxSOUND_NOERROR) { m_lastcount = 0; return *this; } m_function_in(temp_buffer, buffer, m_sndio->GetLastAccess()); delete[] temp_buffer; } m_lastcount = (wxUint32)(m_sndio->GetLastAccess() * m_multiplier_in); return *this;}wxSoundStream& wxSoundStreamPcm::Write(const void *buffer, wxUint32 len){ wxUint32 out_bufsize; if (!m_function_out) { m_sndio->Write(buffer, len); m_lastcount = m_sndio->GetLastAccess(); m_snderror = m_sndio->GetError(); return *this; } out_bufsize = GetWriteSize(len); if (len <= m_best_size) { out_bufsize = GetWriteSize(len); m_function_out(buffer, m_prebuffer, len); m_sndio->Write(m_prebuffer, out_bufsize); m_snderror = m_sndio->GetError(); if (m_snderror != wxSOUND_NOERROR) { m_lastcount = 0; return *this; } } else { char *temp_buffer; temp_buffer = new char[out_bufsize]; m_function_out(buffer, temp_buffer, len); m_sndio->Write(temp_buffer, out_bufsize); m_snderror = m_sndio->GetError(); if (m_snderror != wxSOUND_NOERROR) { m_lastcount = 0; return *this; } delete[] temp_buffer; } m_lastcount = (wxUint32)(m_sndio->GetLastAccess() / m_multiplier_out); return *this;}bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase& format){ wxSoundFormatBase *new_format; wxSoundFormatPcm *pcm_format, *pcm_format2; if (m_sndio->SetSoundFormat(format)) { m_function_out = NULL; m_function_in = NULL; return true; } if (format.GetType() != wxSOUND_PCM) { m_snderror = wxSOUND_INVFRMT; return false; } if (m_sndformat) delete m_sndformat; new_format = m_sndio->GetSoundFormat().Clone(); pcm_format = (wxSoundFormatPcm *)&format; pcm_format2 = (wxSoundFormatPcm *)new_format;#if 0 // ---------------------------------------------------- // Test whether we need to resample if (pcm_format->GetSampleRate() != pcm_format2->GetSampleRate()) { wxUint32 src_rate, dst_rate; src_rate = pcm_format->GetSampleRate(); dst_rate = pcm_format2->GetSampleRate(); m_needResampling = true; if (src_rate < dst_rate) m_expandSamples = true; else m_expandSamples = false; m_pitch = (src_rate << FLOATBITS) / dst_rate; }#endif // ---------------------------------------------------- // Select table to use: // * 8 bits -> 8 bits // * 16 bits -> 8 bits // * 8 bits -> 16 bits // * 16 bits -> 16 bits int table_no, table_no2; int i_sign, i_swap; switch (pcm_format->GetBPS()) { case 8: table_no = 0; break; case 16: table_no = 1; break; default: // TODO: Add something here: error, log, ... return false; } switch (pcm_format2->GetBPS()) { case 8: table_no2 = 0; break; case 16: table_no2 = 1; break; default: // TODO: Add something here: error, log, ... return false; } if (pcm_format2->Signed() != pcm_format->Signed()) i_sign = 1; else i_sign = 0;#define MY_ORDER wxBYTE_ORDER#if wxBYTE_ORDER == wxLITTLE_ENDIAN#define OTHER_ORDER wxBIG_ENDIAN#else#define OTHER_ORDER wxLITTLE_ENDIAN#endif // -------------------------------------------------------- // Find the good converter ! if (pcm_format->GetOrder() == OTHER_ORDER) { if (pcm_format->GetOrder() == pcm_format2->GetOrder()) i_swap = 2; else i_swap = 1; } else { if (pcm_format->GetOrder() == pcm_format2->GetOrder()) i_swap = 0; else i_swap = 1; } m_function_out = s_converters[table_no*2+table_no2][i_swap][i_sign]; m_function_in = s_converters[table_no2*2+table_no][i_swap][i_sign]; m_multiplier_out = s_converters_multip[table_no*2+table_no2]; m_multiplier_in = s_converters_multip[table_no2*2+table_no2]; if (m_prebuffer) delete[] m_prebuffer; // We try to minimize the need for dynamic memory allocation by preallocating a buffer. But // to be sure it will be efficient we minimize the best size. if (m_multiplier_in < m_multiplier_out) { m_prebuffer_size = (wxUint32)(m_sndio->GetBestSize() * m_multiplier_out); m_best_size = (wxUint32)(m_sndio->GetBestSize() * m_multiplier_in); } else { m_prebuffer_size = (wxUint32)(m_sndio->GetBestSize() * m_multiplier_in); m_best_size = (wxUint32)(m_sndio->GetBestSize() * m_multiplier_out); } m_prebuffer = new char[m_prebuffer_size]; bool SetSoundFormatReturn; SetSoundFormatReturn = m_sndio->SetSoundFormat(*new_format); wxASSERT( SetSoundFormatReturn ); wxUnusedVar( SetSoundFormatReturn ); m_sndformat = new_format; return true;}wxUint32 wxSoundStreamPcm::GetWriteSize(wxUint32 len) const{ // For the moment, it is simple but next time it will become more complicated // (Resampling) return (wxUint32)(len * m_multiplier_out);}wxUint32 wxSoundStreamPcm::GetReadSize(wxUint32 len) const{ return (wxUint32)(len / m_multiplier_in);}// Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT.#if 0#define FLOATBITS 16#define INTBITS 16#define FLOATMASK 0xffff#define INTMASK 0xffff0000void ResamplingShrink_##DEPTH##(const void *source, void *destination, wxUint32 len){ wxUint##DEPTH## *source_data, *dest_data; wxUint32 pos; source_data = (wxUint##DEPTH## *)source; dest_data = (wxUint##DEPTH## *)destination; pos = m_saved_pos; while (len > 0) { // Increment the position in the input buffer pos += m_pitch; if (pos & INTMASK) { pos &= FLOATMASK; *dest_data ++ = *source_data; } len--; source_data++; } m_saved_pos = pos;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -