// // This file is part of Dire Wolf, an amateur radio packet TNC. // // Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // /*------------------------------------------------------------------ * * Module: audio_ptt_win.c * * Purpose: Interface to audio device commonly called a "sound card" for * historical reasons. * * This version uses the native Windows sound interface. * *---------------------------------------------------------------*/ #if __WIN32__ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef WAVE_FORMAT_96M16 #define WAVE_FORMAT_96M16 0x40000 #define WAVE_FORMAT_96S16 0x80000 #endif #include "direwolf.h" #include "audio.h" #include "audio_stats.h" #include "textcolor.h" #include "ptt.h" #include "demod.h" /* for alevel_t & demod_get_audio_level() */ #include "audio_ptt.h" static struct audio_s *save_audio_config_p; static unsigned __stdcall ptt_thread ( void *arg ); HANDLE start_ptt_thread (struct audio_s *pa , int ch) { save_audio_config_p = pa; return (HANDLE)_beginthreadex (NULL, 0, ptt_thread, (void*)(long)ch, 0, NULL); } unsigned __stdcall ptt_thread (void *arg) { WAVEFORMATEX wf; HWAVEOUT hWaveOut; int ch = (int)(long)arg; // channel number. int channel = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel; int freq = save_audio_config_p->achan[channel].octrl[OCTYPE_PTT].ptt_frequency; int a = ACHAN2ADEV( channel ); int err; if (save_audio_config_p->adev[a].defined) { wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = save_audio_config_p->adev[a].num_channels; wf.nSamplesPerSec = save_audio_config_p->adev[a].samples_per_sec; wf.wBitsPerSample = save_audio_config_p->adev[a].bits_per_sample; wf.nBlockAlign = ( wf.wBitsPerSample / 8 ) * wf.nChannels; wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; wf.cbSize = 0; /* * Open the audio output device. * Soundcard is only possibility at this time. */ err = waveOutOpen ( &hWaveOut, atoi( save_audio_config_p->adev[a].adevice_out ), &wf, (DWORD_PTR)NULL, 0, CALLBACK_NULL ); if (err == MMSYSERR_NOERROR) { WAVEHDR waveHeader; short* pnData; short sample; int nSamples = save_audio_config_p->adev[a].samples_per_sec / freq; int i; int j; waveHeader.dwBufferLength = save_audio_config_p->adev[a].num_channels * nSamples * sizeof( short ); waveHeader.lpData = malloc( waveHeader.dwBufferLength ); waveHeader.dwUser = 0; waveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; waveHeader.dwLoops = 0xFFFF; pnData = (short*)waveHeader.lpData; for (i = 0; i < nSamples; i++) { sample = (short)( (double)SHRT_MAX * sin( ( (double)i / (double)nSamples ) * 2.0 * M_PI ) ); for (j = 0; j < save_audio_config_p->adev[a].num_channels; j++) { if (channel == ADEVFIRSTCHAN( a ) + j) { pnData[i*save_audio_config_p->adev[a].num_channels + j] = sample; } else { pnData[i*save_audio_config_p->adev[a].num_channels + j] = 0; } } } err = waveOutPrepareHeader (hWaveOut, &waveHeader, sizeof( WAVEHDR )); if (err == MMSYSERR_NOERROR) { HANDLE handles[3]; DWORD dwWait; handles[0] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_start; handles[1] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_stop; handles[2] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_close; while (1) { dwWait = WaitForMultipleObjects (3, handles, FALSE, INFINITE); if (dwWait == WAIT_OBJECT_0 + 0) { // // ptt_set on // waveOutWrite ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) ); } else if (dwWait == WAIT_OBJECT_0 + 1) { // // ptt_set off // waveOutReset ( hWaveOut ); } else if (dwWait == WAIT_OBJECT_0 + 2) { // // close // waveOutReset (hWaveOut); waveOutUnprepareHeader (hWaveOut, &waveHeader, sizeof(WAVEHDR)); break; } } } waveOutClose ( hWaveOut ); free( waveHeader.lpData ); } } return 0; } #endif