| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2013 - Raw Material Software Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE 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.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace CDBurnerHelpers
 - {
 -     IDiscRecorder* enumCDBurners (StringArray* list, int indexToOpen, IDiscMaster** master)
 -     {
 -         CoInitialize (0);
 - 
 -         IDiscMaster* dm;
 -         IDiscRecorder* result = nullptr;
 - 
 -         if (SUCCEEDED (CoCreateInstance (CLSID_MSDiscMasterObj, 0,
 -                                          CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
 -                                          IID_IDiscMaster,
 -                                          (void**) &dm)))
 -         {
 -             if (SUCCEEDED (dm->Open()))
 -             {
 -                 IEnumDiscRecorders* drEnum = nullptr;
 - 
 -                 if (SUCCEEDED (dm->EnumDiscRecorders (&drEnum)))
 -                 {
 -                     IDiscRecorder* dr = nullptr;
 -                     DWORD dummy;
 -                     int index = 0;
 - 
 -                     while (drEnum->Next (1, &dr, &dummy) == S_OK)
 -                     {
 -                         if (indexToOpen == index)
 -                         {
 -                             result = dr;
 -                             break;
 -                         }
 -                         else if (list != nullptr)
 -                         {
 -                             BSTR path;
 - 
 -                             if (SUCCEEDED (dr->GetPath (&path)))
 -                                 list->add ((const WCHAR*) path);
 -                         }
 - 
 -                         ++index;
 -                         dr->Release();
 -                     }
 - 
 -                     drEnum->Release();
 -                 }
 - 
 -                 if (master == 0)
 -                     dm->Close();
 -             }
 - 
 -             if (master != nullptr)
 -                 *master = dm;
 -             else
 -                 dm->Release();
 -         }
 - 
 -         return result;
 -     }
 - }
 - 
 - //==============================================================================
 - class AudioCDBurner::Pimpl  : public ComBaseClassHelper <IDiscMasterProgressEvents>,
 -                               public Timer
 - {
 - public:
 -     Pimpl (AudioCDBurner& owner_, IDiscMaster* discMaster_, IDiscRecorder* discRecorder_)
 -       : owner (owner_), discMaster (discMaster_), discRecorder (discRecorder_), redbook (0),
 -         listener (0), progress (0), shouldCancel (false)
 -     {
 -         HRESULT hr = discMaster->SetActiveDiscMasterFormat (IID_IRedbookDiscMaster, (void**) &redbook);
 -         jassert (SUCCEEDED (hr));
 -         hr = discMaster->SetActiveDiscRecorder (discRecorder);
 -         //jassert (SUCCEEDED (hr));
 - 
 -         lastState = getDiskState();
 -         startTimer (2000);
 -     }
 - 
 -     ~Pimpl()  {}
 - 
 -     void releaseObjects()
 -     {
 -         discRecorder->Close();
 -         if (redbook != nullptr)
 -             redbook->Release();
 -         discRecorder->Release();
 -         discMaster->Release();
 -         Release();
 -     }
 - 
 -     JUCE_COMRESULT QueryCancel (boolean* pbCancel)
 -     {
 -         if (listener != nullptr && ! shouldCancel)
 -             shouldCancel = listener->audioCDBurnProgress (progress);
 - 
 -         *pbCancel = shouldCancel;
 - 
 -         return S_OK;
 -     }
 - 
 -     JUCE_COMRESULT NotifyBlockProgress (long nCompleted, long nTotal)
 -     {
 -         progress = nCompleted / (float) nTotal;
 -         shouldCancel = listener != nullptr && listener->audioCDBurnProgress (progress);
 - 
 -         return E_NOTIMPL;
 -     }
 - 
 -     JUCE_COMRESULT NotifyPnPActivity (void)                              { return E_NOTIMPL; }
 -     JUCE_COMRESULT NotifyAddProgress (long /*nCompletedSteps*/, long /*nTotalSteps*/)    { return E_NOTIMPL; }
 -     JUCE_COMRESULT NotifyTrackProgress (long /*nCurrentTrack*/, long /*nTotalTracks*/)   { return E_NOTIMPL; }
 -     JUCE_COMRESULT NotifyPreparingBurn (long /*nEstimatedSeconds*/)      { return E_NOTIMPL; }
 -     JUCE_COMRESULT NotifyClosingDisc (long /*nEstimatedSeconds*/)        { return E_NOTIMPL; }
 -     JUCE_COMRESULT NotifyBurnComplete (HRESULT /*status*/)               { return E_NOTIMPL; }
 -     JUCE_COMRESULT NotifyEraseComplete (HRESULT /*status*/)              { return E_NOTIMPL; }
 - 
 -     class ScopedDiscOpener
 -     {
 -     public:
 -         ScopedDiscOpener (Pimpl& p) : pimpl (p) { pimpl.discRecorder->OpenExclusive(); }
 -         ~ScopedDiscOpener()                     { pimpl.discRecorder->Close(); }
 - 
 -     private:
 -         Pimpl& pimpl;
 - 
 -         JUCE_DECLARE_NON_COPYABLE (ScopedDiscOpener)
 -     };
 - 
 -     DiskState getDiskState()
 -     {
 -         const ScopedDiscOpener opener (*this);
 - 
 -         long type, flags;
 -         HRESULT hr = discRecorder->QueryMediaType (&type, &flags);
 - 
 -         if (FAILED (hr))
 -             return unknown;
 - 
 -         if (type != 0 && (flags & MEDIA_WRITABLE) != 0)
 -             return writableDiskPresent;
 - 
 -         if (type == 0)
 -             return noDisc;
 - 
 -         return readOnlyDiskPresent;
 -     }
 - 
 -     int getIntProperty (const LPOLESTR name, const int defaultReturn) const
 -     {
 -         ComSmartPtr<IPropertyStorage> prop;
 -         if (FAILED (discRecorder->GetRecorderProperties (prop.resetAndGetPointerAddress())))
 -             return defaultReturn;
 - 
 -         PROPSPEC iPropSpec;
 -         iPropSpec.ulKind = PRSPEC_LPWSTR;
 -         iPropSpec.lpwstr = name;
 - 
 -         PROPVARIANT iPropVariant;
 -         return FAILED (prop->ReadMultiple (1, &iPropSpec, &iPropVariant))
 -                    ? defaultReturn : (int) iPropVariant.lVal;
 -     }
 - 
 -     bool setIntProperty (const LPOLESTR name, const int value) const
 -     {
 -         ComSmartPtr<IPropertyStorage> prop;
 -         if (FAILED (discRecorder->GetRecorderProperties (prop.resetAndGetPointerAddress())))
 -             return false;
 - 
 -         PROPSPEC iPropSpec;
 -         iPropSpec.ulKind = PRSPEC_LPWSTR;
 -         iPropSpec.lpwstr = name;
 - 
 -         PROPVARIANT iPropVariant;
 -         if (FAILED (prop->ReadMultiple (1, &iPropSpec, &iPropVariant)))
 -             return false;
 - 
 -         iPropVariant.lVal = (long) value;
 -         return SUCCEEDED (prop->WriteMultiple (1, &iPropSpec, &iPropVariant, iPropVariant.vt))
 -                 && SUCCEEDED (discRecorder->SetRecorderProperties (prop));
 -     }
 - 
 -     void timerCallback() override
 -     {
 -         const DiskState state = getDiskState();
 - 
 -         if (state != lastState)
 -         {
 -             lastState = state;
 -             owner.sendChangeMessage();
 -         }
 -     }
 - 
 -     AudioCDBurner& owner;
 -     DiskState lastState;
 -     IDiscMaster* discMaster;
 -     IDiscRecorder* discRecorder;
 -     IRedbookDiscMaster* redbook;
 -     AudioCDBurner::BurnProgressListener* listener;
 -     float progress;
 -     bool shouldCancel;
 - };
 - 
 - //==============================================================================
 - AudioCDBurner::AudioCDBurner (const int deviceIndex)
 - {
 -     IDiscMaster* discMaster = nullptr;
 -     IDiscRecorder* discRecorder = CDBurnerHelpers::enumCDBurners (0, deviceIndex, &discMaster);
 - 
 -     if (discRecorder != nullptr)
 -         pimpl = new Pimpl (*this, discMaster, discRecorder);
 - }
 - 
 - AudioCDBurner::~AudioCDBurner()
 - {
 -     if (pimpl != nullptr)
 -         pimpl.release()->releaseObjects();
 - }
 - 
 - StringArray AudioCDBurner::findAvailableDevices()
 - {
 -     StringArray devs;
 -     CDBurnerHelpers::enumCDBurners (&devs, -1, 0);
 -     return devs;
 - }
 - 
 - AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
 - {
 -     ScopedPointer<AudioCDBurner> b (new AudioCDBurner (deviceIndex));
 - 
 -     if (b->pimpl == 0)
 -         b = nullptr;
 - 
 -     return b.release();
 - }
 - 
 - AudioCDBurner::DiskState AudioCDBurner::getDiskState() const
 - {
 -     return pimpl->getDiskState();
 - }
 - 
 - bool AudioCDBurner::isDiskPresent() const
 - {
 -     return getDiskState() == writableDiskPresent;
 - }
 - 
 - bool AudioCDBurner::openTray()
 - {
 -     const Pimpl::ScopedDiscOpener opener (*pimpl);
 -     return SUCCEEDED (pimpl->discRecorder->Eject());
 - }
 - 
 - AudioCDBurner::DiskState AudioCDBurner::waitUntilStateChange (int timeOutMilliseconds)
 - {
 -     const int64 timeout = Time::currentTimeMillis() + timeOutMilliseconds;
 -     DiskState oldState = getDiskState();
 -     DiskState newState = oldState;
 - 
 -     while (newState == oldState && Time::currentTimeMillis() < timeout)
 -     {
 -         newState = getDiskState();
 -         Thread::sleep (jmin (250, (int) (timeout - Time::currentTimeMillis())));
 -     }
 - 
 -     return newState;
 - }
 - 
 - Array<int> AudioCDBurner::getAvailableWriteSpeeds() const
 - {
 -     Array<int> results;
 -     const int maxSpeed = pimpl->getIntProperty (L"MaxWriteSpeed", 1);
 -     const int speeds[] = { 1, 2, 4, 8, 12, 16, 20, 24, 32, 40, 64, 80 };
 - 
 -     for (int i = 0; i < numElementsInArray (speeds); ++i)
 -         if (speeds[i] <= maxSpeed)
 -             results.add (speeds[i]);
 - 
 -     results.addIfNotAlreadyThere (maxSpeed);
 -     return results;
 - }
 - 
 - bool AudioCDBurner::setBufferUnderrunProtection (const bool shouldBeEnabled)
 - {
 -     if (pimpl->getIntProperty (L"BufferUnderrunFreeCapable", 0) == 0)
 -         return false;
 - 
 -     pimpl->setIntProperty (L"EnableBufferUnderrunFree", shouldBeEnabled ? -1 : 0);
 -     return pimpl->getIntProperty (L"EnableBufferUnderrunFree", 0) != 0;
 - }
 - 
 - int AudioCDBurner::getNumAvailableAudioBlocks() const
 - {
 -     long blocksFree = 0;
 -     pimpl->redbook->GetAvailableAudioTrackBlocks (&blocksFree);
 -     return blocksFree;
 - }
 - 
 - String AudioCDBurner::burn (AudioCDBurner::BurnProgressListener* listener, bool ejectDiscAfterwards,
 -                             bool performFakeBurnForTesting, int writeSpeed)
 - {
 -     pimpl->setIntProperty (L"WriteSpeed", writeSpeed > 0 ? writeSpeed : -1);
 - 
 -     pimpl->listener = listener;
 -     pimpl->progress = 0;
 -     pimpl->shouldCancel = false;
 - 
 -     UINT_PTR cookie;
 -     HRESULT hr = pimpl->discMaster->ProgressAdvise ((AudioCDBurner::Pimpl*) pimpl, &cookie);
 - 
 -     hr = pimpl->discMaster->RecordDisc (performFakeBurnForTesting,
 -                                         ejectDiscAfterwards);
 - 
 -     String error;
 -     if (hr != S_OK)
 -     {
 -         const char* e = "Couldn't open or write to the CD device";
 - 
 -         if (hr == IMAPI_E_USERABORT)
 -             e = "User cancelled the write operation";
 -         else if (hr == IMAPI_E_MEDIUM_NOTPRESENT || hr == IMAPI_E_TRACKOPEN)
 -             e = "No Disk present";
 - 
 -         error = e;
 -     }
 - 
 -     pimpl->discMaster->ProgressUnadvise (cookie);
 -     pimpl->listener = 0;
 - 
 -     return error;
 - }
 - 
 - bool AudioCDBurner::addAudioTrack (AudioSource* audioSource, int numSamples)
 - {
 -     if (audioSource == 0)
 -         return false;
 - 
 -     ScopedPointer<AudioSource> source (audioSource);
 - 
 -     long bytesPerBlock;
 -     HRESULT hr = pimpl->redbook->GetAudioBlockSize (&bytesPerBlock);
 - 
 -     const int samplesPerBlock = bytesPerBlock / 4;
 -     bool ok = true;
 - 
 -     hr = pimpl->redbook->CreateAudioTrack ((long) numSamples / (bytesPerBlock * 4));
 - 
 -     HeapBlock <byte> buffer (bytesPerBlock);
 -     AudioSampleBuffer sourceBuffer (2, samplesPerBlock);
 -     int samplesDone = 0;
 - 
 -     source->prepareToPlay (samplesPerBlock, 44100.0);
 - 
 -     while (ok)
 -     {
 -         {
 -             AudioSourceChannelInfo info (&sourceBuffer, 0, samplesPerBlock);
 -             sourceBuffer.clear();
 - 
 -             source->getNextAudioBlock (info);
 -         }
 - 
 -         buffer.clear (bytesPerBlock);
 - 
 -         typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian,
 -                                     AudioData::Interleaved, AudioData::NonConst> CDSampleFormat;
 - 
 -         typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian,
 -                                     AudioData::NonInterleaved, AudioData::Const> SourceSampleFormat;
 - 
 -         CDSampleFormat left (buffer, 2);
 -         left.convertSamples (SourceSampleFormat (sourceBuffer.getReadPointer (0)), samplesPerBlock);
 -         CDSampleFormat right (buffer + 2, 2);
 -         right.convertSamples (SourceSampleFormat (sourceBuffer.getReadPointer (1)), samplesPerBlock);
 - 
 -         hr = pimpl->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);
 - 
 -         if (FAILED (hr))
 -             ok = false;
 - 
 -         samplesDone += samplesPerBlock;
 - 
 -         if (samplesDone >= numSamples)
 -             break;
 -     }
 - 
 -     hr = pimpl->redbook->CloseAudioTrack();
 -     return ok && hr == S_OK;
 - }
 
 
  |