mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
This commit is contained in:
parent
80ab76f672
commit
ad0f73dad6
26 changed files with 5535 additions and 3896 deletions
|
|
@ -1,191 +1,191 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/network/IOEthernetInterface.h>
|
||||
#include <IOKit/network/IONetworkInterface.h>
|
||||
#include <IOKit/network/IOEthernetController.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_core/text/juce_String.h"
|
||||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/basics/juce_SystemStats.h"
|
||||
#include "../../../src/juce_core/containers/juce_MemoryBlock.h"
|
||||
#include "../../../src/juce_core/text/juce_StringArray.h"
|
||||
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
||||
#include "../../../src/juce_core/io/network/juce_URL.h"
|
||||
#include "juce_mac_HTTPStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static bool GetEthernetIterator (io_iterator_t* matchingServices) throw()
|
||||
{
|
||||
mach_port_t masterPort;
|
||||
|
||||
if (IOMasterPort (MACH_PORT_NULL, &masterPort) == KERN_SUCCESS)
|
||||
{
|
||||
CFMutableDictionaryRef dict = IOServiceMatching (kIOEthernetInterfaceClass);
|
||||
|
||||
if (dict != 0)
|
||||
{
|
||||
CFMutableDictionaryRef propDict = CFDictionaryCreateMutable (kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (propDict != 0)
|
||||
{
|
||||
CFDictionarySetValue (propDict, CFSTR (kIOPrimaryInterface), kCFBooleanTrue);
|
||||
|
||||
CFDictionarySetValue (dict, CFSTR (kIOPropertyMatchKey), propDict);
|
||||
CFRelease (propDict);
|
||||
}
|
||||
}
|
||||
|
||||
return IOServiceGetMatchingServices (masterPort, dict, matchingServices) == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
|
||||
{
|
||||
int numResults = 0;
|
||||
io_iterator_t it;
|
||||
|
||||
if (GetEthernetIterator (&it))
|
||||
{
|
||||
io_object_t i;
|
||||
|
||||
while ((i = IOIteratorNext (it)) != 0)
|
||||
{
|
||||
io_object_t controller;
|
||||
|
||||
if (IORegistryEntryGetParentEntry (i, kIOServicePlane, &controller) == KERN_SUCCESS)
|
||||
{
|
||||
CFTypeRef data = IORegistryEntryCreateCFProperty (controller,
|
||||
CFSTR (kIOMACAddress),
|
||||
kCFAllocatorDefault,
|
||||
0);
|
||||
if (data != 0)
|
||||
{
|
||||
UInt8 addr [kIOEthernetAddressSize];
|
||||
zeromem (addr, sizeof (addr));
|
||||
|
||||
CFDataGetBytes ((CFDataRef) data, CFRangeMake (0, sizeof (addr)), addr);
|
||||
CFRelease (data);
|
||||
|
||||
int64 a = 0;
|
||||
for (int i = 6; --i >= 0;)
|
||||
a = (a << 8) | addr[i];
|
||||
|
||||
if (! littleEndian)
|
||||
a = (int64) swapByteOrder ((uint64) a);
|
||||
|
||||
if (numResults < maxNum)
|
||||
{
|
||||
*addresses++ = a;
|
||||
++numResults;
|
||||
}
|
||||
}
|
||||
|
||||
IOObjectRelease (controller);
|
||||
}
|
||||
|
||||
IOObjectRelease (i);
|
||||
}
|
||||
|
||||
IOObjectRelease (it);
|
||||
}
|
||||
|
||||
return numResults;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
String script;
|
||||
script << "tell application \"Mail\"\r\n"
|
||||
"set newMessage to make new outgoing message with properties {subject:\""
|
||||
<< emailSubject
|
||||
<< "\", content:\""
|
||||
<< bodyText
|
||||
<< "\" & return & return}\r\n"
|
||||
"tell newMessage\r\n"
|
||||
"set visible to true\r\n"
|
||||
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||
"make new to recipient at end of to recipients with properties {address:\""
|
||||
<< targetEmailAddress
|
||||
<< "\"}\r\n";
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
script << "tell content\r\n"
|
||||
"make new attachment with properties {file name:\""
|
||||
<< filesToAttach[i]
|
||||
<< "\"} at after the last paragraph\r\n"
|
||||
"end tell\r\n";
|
||||
}
|
||||
|
||||
script << "end tell\r\n"
|
||||
"end tell\r\n";
|
||||
|
||||
DBG (script);
|
||||
ComponentInstance comp = OpenDefaultComponent (kOSAComponentType, kOSAGenericScriptingComponentSubtype);
|
||||
|
||||
OSAID resultID;
|
||||
AEDesc source;
|
||||
AECreateDesc (typeUTF8Text, (Ptr) script.toUTF8(), strlen (script.toUTF8()), &source);
|
||||
OSAError err = OSACompileExecute (comp, &source,
|
||||
kOSANullScript, kOSAModeNull,
|
||||
&resultID);
|
||||
AEDisposeDesc (&source);
|
||||
CloseComponent (comp);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/network/IOEthernetInterface.h>
|
||||
#include <IOKit/network/IONetworkInterface.h>
|
||||
#include <IOKit/network/IOEthernetController.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_core/text/juce_String.h"
|
||||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/basics/juce_SystemStats.h"
|
||||
#include "../../../src/juce_core/containers/juce_MemoryBlock.h"
|
||||
#include "../../../src/juce_core/text/juce_StringArray.h"
|
||||
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
||||
#include "../../../src/juce_core/io/network/juce_URL.h"
|
||||
#include "juce_mac_HTTPStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static bool GetEthernetIterator (io_iterator_t* matchingServices) throw()
|
||||
{
|
||||
mach_port_t masterPort;
|
||||
|
||||
if (IOMasterPort (MACH_PORT_NULL, &masterPort) == KERN_SUCCESS)
|
||||
{
|
||||
CFMutableDictionaryRef dict = IOServiceMatching (kIOEthernetInterfaceClass);
|
||||
|
||||
if (dict != 0)
|
||||
{
|
||||
CFMutableDictionaryRef propDict = CFDictionaryCreateMutable (kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (propDict != 0)
|
||||
{
|
||||
CFDictionarySetValue (propDict, CFSTR (kIOPrimaryInterface), kCFBooleanTrue);
|
||||
|
||||
CFDictionarySetValue (dict, CFSTR (kIOPropertyMatchKey), propDict);
|
||||
CFRelease (propDict);
|
||||
}
|
||||
}
|
||||
|
||||
return IOServiceGetMatchingServices (masterPort, dict, matchingServices) == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
|
||||
{
|
||||
int numResults = 0;
|
||||
io_iterator_t it;
|
||||
|
||||
if (GetEthernetIterator (&it))
|
||||
{
|
||||
io_object_t i;
|
||||
|
||||
while ((i = IOIteratorNext (it)) != 0)
|
||||
{
|
||||
io_object_t controller;
|
||||
|
||||
if (IORegistryEntryGetParentEntry (i, kIOServicePlane, &controller) == KERN_SUCCESS)
|
||||
{
|
||||
CFTypeRef data = IORegistryEntryCreateCFProperty (controller,
|
||||
CFSTR (kIOMACAddress),
|
||||
kCFAllocatorDefault,
|
||||
0);
|
||||
if (data != 0)
|
||||
{
|
||||
UInt8 addr [kIOEthernetAddressSize];
|
||||
zeromem (addr, sizeof (addr));
|
||||
|
||||
CFDataGetBytes ((CFDataRef) data, CFRangeMake (0, sizeof (addr)), addr);
|
||||
CFRelease (data);
|
||||
|
||||
int64 a = 0;
|
||||
for (int i = 6; --i >= 0;)
|
||||
a = (a << 8) | addr[i];
|
||||
|
||||
if (! littleEndian)
|
||||
a = (int64) swapByteOrder ((uint64) a);
|
||||
|
||||
if (numResults < maxNum)
|
||||
{
|
||||
*addresses++ = a;
|
||||
++numResults;
|
||||
}
|
||||
}
|
||||
|
||||
IOObjectRelease (controller);
|
||||
}
|
||||
|
||||
IOObjectRelease (i);
|
||||
}
|
||||
|
||||
IOObjectRelease (it);
|
||||
}
|
||||
|
||||
return numResults;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
String script;
|
||||
script << "tell application \"Mail\"\r\n"
|
||||
"set newMessage to make new outgoing message with properties {subject:\""
|
||||
<< emailSubject
|
||||
<< "\", content:\""
|
||||
<< bodyText
|
||||
<< "\" & return & return}\r\n"
|
||||
"tell newMessage\r\n"
|
||||
"set visible to true\r\n"
|
||||
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||
"make new to recipient at end of to recipients with properties {address:\""
|
||||
<< targetEmailAddress
|
||||
<< "\"}\r\n";
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
script << "tell content\r\n"
|
||||
"make new attachment with properties {file name:\""
|
||||
<< filesToAttach[i]
|
||||
<< "\"} at after the last paragraph\r\n"
|
||||
"end tell\r\n";
|
||||
}
|
||||
|
||||
script << "end tell\r\n"
|
||||
"end tell\r\n";
|
||||
|
||||
DBG (script);
|
||||
ComponentInstance comp = OpenDefaultComponent (kOSAComponentType, kOSAGenericScriptingComponentSubtype);
|
||||
|
||||
OSAID resultID;
|
||||
AEDesc source;
|
||||
AECreateDesc (typeUTF8Text, (Ptr) script.toUTF8(), strlen (script.toUTF8()), &source);
|
||||
OSAError err = OSACompileExecute (comp, &source,
|
||||
kOSANullScript, kOSAModeNull,
|
||||
&resultID);
|
||||
AEDisposeDesc (&source);
|
||||
CloseComponent (comp);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ bool JUCE_CALLTYPE juce_isRunningUnderDebugger() throw()
|
|||
int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
|
||||
size_t sz = sizeof (info);
|
||||
sysctl (m, 4, &info, &sz, 0, 0);
|
||||
testResult = (info.kp_proc.p_flag & P_TRACED) == P_TRACED ? 1 : -1;
|
||||
testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
return testResult > 0;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -36,13 +36,18 @@
|
|||
|
||||
#include "win32_headers.h"
|
||||
#include <stddef.h>
|
||||
#include <imapi.h>
|
||||
#include <imapierror.h>
|
||||
|
||||
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_appframework/audio/audio_file_formats/juce_AudioCDReader.h"
|
||||
#include "../../../src/juce_appframework/audio/audio_file_formats/juce_AudioCDBurner.h"
|
||||
#include "../../../src/juce_appframework/events/juce_Timer.h"
|
||||
#include "../../../src/juce_appframework/application/juce_DeletedAtShutdown.h"
|
||||
#include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
|
|
@ -2108,4 +2113,381 @@ void AudioCDReader::ejectDisk()
|
|||
((CDDeviceWrapper*) handle)->cdH->openDrawer (true);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static IDiscRecorder* enumCDBurners (StringArray* list, int indexToOpen, IDiscMaster** master)
|
||||
{
|
||||
CoInitialize (0);
|
||||
|
||||
IDiscMaster* dm;
|
||||
IDiscRecorder* result = 0;
|
||||
|
||||
if (SUCCEEDED (CoCreateInstance (CLSID_MSDiscMasterObj, 0,
|
||||
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
|
||||
IID_IDiscMaster,
|
||||
(void**) &dm)))
|
||||
{
|
||||
if (SUCCEEDED (dm->Open()))
|
||||
{
|
||||
IEnumDiscRecorders* drEnum = 0;
|
||||
|
||||
if (SUCCEEDED (dm->EnumDiscRecorders (&drEnum)))
|
||||
{
|
||||
IDiscRecorder* dr = 0;
|
||||
DWORD dummy;
|
||||
int index = 0;
|
||||
|
||||
while (drEnum->Next (1, &dr, &dummy) == S_OK)
|
||||
{
|
||||
if (indexToOpen == index)
|
||||
{
|
||||
result = dr;
|
||||
break;
|
||||
}
|
||||
else if (list != 0)
|
||||
{
|
||||
BSTR path;
|
||||
|
||||
if (SUCCEEDED (dr->GetPath (&path)))
|
||||
list->add ((const WCHAR*) path);
|
||||
}
|
||||
|
||||
++index;
|
||||
dr->Release();
|
||||
}
|
||||
|
||||
drEnum->Release();
|
||||
}
|
||||
|
||||
/*if (redbookFormat != 0)
|
||||
{
|
||||
IEnumDiscMasterFormats* mfEnum;
|
||||
|
||||
if (SUCCEEDED (dm->EnumDiscMasterFormats (&mfEnum)))
|
||||
{
|
||||
IID formatIID;
|
||||
DWORD dummy;
|
||||
|
||||
while (mfEnum->Next (1, &formatIID, &dummy) == S_OK)
|
||||
{
|
||||
}
|
||||
|
||||
mfEnum->Release();
|
||||
}
|
||||
|
||||
redbookFormat
|
||||
}*/
|
||||
|
||||
if (master == 0)
|
||||
dm->Close();
|
||||
}
|
||||
|
||||
if (master != 0)
|
||||
*master = dm;
|
||||
else
|
||||
dm->Release();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const StringArray AudioCDBurner::findAvailableDevices()
|
||||
{
|
||||
StringArray devs;
|
||||
enumCDBurners (&devs, -1, 0);
|
||||
return devs;
|
||||
}
|
||||
|
||||
AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
|
||||
{
|
||||
AudioCDBurner* b = new AudioCDBurner (deviceIndex);
|
||||
|
||||
if (b->internal == 0)
|
||||
deleteAndZero (b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
class CDBurnerInfo : public IDiscMasterProgressEvents
|
||||
{
|
||||
public:
|
||||
CDBurnerInfo()
|
||||
: refCount (1),
|
||||
progress (0),
|
||||
shouldCancel (false),
|
||||
listener (0)
|
||||
{
|
||||
}
|
||||
|
||||
~CDBurnerInfo()
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
|
||||
{
|
||||
if (result == 0)
|
||||
return E_POINTER;
|
||||
|
||||
if (id == IID_IUnknown || id == IID_IDiscMasterProgressEvents)
|
||||
{
|
||||
AddRef();
|
||||
*result = this;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*result = 0;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG __stdcall AddRef() { return ++refCount; }
|
||||
ULONG __stdcall Release() { jassert (refCount > 0); const int r = --refCount; if (r == 0) delete this; return r; }
|
||||
|
||||
HRESULT __stdcall QueryCancel (boolean* pbCancel)
|
||||
{
|
||||
if (listener != 0 && ! shouldCancel)
|
||||
shouldCancel = listener->audioCDBurnProgress (progress);
|
||||
|
||||
*pbCancel = shouldCancel;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall NotifyBlockProgress (long nCompleted, long nTotal)
|
||||
{
|
||||
progress = nCompleted / (float) nTotal;
|
||||
shouldCancel = listener != 0 && listener->audioCDBurnProgress (progress);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT __stdcall NotifyPnPActivity (void) { return E_NOTIMPL; }
|
||||
HRESULT __stdcall NotifyAddProgress (long /*nCompletedSteps*/, long /*nTotalSteps*/) { return E_NOTIMPL; }
|
||||
HRESULT __stdcall NotifyTrackProgress (long /*nCurrentTrack*/, long /*nTotalTracks*/) { return E_NOTIMPL; }
|
||||
HRESULT __stdcall NotifyPreparingBurn (long /*nEstimatedSeconds*/) { return E_NOTIMPL; }
|
||||
HRESULT __stdcall NotifyClosingDisc (long /*nEstimatedSeconds*/) { return E_NOTIMPL; }
|
||||
HRESULT __stdcall NotifyBurnComplete (HRESULT /*status*/) { return E_NOTIMPL; }
|
||||
HRESULT __stdcall NotifyEraseComplete (HRESULT /*status*/) { return E_NOTIMPL; }
|
||||
|
||||
IDiscMaster* discMaster;
|
||||
IDiscRecorder* discRecorder;
|
||||
IRedbookDiscMaster* redbook;
|
||||
AudioCDBurner::BurnProgressListener* listener;
|
||||
float progress;
|
||||
bool shouldCancel;
|
||||
|
||||
private:
|
||||
int refCount;
|
||||
};
|
||||
|
||||
AudioCDBurner::AudioCDBurner (const int deviceIndex)
|
||||
: internal (0)
|
||||
{
|
||||
IDiscMaster* discMaster;
|
||||
IDiscRecorder* dr = enumCDBurners (0, deviceIndex, &discMaster);
|
||||
|
||||
if (dr != 0)
|
||||
{
|
||||
IRedbookDiscMaster* redbook;
|
||||
HRESULT hr = discMaster->SetActiveDiscMasterFormat (IID_IRedbookDiscMaster, (void**) &redbook);
|
||||
|
||||
hr = discMaster->SetActiveDiscRecorder (dr);
|
||||
|
||||
CDBurnerInfo* const info = new CDBurnerInfo();
|
||||
internal = info;
|
||||
|
||||
info->discMaster = discMaster;
|
||||
info->discRecorder = dr;
|
||||
info->redbook = redbook;
|
||||
}
|
||||
}
|
||||
|
||||
AudioCDBurner::~AudioCDBurner()
|
||||
{
|
||||
CDBurnerInfo* const info = (CDBurnerInfo*) internal;
|
||||
|
||||
if (info != 0)
|
||||
{
|
||||
info->discRecorder->Close();
|
||||
info->redbook->Release();
|
||||
info->discRecorder->Release();
|
||||
info->discMaster->Release();
|
||||
|
||||
info->Release();
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioCDBurner::isDiskPresent() const
|
||||
{
|
||||
CDBurnerInfo* const info = (CDBurnerInfo*) internal;
|
||||
|
||||
HRESULT hr = info->discRecorder->OpenExclusive();
|
||||
|
||||
long type, flags;
|
||||
hr = info->discRecorder->QueryMediaType (&type, &flags);
|
||||
|
||||
info->discRecorder->Close();
|
||||
return hr == S_OK && type != 0 && (flags & MEDIA_WRITABLE) != 0;
|
||||
}
|
||||
|
||||
int AudioCDBurner::getNumAvailableAudioBlocks() const
|
||||
{
|
||||
CDBurnerInfo* const info = (CDBurnerInfo*) internal;
|
||||
long blocksFree = 0;
|
||||
info->redbook->GetAvailableAudioTrackBlocks (&blocksFree);
|
||||
return blocksFree;
|
||||
}
|
||||
|
||||
const String AudioCDBurner::burn (AudioCDBurner::BurnProgressListener* listener,
|
||||
const bool ejectDiscAfterwards)
|
||||
{
|
||||
CDBurnerInfo* const info = (CDBurnerInfo*) internal;
|
||||
|
||||
info->listener = listener;
|
||||
info->progress = 0;
|
||||
info->shouldCancel = false;
|
||||
|
||||
UINT cookie;
|
||||
HRESULT hr = info->discMaster->ProgressAdvise (info, &cookie);
|
||||
|
||||
hr = info->discMaster->RecordDisc (FALSE, // set this to TRUE to make it do a fake burn, without actually writing to the disc
|
||||
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;
|
||||
}
|
||||
|
||||
info->discMaster->ProgressUnadvise (cookie);
|
||||
info->listener = 0;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool AudioCDBurner::addAudioTrack (AudioFormatReader& source, int numSamples)
|
||||
{
|
||||
CDBurnerInfo* const info = (CDBurnerInfo*) internal;
|
||||
|
||||
long bytesPerBlock;
|
||||
HRESULT hr = info->redbook->GetAudioBlockSize (&bytesPerBlock);
|
||||
|
||||
const int samplesPerBlock = bytesPerBlock / 4;
|
||||
bool ok = true;
|
||||
|
||||
hr = info->redbook->CreateAudioTrack ((long) numSamples / (bytesPerBlock * 4));
|
||||
|
||||
byte* const buffer = (byte*) juce_malloc (bytesPerBlock);
|
||||
|
||||
int* sourceBuffers[2];
|
||||
sourceBuffers[0] = (int*) juce_malloc (samplesPerBlock * 4);
|
||||
sourceBuffers[1] = (int*) juce_malloc (samplesPerBlock * 4);
|
||||
|
||||
int samplesDone = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
zeromem (buffer, bytesPerBlock);
|
||||
|
||||
if (! source.read (sourceBuffers, samplesDone, samplesPerBlock))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
short* destBuffer = (short*) buffer;
|
||||
|
||||
for (int j = 0; j < samplesPerBlock; ++j)
|
||||
{
|
||||
*destBuffer++ = (short) (sourceBuffers [0][j] >> 16);
|
||||
*destBuffer++ = (short) (sourceBuffers [jmin (1, source.numChannels - 1)][j] >> 16);
|
||||
}
|
||||
|
||||
hr = info->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);
|
||||
|
||||
if (hr != S_OK)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
samplesDone += samplesPerBlock;
|
||||
|
||||
if (samplesDone >= numSamples)
|
||||
break;
|
||||
}
|
||||
|
||||
juce_free (sourceBuffers[0]);
|
||||
juce_free (sourceBuffers[1]);
|
||||
juce_free (buffer);
|
||||
|
||||
hr = info->redbook->CloseAudioTrack();
|
||||
|
||||
return ok && hr == S_OK;
|
||||
}
|
||||
|
||||
bool AudioCDBurner::addAudioTrack (AudioSource& source, int numSamples)
|
||||
{
|
||||
CDBurnerInfo* const info = (CDBurnerInfo*) internal;
|
||||
|
||||
long bytesPerBlock;
|
||||
HRESULT hr = info->redbook->GetAudioBlockSize (&bytesPerBlock);
|
||||
|
||||
const int samplesPerBlock = bytesPerBlock / 4;
|
||||
bool ok = true;
|
||||
|
||||
hr = info->redbook->CreateAudioTrack ((long) numSamples / (bytesPerBlock * 4));
|
||||
|
||||
byte* const buffer = (byte*) juce_malloc (bytesPerBlock);
|
||||
|
||||
AudioSampleBuffer sourceBuffer (2, samplesPerBlock);
|
||||
int samplesDone = 0;
|
||||
|
||||
source.prepareToPlay (samplesPerBlock, 44100.0);
|
||||
|
||||
while (ok)
|
||||
{
|
||||
{
|
||||
AudioSourceChannelInfo info;
|
||||
info.buffer = &sourceBuffer;
|
||||
info.numSamples = samplesPerBlock;
|
||||
info.startSample = 0;
|
||||
sourceBuffer.clear();
|
||||
|
||||
source.getNextAudioBlock (info);
|
||||
}
|
||||
|
||||
zeromem (buffer, bytesPerBlock);
|
||||
|
||||
AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (0, 0),
|
||||
buffer, samplesPerBlock, 4);
|
||||
|
||||
AudioDataConverters::convertFloatToInt16LE (sourceBuffer.getSampleData (1, 0),
|
||||
buffer + 2, samplesPerBlock, 4);
|
||||
|
||||
hr = info->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);
|
||||
|
||||
if (hr != S_OK)
|
||||
ok = false;
|
||||
|
||||
samplesDone += samplesPerBlock;
|
||||
|
||||
if (samplesDone >= numSamples)
|
||||
break;
|
||||
}
|
||||
|
||||
juce_free (buffer);
|
||||
|
||||
hr = info->redbook->CloseAudioTrack();
|
||||
|
||||
return ok && hr == S_OK;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAdd
|
|||
files[i].lpszPathName = (LPTSTR) (LPCTSTR) filesToAttach [i];
|
||||
}
|
||||
|
||||
ok = (mapiSendMail (0, 0, &message, MAPI_DIALOG, 0) == SUCCESS_SUCCESS);
|
||||
ok = (mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS);
|
||||
}
|
||||
|
||||
FreeLibrary (h);
|
||||
|
|
|
|||
|
|
@ -533,6 +533,10 @@
|
|||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AiffAudioFormat.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioCDBurner.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioCDReader.h"
|
||||
>
|
||||
|
|
@ -641,6 +645,22 @@
|
|||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioSubsectionReader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioThumbnail.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioThumbnail.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioThumbnailCache.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_AudioThumbnailCache.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_appframework\audio\audio_file_formats\juce_FlacAudioFormat.cpp"
|
||||
>
|
||||
|
|
@ -5242,6 +5262,14 @@
|
|||
RelativePath="..\..\..\src\juce_core\io\streams\juce_BufferedInputStream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_core\io\streams\juce_FileInputSource.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_core\io\streams\juce_FileInputSource.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_core\io\streams\juce_GZIPCompressorOutputStream.cpp"
|
||||
>
|
||||
|
|
@ -5330,6 +5358,10 @@
|
|||
RelativePath="..\..\..\src\juce_core\io\streams\juce_GZIPDecompressorInputStream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_core\io\streams\juce_InputSource.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\juce_core\io\streams\juce_MemoryInputStream.cpp"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ Changelist for version 1.46
|
|||
- added a parameter to DragAndDropTarget::isInterestedInDragSource(). This ma
|
||||
- changed the parameters to AudioIODeviceCallback::audioDeviceAboutToStart(), so that it now just supplies a pointer to the device. If you need to, you can still find out the sample rate and block size by asking the device for them.
|
||||
- changes to the URL class to allow file uploading
|
||||
- new method: PlatformUtilities::launchEmailWithAttachments
|
||||
- new classes: AudioThumbnail and AudioThumbnailCache, which allow easy rendering of low-res waveform previews
|
||||
- new classes: InputSource and FileInputSource. These encapsulate some kind of resource, and also replace the XmlInputSource class.
|
||||
|
||||
|
||||
==============================================================================
|
||||
Changelist for version 1.45
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
84EAE2F309DAAF0B00288D0A /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EAE2F109DAAF0B00288D0A /* AGL.framework */; };
|
||||
84EAE2F409DAAF0B00288D0A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EAE2F209DAAF0B00288D0A /* OpenGL.framework */; };
|
||||
84F8DB0B099CA8DD00E911ED /* QuickTimeDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F8DB0A099CA8DD00E911ED /* QuickTimeDemo.cpp */; };
|
||||
84FDB0950C15BDDD00CD0087 /* libjuce.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FDB0940C15BDCE00CD0087 /* libjuce.a */; };
|
||||
84FDB0950C15BDDD00CD0087 /* libjucedebug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FDB0940C15BDCE00CD0087 /* libjucedebug.a */; };
|
||||
8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; };
|
||||
8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
84EAE2F909DAAF2F00288D0A /* Juce.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Juce.xcodeproj; path = ../../../../build/macosx/Juce.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
84F8DB0A099CA8DD00E911ED /* QuickTimeDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = QuickTimeDemo.cpp; sourceTree = "<group>"; };
|
||||
8D0C4E960486CD37000505A6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
8D0C4E970486CD37000505A6 /* jucedemo.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = jucedemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8D0C4E970486CD37000505A6 /* jucedemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = jucedemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84FDB0950C15BDDD00CD0087 /* libjuce.a in Frameworks */,
|
||||
84FDB0950C15BDDD00CD0087 /* libjucedebug.a in Frameworks */,
|
||||
8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */,
|
||||
84C49F2606C0F3200066071B /* CoreAudio.framework in Frameworks */,
|
||||
84C4A41106C0F9A00066071B /* IOKit.framework in Frameworks */,
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
84FDB0900C15BDCE00CD0087 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84FDB0940C15BDCE00CD0087 /* libjuce.a */,
|
||||
84FDB0940C15BDCE00CD0087 /* libjucedebug.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -228,6 +228,7 @@
|
|||
20286C28FDCF999611CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = 84CFBCCF085F14F000C52F85 /* Build configuration list for PBXProject "jucedemo" */;
|
||||
compatibilityVersion = "Xcode 2.4";
|
||||
hasScannedForEncodings = 1;
|
||||
mainGroup = 20286C29FDCF999611CA2CEA /* jucedemo */;
|
||||
projectDirPath = "";
|
||||
|
|
@ -237,6 +238,7 @@
|
|||
ProjectRef = 84EAE2F909DAAF2F00288D0A /* Juce.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8D0C4E890486CD37000505A6 /* jucedemo */,
|
||||
);
|
||||
|
|
@ -244,10 +246,10 @@
|
|||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
84FDB0940C15BDCE00CD0087 /* libjuce.a */ = {
|
||||
84FDB0940C15BDCE00CD0087 /* libjucedebug.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libjuce.a;
|
||||
path = libjucedebug.a;
|
||||
remoteRef = 84FDB0930C15BDCE00CD0087 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -197,6 +197,9 @@
|
|||
#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_AiffAudioFormat.h"
|
||||
#endif
|
||||
#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_AudioCDBurner.h"
|
||||
#endif
|
||||
#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_AudioCDReader.h"
|
||||
#endif
|
||||
|
|
@ -215,6 +218,12 @@
|
|||
#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_AudioSubsectionReader.h"
|
||||
#endif
|
||||
#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_AudioThumbnail.h"
|
||||
#endif
|
||||
#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_AudioThumbnailCache.h"
|
||||
#endif
|
||||
#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__
|
||||
#include "juce_appframework/audio/audio_file_formats/juce_FlacAudioFormat.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__
|
||||
#define __JUCE_AUDIOCDBURNER_JUCEHEADER__
|
||||
|
||||
#include "juce_AudioFormatReader.h"
|
||||
#include "../audio_sources/juce_AudioSource.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class AudioCDBurner
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
static const StringArray findAvailableDevices();
|
||||
static AudioCDBurner* openDevice (const int deviceIndex);
|
||||
|
||||
~AudioCDBurner();
|
||||
|
||||
//==============================================================================
|
||||
bool isDiskPresent() const;
|
||||
|
||||
int getNumAvailableAudioBlocks() const;
|
||||
|
||||
bool addAudioTrack (AudioFormatReader& source, int numSamples);
|
||||
bool addAudioTrack (AudioSource& source, int numSamples);
|
||||
|
||||
/**
|
||||
|
||||
Return true to cancel the current burn operation
|
||||
*/
|
||||
class BurnProgressListener
|
||||
{
|
||||
public:
|
||||
BurnProgressListener() throw() {}
|
||||
virtual ~BurnProgressListener() {}
|
||||
|
||||
/** Called at intervals to report on the progress of the AudioCDBurner.
|
||||
|
||||
To cancel the burn, return true from this.
|
||||
*/
|
||||
virtual bool audioCDBurnProgress (float proportionComplete) = 0;
|
||||
};
|
||||
|
||||
const String burn (BurnProgressListener* listener,
|
||||
const bool ejectDiscAfterwards);
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
AudioCDBurner (const int deviceIndex);
|
||||
|
||||
void* internal;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_AUDIOCDBURNER_JUCEHEADER__
|
||||
|
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_AudioThumbnail.h"
|
||||
#include "juce_AudioThumbnailCache.h"
|
||||
|
||||
const int timeBeforeDeletingReader = 1000;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct AudioThumbnailDataFormat
|
||||
{
|
||||
char thumbnailMagic[4];
|
||||
int samplesPerThumbSample;
|
||||
int64 totalSamples; // source samples
|
||||
int64 numFinishedSamples; // source samples
|
||||
int numThumbnailSamples;
|
||||
int numChannels;
|
||||
int sampleRate;
|
||||
char future[16];
|
||||
char data[1];
|
||||
};
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
static void swap (int& n) { n = (int) swapByteOrder ((uint32) n); }
|
||||
static void swap (int64& n) { n = (int64) swapByteOrder ((uint64) n); }
|
||||
#endif
|
||||
|
||||
static void swapEndiannessIfNeeded (AudioThumbnailDataFormat* const d)
|
||||
{
|
||||
(void) d;
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
swap (d->samplesPerThumbSample);
|
||||
swap (d->totalSamples);
|
||||
swap (d->numFinishedSamples);
|
||||
swap (d->numThumbnailSamples);
|
||||
swap (d->numChannels);
|
||||
swap (d->sampleRate);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioThumbnail::AudioThumbnail (const int orginalSamplesPerThumbnailSample_,
|
||||
AudioFormatManager& formatManagerToUse_,
|
||||
AudioThumbnailCache& cacheToUse)
|
||||
: cache (cacheToUse),
|
||||
formatManagerToUse (formatManagerToUse_),
|
||||
source (0),
|
||||
reader (0),
|
||||
orginalSamplesPerThumbnailSample (orginalSamplesPerThumbnailSample_)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
AudioThumbnail::~AudioThumbnail()
|
||||
{
|
||||
cache.removeThumbnail (this);
|
||||
|
||||
const ScopedLock sl (readerLock);
|
||||
deleteAndZero (reader);
|
||||
|
||||
delete source;
|
||||
}
|
||||
|
||||
void AudioThumbnail::setSource (InputSource* const newSource)
|
||||
{
|
||||
cache.removeThumbnail (this);
|
||||
|
||||
delete source;
|
||||
source = newSource;
|
||||
|
||||
{
|
||||
const ScopedLock sl (readerLock);
|
||||
|
||||
deleteAndZero (reader);
|
||||
reader = createReader();
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
if (reader != 0)
|
||||
{
|
||||
startTimer (timeBeforeDeletingReader);
|
||||
|
||||
initialiseFromAudioFile (*reader);
|
||||
|
||||
cache.loadThumb (*this, newSource->hashCode());
|
||||
|
||||
if (! isFullyLoaded())
|
||||
cache.addThumbnail (this);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioThumbnail::useTimeSlice()
|
||||
{
|
||||
const ScopedLock sl (readerLock);
|
||||
|
||||
if (isFullyLoaded())
|
||||
{
|
||||
if (reader != 0)
|
||||
startTimer (timeBeforeDeletingReader);
|
||||
|
||||
cache.removeThumbnail (this);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reader == 0)
|
||||
reader = createReader();
|
||||
|
||||
if (reader != 0)
|
||||
{
|
||||
readNextBlockFromAudioFile (*reader);
|
||||
startTimer (timeBeforeDeletingReader);
|
||||
|
||||
sendChangeMessage (this);
|
||||
|
||||
const bool justFinished = isFullyLoaded();
|
||||
|
||||
if (justFinished)
|
||||
cache.storeThumb (*this, source->hashCode());
|
||||
|
||||
return ! justFinished;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioFormatReader* AudioThumbnail::createReader() const
|
||||
{
|
||||
if (source != 0)
|
||||
{
|
||||
InputStream* const audioFileStream = source->createInputStream();
|
||||
|
||||
if (audioFileStream != 0)
|
||||
return formatManagerToUse.createReaderFor (audioFileStream);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AudioThumbnail::timerCallback()
|
||||
{
|
||||
stopTimer();
|
||||
|
||||
const ScopedLock sl (readerLock);
|
||||
deleteAndZero (reader);
|
||||
}
|
||||
|
||||
void AudioThumbnail::clear()
|
||||
{
|
||||
data.setSize (sizeof (AudioThumbnailDataFormat) + 3);
|
||||
|
||||
AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData();
|
||||
|
||||
d->thumbnailMagic[0] = 'j';
|
||||
d->thumbnailMagic[1] = 'a';
|
||||
d->thumbnailMagic[2] = 't';
|
||||
d->thumbnailMagic[3] = 'm';
|
||||
|
||||
d->samplesPerThumbSample = orginalSamplesPerThumbnailSample;
|
||||
d->totalSamples = 0;
|
||||
d->numFinishedSamples = 0;
|
||||
d->numThumbnailSamples = 0;
|
||||
d->numChannels = 0;
|
||||
d->sampleRate = 0;
|
||||
|
||||
numSamplesCached = 0;
|
||||
}
|
||||
|
||||
void AudioThumbnail::loadFrom (InputStream& input)
|
||||
{
|
||||
data.setSize (0);
|
||||
input.readIntoMemoryBlock (data);
|
||||
|
||||
AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData();
|
||||
swapEndiannessIfNeeded (d);
|
||||
|
||||
if (! (d->thumbnailMagic[0] == 'j'
|
||||
&& d->thumbnailMagic[1] == 'a'
|
||||
&& d->thumbnailMagic[2] == 't'
|
||||
&& d->thumbnailMagic[3] == 'm'))
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
numSamplesCached = 0;
|
||||
}
|
||||
|
||||
void AudioThumbnail::saveTo (OutputStream& output) const
|
||||
{
|
||||
AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData();
|
||||
swapEndiannessIfNeeded (d);
|
||||
output.write (data.getData(), data.getSize());
|
||||
swapEndiannessIfNeeded (d);
|
||||
}
|
||||
|
||||
bool AudioThumbnail::initialiseFromAudioFile (AudioFormatReader& reader)
|
||||
{
|
||||
AudioThumbnailDataFormat* d = (AudioThumbnailDataFormat*) data.getData();
|
||||
|
||||
d->totalSamples = reader.lengthInSamples;
|
||||
d->numChannels = jmin (2, reader.numChannels);
|
||||
d->numFinishedSamples = 0;
|
||||
d->sampleRate = roundDoubleToInt (reader.sampleRate);
|
||||
d->numThumbnailSamples = (int) (d->totalSamples / d->samplesPerThumbSample) + 1;
|
||||
|
||||
data.setSize (sizeof (AudioThumbnailDataFormat) + 3 + d->numThumbnailSamples * d->numChannels * 2);
|
||||
|
||||
d = (AudioThumbnailDataFormat*) data.getData();
|
||||
zeromem (&(d->data[0]), d->numThumbnailSamples * d->numChannels * 2);
|
||||
|
||||
return d->totalSamples > 0;
|
||||
}
|
||||
|
||||
bool AudioThumbnail::readNextBlockFromAudioFile (AudioFormatReader& reader)
|
||||
{
|
||||
AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData();
|
||||
|
||||
if (d->numFinishedSamples < d->totalSamples)
|
||||
{
|
||||
const int numToDo = (int) jmin ((int64) 65536, d->totalSamples - d->numFinishedSamples);
|
||||
|
||||
generateSection (reader,
|
||||
d->numFinishedSamples,
|
||||
numToDo);
|
||||
|
||||
d->numFinishedSamples += numToDo;
|
||||
}
|
||||
|
||||
numSamplesCached = 0; // zap the cache
|
||||
return (d->numFinishedSamples < d->totalSamples);
|
||||
}
|
||||
|
||||
int AudioThumbnail::getNumChannels() const throw()
|
||||
{
|
||||
const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData();
|
||||
jassert (d != 0);
|
||||
|
||||
return d->numChannels;
|
||||
}
|
||||
|
||||
double AudioThumbnail::getTotalLength() const throw()
|
||||
{
|
||||
const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData();
|
||||
jassert (d != 0);
|
||||
|
||||
if (d->sampleRate > 0)
|
||||
return d->totalSamples / (double)d->sampleRate;
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void AudioThumbnail::generateSection (AudioFormatReader& reader,
|
||||
int64 startSample,
|
||||
int numSamples)
|
||||
{
|
||||
AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData();
|
||||
jassert (d != 0);
|
||||
|
||||
int firstDataPos = (int) (startSample / d->samplesPerThumbSample);
|
||||
int lastDataPos = (int) ((startSample + numSamples) / d->samplesPerThumbSample);
|
||||
|
||||
char* l = getChannelData (0);
|
||||
char* r = getChannelData (1);
|
||||
|
||||
for (int i = firstDataPos; i < lastDataPos; ++i)
|
||||
{
|
||||
const int sourceStart = i * d->samplesPerThumbSample;
|
||||
const int sourceEnd = sourceStart + d->samplesPerThumbSample;
|
||||
|
||||
float lowestLeft, highestLeft, lowestRight, highestRight;
|
||||
|
||||
reader.readMaxLevels (sourceStart,
|
||||
sourceEnd - sourceStart,
|
||||
lowestLeft,
|
||||
highestLeft,
|
||||
lowestRight,
|
||||
highestRight);
|
||||
|
||||
int n = i * 2;
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
l [n] = (char) jlimit (-128.0f, 127.0f, lowestLeft * 127.0f);
|
||||
r [n++] = (char) jlimit (-128.0f, 127.0f, lowestRight * 127.0f);
|
||||
l [n] = (char) jlimit (-128.0f, 127.0f, highestLeft * 127.0f);
|
||||
r [n++] = (char) jlimit (-128.0f, 127.0f, highestRight * 127.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
l [n++] = (char) jlimit (-128.0f, 127.0f, lowestLeft * 127.0f);
|
||||
l [n++] = (char) jlimit (-128.0f, 127.0f, highestLeft * 127.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* AudioThumbnail::getChannelData (int channel) const
|
||||
{
|
||||
AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData();
|
||||
jassert (d != 0);
|
||||
|
||||
if (channel >= 0 && channel < d->numChannels)
|
||||
return d->data + (channel * 2 * d->numThumbnailSamples);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AudioThumbnail::isFullyLoaded() const throw()
|
||||
{
|
||||
const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData();
|
||||
jassert (d != 0);
|
||||
|
||||
return d->numFinishedSamples >= d->totalSamples;
|
||||
}
|
||||
|
||||
void AudioThumbnail::refillCache (const int numSamples,
|
||||
double startTime,
|
||||
const double timePerPixel)
|
||||
{
|
||||
const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData();
|
||||
jassert (d != 0);
|
||||
|
||||
if (numSamples <= 0
|
||||
|| timePerPixel <= 0.0
|
||||
|| d->sampleRate <= 0)
|
||||
{
|
||||
numSamplesCached = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (numSamples == numSamplesCached
|
||||
&& numChannelsCached == d->numChannels
|
||||
&& startTime == cachedStart
|
||||
&& timePerPixel == cachedTimePerPixel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
numSamplesCached = numSamples;
|
||||
numChannelsCached = d->numChannels;
|
||||
cachedStart = startTime;
|
||||
cachedTimePerPixel = timePerPixel;
|
||||
|
||||
cachedLevels.ensureSize (2 * numChannelsCached * numSamples);
|
||||
|
||||
const bool needExtraDetail = (timePerPixel * d->sampleRate <= d->samplesPerThumbSample);
|
||||
|
||||
const ScopedLock sl (readerLock);
|
||||
|
||||
if (needExtraDetail && reader == 0)
|
||||
reader = createReader();
|
||||
|
||||
if (reader != 0 && timePerPixel * d->sampleRate <= d->samplesPerThumbSample)
|
||||
{
|
||||
startTimer (timeBeforeDeletingReader);
|
||||
|
||||
char* cacheData = (char*) cachedLevels;
|
||||
int sample = roundDoubleToInt (startTime * d->sampleRate);
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
const int nextSample = roundDoubleToInt ((startTime + timePerPixel) * d->sampleRate);
|
||||
|
||||
if (sample >= 0)
|
||||
{
|
||||
if (sample >= reader->lengthInSamples)
|
||||
break;
|
||||
|
||||
float lmin, lmax, rmin, rmax;
|
||||
|
||||
reader->readMaxLevels (sample,
|
||||
jmax (1, nextSample - sample),
|
||||
lmin, lmax, rmin, rmax);
|
||||
|
||||
cacheData[0] = (char) jlimit (-128, 127, roundFloatToInt (lmin * 127.0f));
|
||||
cacheData[1] = (char) jlimit (-128, 127, roundFloatToInt (lmax * 127.0f));
|
||||
|
||||
if (numChannelsCached > 1)
|
||||
{
|
||||
cacheData[2] = (char) jlimit (-128, 127, roundFloatToInt (rmin * 127.0f));
|
||||
cacheData[3] = (char) jlimit (-128, 127, roundFloatToInt (rmax * 127.0f));
|
||||
}
|
||||
|
||||
cacheData += 2 * numChannelsCached;
|
||||
}
|
||||
|
||||
startTime += timePerPixel;
|
||||
sample = nextSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int channelNum = 0; channelNum < 2; ++channelNum)
|
||||
{
|
||||
char* const data = getChannelData (channelNum);
|
||||
char* cacheData = ((char*) cachedLevels) + channelNum * 2;
|
||||
|
||||
const double timeToThumbSampleFactor = d->sampleRate / (double) d->samplesPerThumbSample;
|
||||
|
||||
startTime = cachedStart;
|
||||
int sample = roundDoubleToInt (startTime * timeToThumbSampleFactor);
|
||||
const int numFinished = (int) (d->numFinishedSamples / d->samplesPerThumbSample);
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
const int nextSample = roundDoubleToInt ((startTime + timePerPixel) * timeToThumbSampleFactor);
|
||||
|
||||
if (sample >= 0 && data != 0)
|
||||
{
|
||||
char mx = -128;
|
||||
char mn = 127;
|
||||
|
||||
while (sample <= nextSample)
|
||||
{
|
||||
if (sample >= numFinished)
|
||||
break;
|
||||
|
||||
const int n = sample << 1;
|
||||
const char sampMin = data [n];
|
||||
const char sampMax = data [n + 1];
|
||||
|
||||
if (sampMin < mn)
|
||||
mn = sampMin;
|
||||
|
||||
if (sampMax > mx)
|
||||
mx = sampMax;
|
||||
|
||||
++sample;
|
||||
}
|
||||
|
||||
if (mn <= mx)
|
||||
{
|
||||
cacheData[0] = mn;
|
||||
cacheData[1] = mx;
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheData[0] = 1;
|
||||
cacheData[1] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheData[0] = 1;
|
||||
cacheData[1] = 0;
|
||||
}
|
||||
|
||||
cacheData += numChannelsCached * 2;
|
||||
startTime += timePerPixel;
|
||||
sample = nextSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioThumbnail::drawChannel (Graphics& g,
|
||||
int x, int y, int w, int h,
|
||||
double startTime,
|
||||
double endTime,
|
||||
int channelNum,
|
||||
const float verticalZoomFactor)
|
||||
{
|
||||
refillCache (w, startTime, (endTime - startTime) / w);
|
||||
|
||||
if (numSamplesCached >= w
|
||||
&& channelNum >= 0
|
||||
&& channelNum < numChannelsCached)
|
||||
{
|
||||
const float topY = (float) y;
|
||||
const float bottomY = topY + h;
|
||||
const float midY = topY + h * 0.5f;
|
||||
const float vscale = verticalZoomFactor * h / 256.0f;
|
||||
|
||||
const Rectangle clip (g.getClipBounds());
|
||||
const int skipLeft = clip.getX() - x;
|
||||
w -= skipLeft;
|
||||
x += skipLeft;
|
||||
|
||||
const char* cacheData = ((const char*) cachedLevels)
|
||||
+ (channelNum << 1)
|
||||
+ skipLeft * (numChannelsCached << 1);
|
||||
|
||||
while (--w >= 0)
|
||||
{
|
||||
const char mn = cacheData[0];
|
||||
const char mx = cacheData[1];
|
||||
cacheData += numChannelsCached << 1;
|
||||
|
||||
if (mn <= mx) // if the wrong way round, signifies that the sample's not yet known
|
||||
g.drawLine ((float) x, jmax (midY - mx * vscale - 0.3f, topY),
|
||||
(float) x, jmin (midY - mn * vscale + 0.3f, bottomY));
|
||||
|
||||
++x;
|
||||
|
||||
if (x >= clip.getRight())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__
|
||||
#define __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__
|
||||
|
||||
#include "../../../juce_core/threads/juce_TimeSliceThread.h"
|
||||
#include "../../../juce_core/io/streams/juce_InputSource.h"
|
||||
#include "../../../juce_core/io/juce_OutputStream.h"
|
||||
#include "../../events/juce_ChangeBroadcaster.h"
|
||||
#include "../../events/juce_Timer.h"
|
||||
#include "../../gui/graphics/contexts/juce_Graphics.h"
|
||||
#include "juce_AudioFormatReader.h"
|
||||
#include "juce_AudioFormatManager.h"
|
||||
|
||||
class AudioThumbnailCache;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Makes it easy to quickly draw scaled views of the waveform shape of an
|
||||
audio file.
|
||||
|
||||
To use this class, just create an AudioThumbNail class for the file you want
|
||||
to draw, call setSource to tell it which file or resource to use, then call
|
||||
drawChannel() to draw it.
|
||||
|
||||
The class will asynchronously scan the wavefile to create its scaled-down view,
|
||||
so you should make your UI repaint itself as this data comes in. To do this, the
|
||||
AudioThumbnail is a ChangeBroadcaster, and will broadcast a message when its
|
||||
listeners should repaint themselves.
|
||||
|
||||
The thumbnail stores an internal low-res version of the wave data, and this can
|
||||
be loaded and saved to avoid having to scan the file again.
|
||||
|
||||
@see AudioThumbnailCache
|
||||
*/
|
||||
class JUCE_API AudioThumbnail : public ChangeBroadcaster,
|
||||
public TimeSliceClient,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an audio thumbnail.
|
||||
|
||||
@param sourceSamplesPerThumbnailSample when creating a stored, low-res version
|
||||
of the audio data, this is the scale at which it should be done
|
||||
@param formatManagerToUse the audio format manager that is used to open the file
|
||||
@param cacheToUse an instance of an AudioThumbnailCache - this provides a background
|
||||
thread and storage that is used to by the thumbnail, and the cache
|
||||
object can be shared between multiple thumbnails
|
||||
*/
|
||||
AudioThumbnail (const int sourceSamplesPerThumbnailSample,
|
||||
AudioFormatManager& formatManagerToUse,
|
||||
AudioThumbnailCache& cacheToUse);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioThumbnail();
|
||||
|
||||
//==============================================================================
|
||||
/** Specifies the file or stream that contains the audio file.
|
||||
|
||||
For a file, just call
|
||||
@code
|
||||
setSource (new FileInputSource (file))
|
||||
@endcode
|
||||
|
||||
You can pass a zero in here to clear the thumbnail.
|
||||
|
||||
The source that is passed in will be deleted by this object when it is no
|
||||
longer needed
|
||||
*/
|
||||
void setSource (InputSource* const newSource);
|
||||
|
||||
/** Reloads the low res thumbnail data from an input stream.
|
||||
|
||||
The thumb will automatically attempt to reload itself from its
|
||||
AudioThumbnailCache.
|
||||
*/
|
||||
void loadFrom (InputStream& input);
|
||||
|
||||
/** Saves the low res thumbnail data to an output stream.
|
||||
|
||||
The thumb will automatically attempt to save itself to its
|
||||
AudioThumbnailCache after it finishes scanning the wave file.
|
||||
*/
|
||||
void saveTo (OutputStream& output) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of channels in the file.
|
||||
*/
|
||||
int getNumChannels() const throw();
|
||||
|
||||
/** Returns the length of the audio file.
|
||||
*/
|
||||
double getTotalLength() const throw();
|
||||
|
||||
/** Renders the waveform shape for a channel.
|
||||
|
||||
The waveform will be drawn within the specified rectangle, where startTime
|
||||
and endTime specify the times within the audio file that should be positioned
|
||||
at the left and right edges of the rectangle.
|
||||
|
||||
The waveform will be scaled vertically so that a full-volume sample will fill
|
||||
the rectangle vertically, but you can also specify an extra vertical scale factor
|
||||
with the verticalZoomFactor parameter.
|
||||
*/
|
||||
void drawChannel (Graphics& g,
|
||||
int x, int y, int w, int h,
|
||||
double startTime,
|
||||
double endTime,
|
||||
int channelNum,
|
||||
const float verticalZoomFactor);
|
||||
|
||||
/** Returns true if the low res preview is fully generated.
|
||||
*/
|
||||
bool isFullyLoaded() const throw();
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
bool useTimeSlice();
|
||||
/** @internal */
|
||||
void timerCallback();
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
AudioFormatManager& formatManagerToUse;
|
||||
AudioThumbnailCache& cache;
|
||||
InputSource* source;
|
||||
|
||||
CriticalSection readerLock;
|
||||
AudioFormatReader* reader;
|
||||
|
||||
MemoryBlock data, cachedLevels;
|
||||
int orginalSamplesPerThumbnailSample;
|
||||
|
||||
int numChannelsCached, numSamplesCached;
|
||||
double cachedStart, cachedTimePerPixel;
|
||||
|
||||
void clear();
|
||||
|
||||
AudioFormatReader* createReader() const;
|
||||
|
||||
void generateSection (AudioFormatReader& reader,
|
||||
int64 startSample,
|
||||
int numSamples);
|
||||
|
||||
char* getChannelData (int channel) const;
|
||||
|
||||
void refillCache (const int numSamples,
|
||||
double startTime,
|
||||
const double timePerPixel);
|
||||
|
||||
friend class AudioThumbnailCache;
|
||||
|
||||
// true if it needs more callbacks from the readNextBlockFromAudioFile() method
|
||||
bool initialiseFromAudioFile (AudioFormatReader& reader);
|
||||
|
||||
// returns true if more needs to be read
|
||||
bool readNextBlockFromAudioFile (AudioFormatReader& reader);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_AudioThumbnailCache.h"
|
||||
#include "../../../juce_core/io/streams/juce_MemoryInputStream.h"
|
||||
#include "../../../juce_core/io/streams/juce_MemoryOutputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct ThumbnailCacheEntry
|
||||
{
|
||||
int64 hash;
|
||||
uint32 lastUsed;
|
||||
MemoryBlock data;
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
AudioThumbnailCache::AudioThumbnailCache (const int maxNumThumbsToStore_)
|
||||
: TimeSliceThread (T("thumb cache")),
|
||||
maxNumThumbsToStore (maxNumThumbsToStore_)
|
||||
{
|
||||
startThread (2);
|
||||
}
|
||||
|
||||
AudioThumbnailCache::~AudioThumbnailCache()
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioThumbnailCache::loadThumb (AudioThumbnail& thumb, const int64 hashCode)
|
||||
{
|
||||
for (int i = thumbs.size(); --i >= 0;)
|
||||
{
|
||||
if (thumbs[i]->hash == hashCode)
|
||||
{
|
||||
MemoryInputStream in ((const char*) thumbs[i]->data,
|
||||
thumbs[i]->data.getSize(),
|
||||
false);
|
||||
|
||||
thumb.loadFrom (in);
|
||||
|
||||
thumbs[i]->lastUsed = Time::getMillisecondCounter();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioThumbnailCache::storeThumb (const AudioThumbnail& thumb,
|
||||
const int64 hashCode)
|
||||
{
|
||||
MemoryOutputStream out;
|
||||
thumb.saveTo (out);
|
||||
|
||||
ThumbnailCacheEntry* te = 0;
|
||||
|
||||
for (int i = thumbs.size(); --i >= 0;)
|
||||
{
|
||||
if (thumbs[i]->hash == hashCode)
|
||||
{
|
||||
te = thumbs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (te == 0)
|
||||
{
|
||||
te = new ThumbnailCacheEntry();
|
||||
te->hash = hashCode;
|
||||
|
||||
if (thumbs.size() < maxNumThumbsToStore)
|
||||
{
|
||||
thumbs.add (te);
|
||||
}
|
||||
else
|
||||
{
|
||||
int oldest = 0;
|
||||
unsigned int oldestTime = Time::getMillisecondCounter() + 1;
|
||||
|
||||
int i;
|
||||
for (i = thumbs.size(); --i >= 0;)
|
||||
if (thumbs[i]->lastUsed < oldestTime)
|
||||
oldest = i;
|
||||
|
||||
thumbs.set (i, te);
|
||||
}
|
||||
}
|
||||
|
||||
te->lastUsed = Time::getMillisecondCounter();
|
||||
te->data.setSize (0);
|
||||
te->data.append (out.getData(), out.getDataSize());
|
||||
}
|
||||
|
||||
void AudioThumbnailCache::clear()
|
||||
{
|
||||
thumbs.clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioThumbnailCache::addThumbnail (AudioThumbnail* const thumb)
|
||||
{
|
||||
addTimeSliceClient (thumb);
|
||||
}
|
||||
|
||||
void AudioThumbnailCache::removeThumbnail (AudioThumbnail* const thumb)
|
||||
{
|
||||
removeTimeSliceClient (thumb);
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__
|
||||
#define __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__
|
||||
|
||||
#include "juce_AudioThumbnail.h"
|
||||
struct ThumbnailCacheEntry;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An instance of this class is used to manage multiple AudioThumbnail objects.
|
||||
|
||||
The cache runs a single background thread that is shared by all the thumbnails
|
||||
that need it, and it maintains a set of low-res previews in memory, to avoid
|
||||
having to re-scan audio files too often.
|
||||
|
||||
@see AudioThumbnail
|
||||
*/
|
||||
class JUCE_API AudioThumbnailCache : public TimeSliceThread
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a cache object.
|
||||
|
||||
The maxNumThumbsToStore parameter lets you specify how many previews should
|
||||
be kept in memory at once.
|
||||
*/
|
||||
AudioThumbnailCache (const int maxNumThumbsToStore);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioThumbnailCache();
|
||||
|
||||
//==============================================================================
|
||||
/** Clears out any stored thumbnails.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/** Reloads the specified thumb if this cache contains the appropriate stored
|
||||
data.
|
||||
|
||||
This is called automatically by the AudioThumbnail class, so you shouldn't
|
||||
normally need to call it directly.
|
||||
*/
|
||||
bool loadThumb (AudioThumbnail& thumb, const int64 hashCode);
|
||||
|
||||
/** Stores the cachable data from the specified thumb in this cache.
|
||||
|
||||
This is called automatically by the AudioThumbnail class, so you shouldn't
|
||||
normally need to call it directly.
|
||||
*/
|
||||
void storeThumb (const AudioThumbnail& thumb, const int64 hashCode);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
OwnedArray <ThumbnailCacheEntry> thumbs;
|
||||
int maxNumThumbsToStore;
|
||||
|
||||
friend class AudioThumbnail;
|
||||
void addThumbnail (AudioThumbnail* const thumb);
|
||||
void removeThumbnail (AudioThumbnail* const thumb);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__
|
||||
|
|
@ -666,7 +666,7 @@ int ListBox::getRowNumberOfComponent (Component* const rowComponent) const throw
|
|||
return viewport->getRowNumberOfComponent (rowComponent);
|
||||
}
|
||||
|
||||
const Rectangle ListBox::getRowPosition (const int rowNumber,
|
||||
const Rectangle ListBox::getRowPosition (const int rowNumber,
|
||||
const bool relativeToComponentTopLeft) const throw()
|
||||
{
|
||||
const int rowHeight = getRowHeight();
|
||||
|
|
@ -675,7 +675,7 @@ const Rectangle ListBox::getRowPosition (const int rowNumber,
|
|||
if (relativeToComponentTopLeft)
|
||||
y -= viewport->getViewPositionY();
|
||||
|
||||
return Rectangle (viewport->getX(), y,
|
||||
return Rectangle (viewport->getX(), y,
|
||||
viewport->getViewedComponent()->getWidth(), rowHeight);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -384,8 +384,8 @@ public:
|
|||
/** Finds a row index that would be the most suitable place to insert a new
|
||||
item for a given position.
|
||||
|
||||
This is useful when the user is e.g. dragging and dropping onto the listbox,
|
||||
because it lets you easily choose the best position to insert the item that
|
||||
This is useful when the user is e.g. dragging and dropping onto the listbox,
|
||||
because it lets you easily choose the best position to insert the item that
|
||||
they drop, based on where they drop it.
|
||||
|
||||
If the position is out of range, this will return -1. If the position is
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ bool TableListBox::isAutoSizeMenuOptionShown() const throw()
|
|||
return autoSizeOptionsShown;
|
||||
}
|
||||
|
||||
const Rectangle TableListBox::getCellPosition (const int columnId,
|
||||
const Rectangle TableListBox::getCellPosition (const int columnId,
|
||||
const int rowNumber,
|
||||
const bool relativeToComponentTopLeft) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -264,14 +264,14 @@ public:
|
|||
|
||||
/** Returns the position of one of the cells in the table.
|
||||
|
||||
If relativeToComponentTopLeft is true, the co-ordinates are relative to
|
||||
the table component's top-left. The row number isn't checked to see if it's
|
||||
If relativeToComponentTopLeft is true, the co-ordinates are relative to
|
||||
the table component's top-left. The row number isn't checked to see if it's
|
||||
in-range, but the column ID must exist or this will return an empty rectangle.
|
||||
|
||||
If relativeToComponentTopLeft is false, the co-ords are relative to the
|
||||
If relativeToComponentTopLeft is false, the co-ords are relative to the
|
||||
top-left of the table's top-left cell.
|
||||
*/
|
||||
const Rectangle getCellPosition (const int columnId,
|
||||
const Rectangle getCellPosition (const int columnId,
|
||||
const int rowNumber,
|
||||
const bool relativeToComponentTopLeft) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -155,10 +155,10 @@ inline void bigEndian24BitToChars (const int value, char* const destBytes) throw
|
|||
|
||||
This is faster than using the normal c++ cast to convert a double to an int, and
|
||||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently. For a more accurate conversion,
|
||||
see roundDoubleToIntAccurate().
|
||||
*/
|
||||
|
|
@ -190,8 +190,8 @@ inline int roundDoubleToIntAccurate (const double value) throw()
|
|||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently.
|
||||
*/
|
||||
inline int roundFloatToInt (const float value) throw()
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static VoidArray activeStreams;
|
|||
|
||||
void juce_CheckForDanglingStreams()
|
||||
{
|
||||
/*
|
||||
/*
|
||||
It's always a bad idea to leak any object, but if you're leaking output
|
||||
streams, then there's a good chance that you're failing to flush a file
|
||||
to disk properly, which could result in corrupted data and other similar
|
||||
|
|
|
|||
66
src/juce_core/io/streams/juce_FileInputSource.cpp
Normal file
66
src/juce_core/io/streams/juce_FileInputSource.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_FileInputSource.h"
|
||||
#include "../files/juce_FileInputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
FileInputSource::FileInputSource (const File& file_) throw()
|
||||
: file (file_)
|
||||
{
|
||||
}
|
||||
|
||||
FileInputSource::~FileInputSource()
|
||||
{
|
||||
}
|
||||
|
||||
InputStream* FileInputSource::createInputStream()
|
||||
{
|
||||
return file.createInputStream();
|
||||
}
|
||||
|
||||
InputStream* FileInputSource::createInputStreamFor (const String& relatedItemPath)
|
||||
{
|
||||
return file.getSiblingFile (relatedItemPath).createInputStream();
|
||||
}
|
||||
|
||||
int64 FileInputSource::hashCode() const
|
||||
{
|
||||
return file.hashCode();
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
67
src/juce_core/io/streams/juce_FileInputSource.h
Normal file
67
src/juce_core/io/streams/juce_FileInputSource.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__
|
||||
#define __JUCE_FILEINPUTSOURCE_JUCEHEADER__
|
||||
|
||||
#include "juce_InputSource.h"
|
||||
#include "../files/juce_File.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A type of InputSource that represents a normal file.
|
||||
|
||||
@see InputSource
|
||||
*/
|
||||
class JUCE_API FileInputSource : public InputSource
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
FileInputSource (const File& file) throw();
|
||||
~FileInputSource();
|
||||
|
||||
InputStream* createInputStream();
|
||||
InputStream* createInputStreamFor (const String& relatedItemPath);
|
||||
int64 hashCode() const;
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
const File file;
|
||||
|
||||
FileInputSource (const FileInputSource&);
|
||||
const FileInputSource& operator= (const FileInputSource&);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_FILEINPUTSOURCE_JUCEHEADER__
|
||||
80
src/juce_core/io/streams/juce_InputSource.h
Normal file
80
src/juce_core/io/streams/juce_InputSource.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified 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.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_INPUTSOURCE_JUCEHEADER__
|
||||
#define __JUCE_INPUTSOURCE_JUCEHEADER__
|
||||
|
||||
#include "../juce_InputStream.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A lightweight object that can create a stream to read some kind of resource.
|
||||
|
||||
This may be used to refer to a file, or some other kind of source, allowing a
|
||||
caller to create an input stream that can read from it when required.
|
||||
|
||||
@see FileInputSource
|
||||
*/
|
||||
class JUCE_API InputSource
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
InputSource() throw() {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~InputSource() {}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a new InputStream to read this item.
|
||||
|
||||
@returns an inputstream that the caller will delete, or 0 if
|
||||
the filename isn't found.
|
||||
*/
|
||||
virtual InputStream* createInputStream() = 0;
|
||||
|
||||
/** Returns a new InputStream to read an item, relative.
|
||||
|
||||
@param relatedItemPath the relative pathname of the resource that is required
|
||||
@returns an inputstream that the caller will delete, or 0 if
|
||||
the item isn't found.
|
||||
*/
|
||||
virtual InputStream* createInputStreamFor (const String& relatedItemPath) = 0;
|
||||
|
||||
/** Returns a hash code that uniquely represents this item.
|
||||
*/
|
||||
virtual int64 hashCode() const = 0;
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_INPUTSOURCE_JUCEHEADER__
|
||||
|
|
@ -34,17 +34,7 @@
|
|||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_XmlDocument.h"
|
||||
#include "../io/files/juce_FileInputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
XmlInputSource::XmlInputSource() throw()
|
||||
{
|
||||
}
|
||||
|
||||
XmlInputSource::~XmlInputSource()
|
||||
{
|
||||
}
|
||||
#include "../io/streams/juce_FileInputSource.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -60,34 +50,6 @@ static bool isXmlIdentifierChar_Slow (const tchar c) throw()
|
|||
#define isXmlIdentifierChar(c) \
|
||||
((c > 0 && c <= 127) ? identifierLookupTable [(int) c] : isXmlIdentifierChar_Slow (c))
|
||||
|
||||
//==============================================================================
|
||||
class FileInputSource : public XmlInputSource
|
||||
{
|
||||
public:
|
||||
FileInputSource (const File& file_) throw()
|
||||
: file (file_)
|
||||
{
|
||||
}
|
||||
|
||||
~FileInputSource()
|
||||
{
|
||||
}
|
||||
|
||||
InputStream* createInputStreamFor (const String& filename)
|
||||
{
|
||||
if (filename.isEmpty())
|
||||
return file.createInputStream();
|
||||
else
|
||||
return file.getSiblingFile (filename).createInputStream();
|
||||
}
|
||||
|
||||
private:
|
||||
const File file;
|
||||
|
||||
FileInputSource (const FileInputSource&);
|
||||
const FileInputSource& operator= (const FileInputSource&);
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
XmlDocument::XmlDocument (const String& documentText) throw()
|
||||
|
|
@ -106,7 +68,7 @@ XmlDocument::~XmlDocument() throw()
|
|||
delete inputSource;
|
||||
}
|
||||
|
||||
void XmlDocument::setInputSource (XmlInputSource* const newSource) throw()
|
||||
void XmlDocument::setInputSource (InputSource* const newSource) throw()
|
||||
{
|
||||
if (inputSource != newSource)
|
||||
{
|
||||
|
|
@ -121,7 +83,7 @@ XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentEle
|
|||
|
||||
if (textToParse.isEmpty() && inputSource != 0)
|
||||
{
|
||||
InputStream* const in = inputSource->createInputStreamFor (String::empty);
|
||||
InputStream* const in = inputSource->createInputStream();
|
||||
|
||||
if (in != 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,39 +35,7 @@
|
|||
#include "juce_XmlElement.h"
|
||||
#include "juce_StringArray.h"
|
||||
#include "../io/files/juce_File.h"
|
||||
#include "../io/juce_InputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Used by the XmlDocument class to find a document's associated files.
|
||||
|
||||
Because an XML document might need to reference other files for its
|
||||
external DTDs, this class can be used to create input streams for
|
||||
these files.
|
||||
|
||||
@see XmlDocument
|
||||
*/
|
||||
class JUCE_API XmlInputSource
|
||||
{
|
||||
protected:
|
||||
/** Creates a default source that can read from files. */
|
||||
XmlInputSource() throw();
|
||||
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~XmlInputSource();
|
||||
|
||||
/** Returns a new InputStream to read a required file.
|
||||
|
||||
@param filename the partial filename of a file that needs to be read,
|
||||
or an empty string to open the root document that the
|
||||
source refers to
|
||||
@returns an inputstream that the caller will delete, or 0 if
|
||||
the filename isn't found.
|
||||
*/
|
||||
virtual InputStream* createInputStreamFor (const String& filename) = 0;
|
||||
};
|
||||
#include "../io/streams/juce_InputSource.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -150,9 +118,9 @@ public:
|
|||
|
||||
The object that is passed-in will be deleted automatically when no longer needed.
|
||||
|
||||
@see XmlInputSource
|
||||
@see InputSource
|
||||
*/
|
||||
void setInputSource (XmlInputSource* const newSource) throw();
|
||||
void setInputSource (InputSource* const newSource) throw();
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -167,7 +135,7 @@ private:
|
|||
String lastError, dtdText;
|
||||
StringArray tokenisedDTD;
|
||||
bool needToLoadDTD;
|
||||
XmlInputSource* inputSource;
|
||||
InputSource* inputSource;
|
||||
|
||||
void setLastError (const String& desc, const bool carryOn) throw();
|
||||
void skipHeader() throw();
|
||||
|
|
|
|||
|
|
@ -155,12 +155,18 @@
|
|||
#ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__
|
||||
#include "juce_core/io/streams/juce_BufferedInputStream.h"
|
||||
#endif
|
||||
#ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__
|
||||
#include "juce_core/io/streams/juce_FileInputSource.h"
|
||||
#endif
|
||||
#ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__
|
||||
#include "juce_core/io/streams/juce_GZIPCompressorOutputStream.h"
|
||||
#endif
|
||||
#ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__
|
||||
#include "juce_core/io/streams/juce_GZIPDecompressorInputStream.h"
|
||||
#endif
|
||||
#ifndef __JUCE_INPUTSOURCE_JUCEHEADER__
|
||||
#include "juce_core/io/streams/juce_InputSource.h"
|
||||
#endif
|
||||
#ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__
|
||||
#include "juce_core/io/streams/juce_MemoryInputStream.h"
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue