Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.142.197.198] |
|
Сообщ.
#1
,
|
|
|
Всем привет, есть задача, по выводу сигнала произвольной формы на звуковую карту. Подскажите пожалуйста, в какую сторону рыть? или может, у коего есть какой пример?
|
Сообщ.
#2
,
|
|
|
а в чем сложность?
|
Сообщ.
#3
,
|
|
|
Цитата Romzecs @ а в чем сложность? Сложность в том, что никогда не сталкивался с выводом генерируемого на ходу буфера на звуковую карту. Если бы надо было вывести ту же вавку или мпег, то все было бы понятно. |
Сообщ.
#4
,
|
|
|
ну так и генерируй вавку, в буфер её, а карта глядишь разберется, вавка ведь по сути набор уровней, даже не сжатый
|
Сообщ.
#5
,
|
|
|
PlaySound + SND_MEMORY. Структуры wav файла определены где-то в недрах заголовочных файлов winapi (гугл в помощь).
|
Сообщ.
#6
,
|
|
|
BBC
На нашем форуме раз-два кто эти занимался. Есть разный API. OpenAL Audio Stream Input/Output (ASIO) DirectSound waveOut(waveForm) WASAPI Собственно вся сложность в том как манипулировать буферами. И как организовать более или менее работу в реальном масштабе времени. Как по мне в waveOut это очень сложно и запутанно. Про другие не скажу не пробовал. пример работы http://msdn.microsoft.com/en-us/library/wi...3(v=vs.85).aspx WASAPI Описание туфта. А вот комментарии полезные. http://msdn.microsoft.com/en-us/library/wi...6(v=vs.85).aspx |
Сообщ.
#7
,
|
|
|
Да всё проще паренной репы.
я бы писал на Low Level Windows API. Но для этого нужно разобраться с теорией работы с аудиоданными. Самый простой способ - 1. создай заголовок аудио файла(wav). 2. создай дорожку аудио(8 bit mono, 8000 Gz),значение семплов расчитывается по формулам нужной кривой. 3. заполни заголовок файла(сумма отсчётов,кол-во дорожек, битрейт и т.д.). 4. передать адрес файла api функции на проигрывание. |
Сообщ.
#8
,
|
|
|
Я пытался делать прямоугольные импульсы(частный случай произвольной формы) ничего страшного, поищите тут ниже.
Проблема в том ,что менее 100мс длительностью фрагмента низя, а мне хотелось 20. |
Сообщ.
#9
,
|
|
|
Если кому интересно, сделал на CLR
using namespace System::IO; using namespace Microsoft::Win32; public enum ToneType { Sine, Square, Triangle, Sawtooth, User }; public ref class WaveHeader { public: static int HeaderSize = 44; int _sampleRate; short _bitsPerSample; bool _stereo; long _numberOfSamples; int _bytesPerSample; WaveHeader(int sampleRate, short bitsPerSample, bool stereo) { if (sampleRate <= 0)throw "sampleRate", "Sample Rate must be greater than zero."; if (bitsPerSample != 8 && bitsPerSample != 16)throw "Invalid Bits Per Sample specified. Currently supported values are [8, 16].", "bitsPerSample"; _sampleRate = sampleRate; _bitsPerSample = bitsPerSample; _stereo = stereo; _bytesPerSample = _bitsPerSample / 8; if (_stereo)_bytesPerSample *= 2; } property int SampleRate { int get() { return _sampleRate; } } property short BitsPerSample { short get() { return _bitsPerSample; } } property bool Stereo { bool get() { return _stereo; } } property int BytesPerSample { int get() { return _bytesPerSample; } } property long NumberOfSamples { long get() { return _numberOfSamples; } void set(long value) { if (value < 0 || value * _bytesPerSample > 0xFFFFFFFF) throw "NumberOfSamples cannot be less than zero or greater than int.MaxValue * bytesPerSample."; _numberOfSamples = value; } } void Write(BinaryWriter ^writer) { writer->Write(0x46464952); // "RIFF" in ASCII writer->Write((long)(HeaderSize + (_numberOfSamples * _bitsPerSample * (_stereo ? 2 : 1) / 8)) - 8); writer->Write(0x45564157); // "WAVE" in ASCII writer->Write(0x20746d66); // "fmt " in ASCII writer->Write(16); writer->Write((short)1); writer->Write((short)(_stereo ? 2 : 1)); writer->Write(_sampleRate); writer->Write(_sampleRate * (_stereo ? 2 : 1) * _bitsPerSample / 8); writer->Write((short)((_stereo ? 2 : 1) * BitsPerSample / 8)); writer->Write(_bitsPerSample); writer->Write(0x61746164); // "data" in ASCII writer->Write((long)(_numberOfSamples * _bitsPerSample * (_stereo ? 2 : 1) / 8)); } }; public ref struct Sample16Bit { short _leftChannel; short _rightChannel; bool _stereo; public: Sample16Bit(short monoChannel) { _leftChannel = monoChannel; _rightChannel = monoChannel; _stereo = false; } Sample16Bit(short leftChannel, short rightChannel) { _leftChannel = leftChannel; _rightChannel = rightChannel; _stereo = true; } Sample16Bit(bool stereo) { _leftChannel = 0; _rightChannel = 0; _stereo = stereo; } property short LeftChannel { short get() { return _leftChannel; } void set(short value) { _leftChannel = value; if (!_stereo)_rightChannel = value; } } property short RightChannel { short get() { return _rightChannel; } void set(short value) { _rightChannel = value; if (!_stereo)_leftChannel = value; } } property bool Stereo { bool get() { return _stereo; } } virtual bool Equals(Object ^obj)override { return (obj->GetType()==Sample16Bit::typeid && this->Equals((Sample16Bit ^)obj)); } virtual int GetHashCode()override { int a = this->_leftChannel; int b = this->_rightChannel; return ((a << 16) | b); } static bool operator == (Sample16Bit ^a, Sample16Bit ^b) { return a->Equals(b); } static bool operator !=(Sample16Bit ^a, Sample16Bit ^b) { return !a->Equals(b); } }; public ref class WaveWriter : public IDisposable { private: WaveHeader ^_header; BinaryWriter ^_writer; BinaryReader ^_reader; long _initialStreamPosition; bool _closeUnderlyingStream; bool _disposed; public: WaveWriter(Stream ^output, int sampleRate, short bitsPerSample, bool stereo, bool closeUnderlyingStream) { if (output == nullptr)throw "Output stream cannot be null."; _header = gcnew WaveHeader(sampleRate, bitsPerSample, stereo); _reader = gcnew BinaryReader(output); _writer = gcnew BinaryWriter(output); _initialStreamPosition = (long)output->Position; output->Position += WaveHeader::HeaderSize; _closeUnderlyingStream = closeUnderlyingStream; _disposed=false; } property long NumberOfSamples { long get() { ThrowIfDisposed(); return _header->NumberOfSamples; } } property int SampleRate { int get() { ThrowIfDisposed(); return _header->SampleRate; } } property WaveHeader ^Header { WaveHeader ^get() { ThrowIfDisposed(); return _header; } } property long CurrentSample { long get() { ThrowIfDisposed(); return (long)((_writer->BaseStream->Position - WaveHeader::HeaderSize - _initialStreamPosition) / _header->BytesPerSample); } void set(long value) { ThrowIfDisposed(); if (value < 0)throw "Sample Number must be greater than or equal to zero."; _writer->BaseStream->Position = _initialStreamPosition + WaveHeader::HeaderSize + (value * _header->BytesPerSample); } } property BinaryReader ^Reader { BinaryReader ^get() { ThrowIfDisposed(); return _reader; } } property BinaryWriter ^Writer { BinaryWriter ^get() { ThrowIfDisposed(); return _writer; } } void Close() { this->!WaveWriter(); } !WaveWriter() { if (!_disposed) { _writer->BaseStream->Position = _initialStreamPosition; Header->Write(_writer); if (_closeUnderlyingStream) { _writer->Close(); _reader->Close(); } _disposed = true; } } ~WaveWriter() { this->!WaveWriter(); GC::SuppressFinalize(this); } protected: void ThrowIfDisposed() { if (_disposed) { throw "WaveWriter"; } } }; public ref class WaveWriter16Bit : WaveWriter { public: WaveWriter16Bit(Stream ^output, int sampleRate, bool stereo) : WaveWriter(output, sampleRate, 16, stereo, true) { } WaveWriter16Bit(Stream ^output, int sampleRate, bool stereo, bool closeUnderlyingStream) : WaveWriter(output, sampleRate, 16, stereo, closeUnderlyingStream) { } Sample16Bit ^Read() { ThrowIfDisposed(); long initialPos = (long)Reader->BaseStream->Position; try { if (Header->Stereo) { return gcnew Sample16Bit(Reader->ReadInt16(), Reader->ReadInt16()); } else { return gcnew Sample16Bit(Reader->ReadInt16()); } } catch(Exception ^) { Reader->BaseStream->Position = initialPos; throw; } } void Write(Sample16Bit ^sample) { ThrowIfDisposed(); long initialPos = (int)Writer->BaseStream->Position; try { Writer->Write(sample->LeftChannel); if (Header->Stereo) Writer->Write(sample->RightChannel); } catch(Exception ^) { Writer->BaseStream->Position = initialPos; throw; } finally { if (CurrentSample > Header->NumberOfSamples) Header->NumberOfSamples = CurrentSample; } } }; public ref class ToneGener { private: System::Media::SoundPlayer ^player; double frequency; int length; short leftVolume; short rightVolume; int toneTypes; public: ToneGener() { player=nullptr; } property int ToneTypes { int get() { return toneTypes; } void set(int value) { toneTypes = value; } } property double Frequency { double get() { return frequency; } void set(double value) { frequency = value; } } property int Length { int get() { return length; } void set(int value) { length = value; } } property short LeftVolume { short get() { return leftVolume; } void set(short value) { leftVolume = value; } } property short RightVolume { short get() { return rightVolume; } void set(short value) { rightVolume = value; } } void Play() { System::IO::MemoryStream ^ms = gcnew System::IO::MemoryStream(); WaveWriter16Bit ^writer = gcnew WaveWriter16Bit(ms, 44100, true, false); double samplesPerCycle = writer->SampleRate / frequency; int samplesForNote = (int)(writer->SampleRate); Sample16Bit ^sample = gcnew Sample16Bit(true); for (int currentSample = 0; currentSample < samplesForNote; currentSample++) { double sampleValueRight = Func(toneTypes, currentSample, samplesPerCycle, rightVolume); double sampleValueLeft = Func(toneTypes, currentSample, samplesPerCycle, leftVolume); if (sampleValueRight > 35000)sampleValueRight = 35000; else if (sampleValueRight < -35000)sampleValueRight = -35000; if (sampleValueLeft > 35000)sampleValueLeft = 35000; else if (sampleValueLeft < -35000)sampleValueLeft = -35000; sample->LeftChannel = (short)sampleValueLeft; sample->RightChannel = (short)sampleValueRight; writer->Write(sample); } writer->Close(); ms->Position = 0; player = gcnew System::Media::SoundPlayer(ms); player->PlayLooping(); } void Stop() { try { if (player != nullptr) { player->Stop(); } } catch(Exception ^) { } } void Record() { System::Windows::Forms::SaveFileDialog ^sf = gcnew System::Windows::Forms::SaveFileDialog(); sf->Filter = "Save opening file|*.wav"; if (sf->ShowDialog()==System::Windows::Forms::DialogResult::OK && (!File::Exists(sf->FileName))) { FuncForRecord(sf); } else if (File::Exists(sf->FileName)) { if (sf->ShowDialog()==System::Windows::Forms::DialogResult::OK) { File::Delete(sf->FileName); FuncForRecord(sf); } } } void FuncForRecord(System::Windows::Forms::SaveFileDialog ^sf) { WaveWriter16Bit ^writer = gcnew WaveWriter16Bit(gcnew FileStream(sf->FileName, FileMode::Create), 44100, true, false); double samplesPerCycle = writer->SampleRate / frequency; int samplesForNote = (int)(writer->SampleRate * length); Sample16Bit ^sample = gcnew Sample16Bit(true); for (int currentSample = 0; currentSample < samplesForNote; currentSample++) { double sampleValueRight = Func(toneTypes, currentSample, samplesPerCycle, rightVolume); double sampleValueLeft = Func(toneTypes, currentSample, samplesPerCycle, leftVolume); if (sampleValueRight > 0x7FFF)sampleValueRight = 0x7FFF; else if (sampleValueRight < 0x8FFF)sampleValueRight = 0x8FFF; if (sampleValueLeft > 0x7FFF)sampleValueLeft = 0x7FFF; else if (sampleValueLeft < 0x8FFF)sampleValueLeft = 0x8FFF; sample->LeftChannel = (short)sampleValueLeft; sample->RightChannel = (short)sampleValueRight; writer->Write(sample); } } double Func(int toneTypes, int currentSample, double samplesPerCycle, short volume) { switch (toneTypes) { case 1: return Math::Sin(currentSample / samplesPerCycle * 2 * Math::PI) * volume; //break; case 2: return Math::Sign(Math::Sin(currentSample / samplesPerCycle * 2 * Math::PI)) * volume; //break; case 3: return Math::Asin(Math::Sin(currentSample / samplesPerCycle * 2 * Math::PI)) * volume; // break; case 4: return (currentSample / samplesPerCycle - Math::Floor(currentSample / (samplesPerCycle) + 1 / 2)) * 2 * volume; //break; default: return 0; //break; } } }; System::Void SoundClientMain::InitializeSystem() { mToneGener=gcnew ToneGener(); mToneGener->Frequency=440; mToneGener->ToneTypes=1; mToneGener->LeftVolume=10000; mToneGener->RightVolume=20000; mToneGener->Play(); } System::Void SoundClientMain::DestroySystem() { mToneGener->Stop(); } |
Сообщ.
#10
,
|
|
|
Ребят, а если пример воспроизведения буфера для VB6?
|