Ticket #8568: vuvuzela-trunk25124.patch
File vuvuzela-trunk25124.patch, 22.5 KB (added by , 14 years ago) |
---|
-
mythtv/libs/libmythtv/avformatdecoder.cpp
498 498 audioSamples(NULL), 499 499 allow_ac3_passthru(false), allow_dts_passthru(false), 500 500 internal_vol(false), 501 disable_passthru(false), max_channels(2), 502 dummy_frame(NULL), 501 disable_passthru(false), dummy_frame(NULL), 503 502 // DVD 504 503 lastdvdtitle(-1), 505 504 decodeStillFrame(false), … … 4633 4632 // Force pass through state to be reanalyzed 4634 4633 QMutexLocker locker(avcodeclock); 4635 4634 SetupAudioStream(); 4636 } 4635 VERBOSE(VB_AUDIO, LOC + QString("max_channels = %1").arg(max_channels)); 4636 } 4637 4637 } 4638 4638 4639 4639 inline bool AvFormatDecoder::DecoderWillDownmix(const AVCodecContext *ctx) … … 4660 4660 else if (ctx->codec_id == CODEC_ID_DTS) 4661 4661 passthru = allow_dts_passthru && !internal_vol; 4662 4662 4663 passthru &= !GetNVP()->GetAudio()->IsVuvuzela(); 4663 4664 passthru &= !transcoding && !disable_passthru; 4664 4665 // Don't know any cards that support spdif clocked at < 44100 4665 4666 // Some US cable transmissions have 2ch 32k AC-3 streams -
mythtv/libs/libmythtv/tv_play.h
433 433 const QStringList &actions); 434 434 435 435 void ToggleUpmix(PlayerContext*); 436 void ToggleVuvuzela(PlayerContext*); 436 437 void ChangeAudioSync(PlayerContext*, int dir, bool allowEdit = true); 437 438 bool AudioSyncHandleAction(PlayerContext*, const QStringList &actions); 438 439 -
mythtv/libs/libmythtv/audioplayer.cpp
269 269 return toggle; 270 270 } 271 271 272 bool AudioPlayer::ToggleVuvuzela(void) 273 { 274 bool toggle = false; 275 m_lock.lock(); 276 if (m_audioOutput) 277 toggle = m_audioOutput->ToggleVuvuzela(); 278 if (m_parent->GetDecoder()) 279 m_parent->GetDecoder()->SetDisablePassThrough(toggle); 280 m_lock.unlock(); 281 return toggle; 282 } 283 284 bool AudioPlayer::IsVuvuzela(void) 285 { 286 return m_audioOutput ? m_audioOutput->IsVuvuzela() : false; 287 } 288 272 289 void AudioPlayer::SetStretchFactor(float factor) 273 290 { 274 291 m_stretchfactor = factor; -
mythtv/libs/libmythtv/tv_play.cpp
4219 4219 ToggleTimeStretch(ctx); 4220 4220 else if (has_action("TOGGLEUPMIX", actions)) 4221 4221 ToggleUpmix(ctx); 4222 else if (has_action("TOGGLEVUVUZELA", actions)) 4223 ToggleVuvuzela(ctx); 4222 4224 else if (has_action("TOGGLESLEEP", actions)) 4223 4225 ToggleSleepTimer(ctx); 4224 4226 else if (has_action("TOGGLERECORD", actions) && islivetv) … … 7874 7876 SetOSDMessage(ctx, text); 7875 7877 } 7876 7878 7879 void TV::ToggleVuvuzela(PlayerContext *ctx) 7880 { 7881 if (!ctx->nvp || !ctx->nvp->HasAudioOut()) 7882 return; 7883 QString text; 7884 if (ctx->nvp->GetAudio()->ToggleVuvuzela()) 7885 text = tr("Vuvuzela Filter On"); 7886 else 7887 text = tr("Vuvuzela Filter Off"); 7888 7889 if (!browsemode) 7890 SetOSDMessage(ctx, text); 7891 } 7892 7877 7893 // dir in 10ms jumps 7878 7894 void TV::ChangeAudioSync(PlayerContext *ctx, int dir, bool allowEdit) 7879 7895 { … … 9639 9655 ToggleTimeStretch(actx); 9640 9656 else if (action == "TOGGLEUPMIX") 9641 9657 ToggleUpmix(actx); 9658 else if (action == "TOGGLEVUVUZELA") 9659 ToggleVuvuzela(actx); 9642 9660 else if (action.left(13) == "ADJUSTSTRETCH") 9643 9661 { 9644 9662 bool floatRead; … … 9916 9934 9917 9935 if (category == "DVD" && top && (ctx->GetState() == kState_WatchingDVD)) 9918 9936 { 9919 osd->DialogAddButton(tr("DVD Root Menu"), "JUMPTODVDROOTMENU");9920 osd->DialogAddButton(tr("DVD Title Menu"), "JUMPTODVDTITLEMENU");9921 osd->DialogAddButton(tr("DVD Chapter Menu"), "JUMPTODVDCHAPTERMENU");9937 osd->DialogAddButton(tr("DVD Root Menu"), "JUMPTODVDROOTMENU"); 9938 osd->DialogAddButton(tr("DVD Title Menu"), "JUMPTODVDTITLEMENU"); 9939 osd->DialogAddButton(tr("DVD Chapter Menu"), "JUMPTODVDCHAPTERMENU"); 9922 9940 } 9923 9941 else if (category == "GUIDE" && top) 9924 osd->DialogAddButton(tr("Program Guide"), "GUIDE");9942 osd->DialogAddButton(tr("Program Guide"), "GUIDE"); 9925 9943 else if (category == "EDITCHANNEL" && top) 9926 osd->DialogAddButton(tr("Edit Channel"), "EDIT");9944 osd->DialogAddButton(tr("Edit Channel"), "EDIT"); 9927 9945 else if (category == "EDITRECORDING" && top) 9928 osd->DialogAddButton(tr("Edit Recording"), "EDIT");9946 osd->DialogAddButton(tr("Edit Recording"), "EDIT"); 9929 9947 else if (category == "TOGGLEBROWSE" && top && !db_browse_always) 9930 osd->DialogAddButton(tr("Enable Browse Mode"), "TOGGLEBROWSE");9948 osd->DialogAddButton(tr("Enable Browse Mode"), "TOGGLEBROWSE"); 9931 9949 else if ( category == "PREVCHAN" && top) 9932 osd->DialogAddButton(tr("Previous Channel"), "PREVCHAN");9950 osd->DialogAddButton(tr("Previous Channel"), "PREVCHAN"); 9933 9951 else if (category == "AUDIOSYNC" && top) 9934 osd->DialogAddButton(tr("Adjust Audio Sync"), "TOGGLEAUDIOSYNC");9952 osd->DialogAddButton(tr("Adjust Audio Sync"), "TOGGLEAUDIOSYNC"); 9935 9953 else if (category == "TOGGLEUPMIX" && top) 9936 osd->DialogAddButton(tr("Toggle Audio Upmixer"), "TOGGLEUPMIX"); 9954 osd->DialogAddButton(tr("Toggle Audio Upmixer"), "TOGGLEUPMIX"); 9955 else if (category == "TOGGLEVUVUZELA" && top) 9956 osd->DialogAddButton(tr("Toggle Vuvuzela Filter"), "TOGGLEVUVUZELA"); 9937 9957 else if (category == "MANUALZOOM" && mainCtx && top) 9938 osd->DialogAddButton(tr("Manual Zoom Mode"), "TOGGLEMANUALZOOM");9958 osd->DialogAddButton(tr("Manual Zoom Mode"), "TOGGLEMANUALZOOM"); 9939 9959 else if (category == "TRANSCODE") 9940 9960 title = FillOSDMenuTranscode(ctx, osd, select, level); 9941 9961 else if (category == "COMMSKIP") -
mythtv/libs/libmythtv/tvosdmenuentry.cpp
1 1 #include "tvosdmenuentry.h" 2 2 #include "mythdb.h" 3 3 #include "mythverbose.h" 4 #include "mythcorecontext.h" 4 5 5 6 #define LOC QString("OSDMenuEntry:") 6 7 #define LOC_ERR QString("OSDMenuEntry Error:") … … 243 244 "AUDIOSYNC", 1, 1, 1, 1, "Audio Sync")); 244 245 curMenuEntries.append(new TVOSDMenuEntry( 245 246 "TOGGLEUPMIX", 1, 1, 1, 1, "Toggle Upmixer")); 247 if (gCoreContext->GetNumSetting("AdvancedAudioSettings", false) && 248 gCoreContext->GetNumSetting("VuvuzelaFilter", false)) 249 { 250 curMenuEntries.append(new TVOSDMenuEntry( 251 "TOGGLEVUVUZELA", 1, 1, 1, 1, "Toggle Vuvuzela Filter")); 252 } 246 253 curMenuEntries.append(new TVOSDMenuEntry( 247 254 "TIMESTRETCH", 1, 1, 1, 1, "Time Stretch")); 248 255 curMenuEntries.append(new TVOSDMenuEntry( -
mythtv/libs/libmythtv/audioplayer.h
33 33 float GetStretchFactor(void) { return m_stretchfactor; } 34 34 void SetStretchFactor(float factor); 35 35 bool ToggleUpmix(void); 36 bool ToggleVuvuzela(void); 37 bool IsVuvuzela(void); 36 38 long long GetAudioTime(void); 37 39 38 40 bool IsMuted(void) { return GetMuteState() == kMuteAll; } -
mythtv/libs/libmyth/audiooutputbase.h
17 17 // MythTV headers 18 18 #include "audiooutput.h" 19 19 #include "audiooutputsettings.h" 20 #include "audiooutpututil.h" 20 21 #include "samplerate.h" 21 22 #include "mythverbose.h" 22 23 … … 50 51 51 52 virtual bool CanPassthrough(void) const; 52 53 virtual bool ToggleUpmix(void); 54 virtual bool ToggleVuvuzela(void); 55 virtual bool IsVuvuzela(void) { return vuvuzela; } 53 56 54 57 virtual void Reset(void); 55 58 … … 211 214 /** main audio buffer */ 212 215 uchar audiobuffer[kAudioRingBufferSize]; 213 216 uint memory_corruption_test3; 217 218 //Vuvuzela filter 219 bool vuvuzela, last_vuvuzela; 220 AudioOutputUtil::Notch *notch_instance; 214 221 }; 215 222 216 223 #endif -
mythtv/libs/libmyth/audiooutpututil.h
5 5 #include "mythverbose.h" 6 6 #include "audiooutputsettings.h" 7 7 8 #define IIR_NUM_COEFFICIENTS (3) // Assumed biquads 9 8 10 class AudioOutputUtil 9 11 { 10 12 public: 13 14 //Notch Filter / IRR transformation 15 // Parameters 16 typedef struct 17 { 18 uint N; 19 uint num_biquads; 20 float b[IIR_NUM_COEFFICIENTS]; 21 float a[IIR_NUM_COEFFICIENTS]; 22 } IIR_Parameters; 23 24 // State information 25 typedef struct 26 { 27 float a[IIR_NUM_COEFFICIENTS]; 28 float b[IIR_NUM_COEFFICIENTS]; 29 float x_mem[IIR_NUM_COEFFICIENTS]; 30 float y_mem[IIR_NUM_COEFFICIENTS]; 31 } IIR_State; 32 33 // Instance 34 typedef struct 35 { 36 IIR_Parameters parameters; 37 IIR_State state; 38 } IIR; 39 40 // Parameters 41 typedef struct 42 { 43 uint N; 44 float frequency; // Notch frequency 45 float attenuation_dB; // Notch attenuation 46 } Notch_Parameters; 47 48 // State information 49 50 typedef struct 51 { 52 float pole_position; 53 float frequency_offset; 54 float a1s; 55 float a2; 56 float depth_factor; 57 float w0; // Input weight 58 float w1; // Output weight 59 } Notch_State; 60 61 // Instance 62 typedef struct 63 { 64 Notch_Parameters parameters; 65 Notch_State state; 66 IIR iir; 67 } Notch; 68 11 69 static int toFloat(AudioFormat format, void *out, void *in, int bytes); 12 70 static int fromFloat(AudioFormat format, void *out, void *in, int bytes); 13 71 static void MonoToStereo(void *dst, void *src, int samples); … … 15 73 bool music, bool upmix); 16 74 static void MuteChannel(int obits, int channels, int ch, 17 75 void *buffer, int bytes); 76 static void notch_update(Notch &instance, float fs); 77 static void notch_execute(Notch &instance, float *in, float *out); 18 78 }; 19 79 20 80 #endif -
mythtv/libs/libmyth/audiooutputbase.cpp
94 94 memory_corruption_test0(0xdeadbeef), 95 95 memory_corruption_test1(0xdeadbeef), 96 96 memory_corruption_test2(0xdeadbeef), 97 memory_corruption_test3(0xdeadbeef) 97 memory_corruption_test3(0xdeadbeef), 98 vuvuzela(false), last_vuvuzela(false), 99 notch_instance(NULL) 98 100 { 99 101 src_in = (float *)AOALIGN(src_in_buf); 100 102 // The following are not bzero() because MS Windows doesn't like it. … … 240 242 } 241 243 242 244 /** 245 * Toggle Vuvuzela filter 246 */ 247 bool AudioOutputBase::ToggleVuvuzela(void) 248 { 249 // Reset audiobuffer now to prevent click 250 audio_buflock.lock(); 251 avsync_lock.lock(); 252 waud = raud = 0; 253 254 vuvuzela = !vuvuzela; 255 const AudioSettings settings(format, source_channels, codec, 256 source_samplerate, passthru); 257 audio_buflock.unlock(); 258 avsync_lock.unlock(); 259 Reconfigure(settings); 260 261 return vuvuzela; 262 } 263 264 /** 243 265 * (Re)Configure AudioOutputBase 244 266 * 245 267 * Must be called from concrete subclasses … … 303 325 settings.use_passthru == passthru && 304 326 lneeds_upmix == needs_upmix && lreenc == reenc && 305 327 lsource_channels == source_channels && 328 last_vuvuzela == vuvuzela && 306 329 lneeds_downmix == needs_downmix; 307 330 308 331 if (general_deps) … … 311 334 return; 312 335 } 313 336 337 last_vuvuzela = vuvuzela; 338 314 339 KillAudio(); 315 340 316 341 QMutexLocker lock(&audio_buflock); … … 328 353 needs_downmix = lneeds_downmix; 329 354 format = output_format = settings.format; 330 355 source_samplerate = samplerate = settings.samplerate; 356 vuvuzela = last_vuvuzela; 331 357 332 358 killaudio = pauseaudio = false; 333 359 was_paused = true; … … 415 441 // Turn on float conversion? 416 442 if (need_resampler || needs_upmix || needs_downmix || 417 443 stretchfactor != 1.0f || (internal_vol && SWVolume()) || 418 (enc && output_format != FORMAT_S16) || 444 (enc && output_format != FORMAT_S16) || vuvuzela || 419 445 !output_settings->IsSupportedFormat(output_format)) 420 446 { 421 447 VBAUDIO("Audio processing enabled"); … … 426 452 output_format = output_settings->BestSupportedFormat(); 427 453 } 428 454 455 if (vuvuzela) 456 { 457 VBAUDIO("Vuvuzela filter enabled. Go Socceroos Go!"); 458 if (!notch_instance) 459 notch_instance = new AudioOutputUtil::Notch; 460 } 461 429 462 if (passthru) 430 463 channels = 2; // IEC958 bitstream - 2 ch 431 464 … … 560 593 src_ctx = NULL; 561 594 } 562 595 563 needs_upmix = need_resampler = enc = false; 596 if (notch_instance) 597 { 598 delete notch_instance; 599 notch_instance = NULL; 600 } 564 601 602 needs_upmix = need_resampler = enc = vuvuzela = false; 603 565 604 CloseDevice(); 566 605 567 606 killAudioLock.unlock(); … … 943 982 return false; // would overflow 944 983 } 945 984 985 if (vuvuzela && notch_instance) 986 { 987 notch_instance->parameters.N = frames * channels; 988 // Notch attenuation 989 notch_instance->parameters.attenuation_dB = 35.0f; 990 991 // Notch frequency 992 notch_instance->parameters.frequency = 233.0f; 993 AudioOutputUtil::notch_update (*notch_instance, (float)source_samplerate); 994 AudioOutputUtil::notch_execute (*notch_instance, src_in, src_out); 995 notch_instance->parameters.frequency = 466.0f; // 1st harmonic 996 AudioOutputUtil::notch_update (*notch_instance, (float)source_samplerate); 997 AudioOutputUtil::notch_execute (*notch_instance, src_out, src_in); 998 notch_instance->parameters.frequency = 932.0f; // 2nd harmonic 999 AudioOutputUtil::notch_update (*notch_instance, (float)source_samplerate); 1000 AudioOutputUtil::notch_execute (*notch_instance, src_in, src_out); 1001 notch_instance->parameters.frequency = 1864.0f; // 3rd harmonic 1002 AudioOutputUtil::notch_update (*notch_instance, (float)source_samplerate); 1003 AudioOutputUtil::notch_execute (*notch_instance, src_out, src_in); 1004 } 1005 946 1006 // Perform downmix if necessary 947 1007 if (needs_downmix) 948 1008 if(AudioOutputDownmix::DownmixFrames(source_channels, channels, -
mythtv/libs/libmyth/audiooutput.h
69 69 virtual int readOutputData(unsigned char *read_buffer, int max_length) = 0; 70 70 71 71 virtual bool ToggleUpmix(void) = 0; 72 virtual bool ToggleVuvuzela(void) = 0; 73 virtual bool IsVuvuzela(void) = 0; 72 74 73 75 protected: 74 76 void Error(const QString &msg); -
mythtv/libs/libmyth/audiooutpututil.cpp
610 610 else 611 611 _MuteChannel((int *)buffer, channels, ch, frames); 612 612 } 613 614 #define IIR_NUM_COEFFICIENTS (3) // Assumed biquads 615 616 static void iir_update (AudioOutputUtil::IIR &instance) 617 { 618 // Clear the filter state 619 bzero(&instance.state.x_mem[0], IIR_NUM_COEFFICIENTS * sizeof(float)); 620 bzero(&instance.state.y_mem[0], IIR_NUM_COEFFICIENTS * sizeof(float)); 621 622 memcpy(&instance.state.b[0], &instance.parameters.b[0], 623 IIR_NUM_COEFFICIENTS * sizeof(float)); 624 memcpy(&instance.state.a[0], &instance.parameters.a[0], 625 IIR_NUM_COEFFICIENTS * sizeof(float)); 626 } 627 628 /* Notch filter (c) 2010 Hydrix & Jean-Yves Avenard */ 629 /* www.hydrix.com */ 630 631 // Processes a single block of samples with a single IIR biquad stage 632 // N M 633 // SUM a(k+1) y(n-k) = SUM b(k+1) x(n-k) for 1<=n<=length(x) 634 // k=0 k=0 635 // where N=length(a)-1 and M=length(b)-1. 636 // Vector s is the initial state of the system. The final state is also returned 637 // The state vector is a column vector whose length is equal to the 638 // length of the longest coefficient vector minus one. 639 static void iir_biquad (float* x, float* y, 640 float* a, float* b, 641 float* x_mem, float* y_mem, 642 unsigned int N) 643 { 644 // Direct Form I 645 // N+1 N+1 646 // y(n) = - SUM a(k) y(n-k) + SUM b(k) x(n-k) for 0 <= n <length(x) 647 // k=1 k=0 648 unsigned int n = 0; 649 unsigned int k = 0; 650 float y_n_minus_k = 0.0f; 651 float x_n_minus_k = 0.0f; 652 for (n = 0; n < N; n++) 653 { 654 y[n] = x[n] * b[0]; 655 656 for (k = 1; k < IIR_NUM_COEFFICIENTS; k++) 657 { 658 signed int n_minus_k = n - k; 659 if (n_minus_k >= 0) 660 { 661 x_n_minus_k = x[n_minus_k]; 662 y_n_minus_k = y[n_minus_k]; 663 } 664 else 665 { 666 x_n_minus_k = x_mem[-n_minus_k-1]; 667 y_n_minus_k = y_mem[-n_minus_k-1]; 668 } 669 670 y[n] -= a[k] * y_n_minus_k; 671 y[n] += b[k] * x_n_minus_k; 672 } 673 } 674 675 // Save input and output state, latest first 676 unsigned int state_offset = N - 1; 677 for (n=0; n < (IIR_NUM_COEFFICIENTS-1); n++) 678 { 679 x_mem[n] = x[state_offset]; 680 y_mem[n] = y[state_offset]; 681 state_offset--; 682 } 683 } 684 685 static void iir_execute(AudioOutputUtil::IIR &instance, float* x, float* y) 686 { 687 iir_biquad(x, y, 688 &instance.state.a[0], &instance.state.b[0], 689 &instance.state.x_mem[0], &instance.state.y_mem[0], 690 instance.parameters.N); 691 } 692 693 // Notch filter 694 #define PI_FLOAT (3.14159265358979f) 695 #define LN2_FLOAT (0.69314718055994530942f) 696 697 void AudioOutputUtil::notch_update (Notch &instance, float fs) 698 { 699 instance.state.pole_position = 0.99f; 700 instance.state.frequency_offset = 0.0f; // in normalised frequency (1.0 = fs) 701 instance.state.a1s = -instance.state.pole_position; 702 instance.state.a2 = -(instance.state.pole_position * instance.state.pole_position); 703 instance.state.depth_factor = 0.999f; 704 705 // Calculate filter coefficients 706 // Direct-form IIR 707 // Ref: http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt and others 708 float normalised_notch_frequency = (2.0f * instance.parameters.frequency / fs); 709 normalised_notch_frequency += instance.state.frequency_offset; 710 float frequency_factor = -2.0f * cosf(PI_FLOAT * normalised_notch_frequency); 711 float a1 = frequency_factor * instance.state.a1s; 712 float a2 = instance.state.a2; 713 float b1 = frequency_factor * instance.state.depth_factor; 714 float b2 = instance.state.depth_factor * instance.state.depth_factor; 715 instance.iir.parameters.N = instance.parameters.N; 716 instance.iir.parameters.a[0] = 1.0f; 717 instance.iir.parameters.a[1] = -a1; 718 instance.iir.parameters.a[2] = -a2; 719 instance.iir.parameters.b[0] = 1.0f; 720 instance.iir.parameters.b[1] = b1; 721 instance.iir.parameters.b[2] = b2; 722 723 // Initialise the IIR stage 724 iir_update(instance.iir); 725 726 // The notch filter strongly attenuates at the notch frequency. 727 // The output is the weighted sum of the input and the 728 // notch-filtered input. The weights are calculated from the 729 // attenuation parameters 730 // instance.state.w0 = pow(10.0, (-instance.parameters.attenuation_dB / 20.0)); 731 // instance.state.w1 = 1.0 - instance.state.w0; 732 float w0 = powf(10.0f, (-instance.parameters.attenuation_dB / 20.0f)); 733 float w1 = 1.0f - w0; 734 instance.state.w0 = w0; 735 instance.state.w1 = w1; 736 737 return; 738 } 739 740 // Processes a single block of samples 741 void AudioOutputUtil::notch_execute (Notch &instance, float *in, float *out) 742 { 743 // Apply the rejection filter 744 iir_execute(instance.iir, in, out); 745 746 // The output is the weighted sum of the input and the 747 // notch-filtered input 748 for (uint i=0; i < instance.parameters.N; i++) 749 { 750 out[i] *= instance.state.w1; 751 out[i] += instance.state.w0 * in[i]; 752 } 753 } -
mythtv/programs/mythfrontend/globalsettings.cpp
219 219 return gc; 220 220 } 221 221 222 static HostCheckBox *VuvuzelaFilter() 223 { 224 HostCheckBox *gc = new HostCheckBox("VuvuzelaFilter"); 225 gc->setLabel(QObject::tr("Enable vuvuzela filter")); 226 gc->setValue(false); 227 gc->setHelpText(QObject::tr("With this option enabled, a dedicated vuvuzela " 228 "filter option will be accessible in the playback " 229 "menu")); 230 return gc; 231 } 232 222 233 static HostCheckBox *MythControlsVolume() 223 234 { 224 235 HostCheckBox *gc = new HostCheckBox("MythControlsVolume"); … … 3301 3312 settings4->addChild(srcqualityoverride); 3302 3313 settings4->addChild(sub4); 3303 3314 3315 group2->addChild(VuvuzelaFilter()); 3304 3316 group2->addChild(settings4); 3305 3317 group2->addChild(Audio48kOverride()); 3306 3318 group2->addChild(settings3); -
mythtv/programs/mythtranscode/transcode.cpp
186 186 // Do nothing 187 187 return false; 188 188 } 189 189 virtual bool ToggleVuvuzela(void) 190 { 191 // Do nothing 192 return false; 193 } 194 virtual bool IsVuvuzela(void) 195 { 196 // Do nothing 197 return false; 198 } 190 199 virtual void SetSWVolume(int new_volume, bool save) 191 200 { 192 201 // Do nothing