1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-16 00:34:19 +00:00

Added CDDB support for mac. Small fix for iPad text entry.

This commit is contained in:
Julian Storer 2010-07-26 16:18:21 +01:00
parent 1335673bf0
commit cd14d5efa5
21 changed files with 428 additions and 358 deletions

View file

@ -299,7 +299,7 @@
reduce code size.
*/
#ifndef JUCE_USE_CDREADER
#define JUCE_USE_CDREADER 0
#define JUCE_USE_CDREADER 1
#endif
/** JUCE_USE_CAMERA: Enables web-cam support using the CameraDevice class (Mac and Windows).
@ -22470,6 +22470,47 @@ END_JUCE_NAMESPACE
/*** End of inlined file: juce_WavAudioFormat.cpp ***/
/*** Start of inlined file: juce_AudioCDReader.cpp ***/
#if JUCE_USE_CDREADER
BEGIN_JUCE_NAMESPACE
int AudioCDReader::getNumTracks() const
{
return trackStartSamples.size() - 1;
}
int AudioCDReader::getPositionOfTrackStart (int trackNum) const
{
return trackStartSamples [trackNum];
}
const Array<int>& AudioCDReader::getTrackOffsets() const
{
return trackStartSamples;
}
int AudioCDReader::getCDDBId()
{
int checksum = 0;
const int numTracks = getNumTracks();
for (int i = 0; i < numTracks; ++i)
for (int offset = (trackStartSamples.getUnchecked(i) + 88200) / 44100; offset > 0; offset /= 10)
checksum += offset % 10;
const int length = (trackStartSamples.getLast() - trackStartSamples.getFirst()) / 44100;
// CCLLLLTT: checksum, length, tracks
return ((checksum & 0xff) << 24) | (length << 8) | numTracks;
}
END_JUCE_NAMESPACE
#endif
/*** End of inlined file: juce_AudioCDReader.cpp ***/
/*** Start of inlined file: juce_AudioFormatReaderSource.cpp ***/
BEGIN_JUCE_NAMESPACE
@ -245023,7 +245064,7 @@ public:
CloseHandle (scsiHandle);
}
bool readTOC (TOC* lpToc, bool useMSF);
bool readTOC (TOC* lpToc);
bool readAudio (CDReadBuffer* buffer, CDReadBuffer* overlapBuffer = 0);
void openDrawer (bool shouldBeOpen);
@ -245581,7 +245622,7 @@ int CDController::getLastIndex()
return 0;
}
bool CDDeviceHandle::readTOC (TOC* lpToc, bool useMSF)
bool CDDeviceHandle::readTOC (TOC* lpToc)
{
HANDLE event = CreateEvent (0, TRUE, FALSE, 0);
@ -245599,7 +245640,7 @@ bool CDDeviceHandle::readTOC (TOC* lpToc, bool useMSF)
s.SRB_CDBLen = 0x0A;
s.SRB_PostProc = event;
s.CDBByte[0] = 0x43;
s.CDBByte[1] = (BYTE)(useMSF ? 0x02 : 0x00);
s.CDBByte[1] = 0x00;
s.CDBByte[7] = 0x03;
s.CDBByte[8] = 0x24;
@ -245965,11 +246006,6 @@ static int getAddressOf (const TOCTRACK* const t)
(((DWORD)t->addr[2]) << 8) + ((DWORD)t->addr[3]);
}
static int getMSFAddressOf (const TOCTRACK* const t)
{
return 60 * t->addr[1] + t->addr[2];
}
static const int samplesPerFrame = 44100 / 75;
static const int bytesPerFrame = samplesPerFrame * 4;
@ -246083,7 +246119,6 @@ AudioCDReader::AudioCDReader (void* handle_)
sampleRate = 44100.0;
bitsPerSample = 16;
lengthInSamples = getPositionOfTrackStart (numTracks);
numChannels = 2;
usesFloatingPointData = false;
@ -246189,7 +246224,7 @@ bool AudioCDReader::readSamples (int** destSamples, int numDestChannels, int sta
// sometimes the read fails for just the very last couple of blocks, so
// we'll ignore and errors in the last half-second of the disk..
ok = startSampleInFile > (trackStarts [numTracks] - 20000);
ok = startSampleInFile > (trackStartSamples [getNumTracks()] - 20000);
break;
}
}
@ -246204,50 +246239,35 @@ bool AudioCDReader::isCDStillPresent() const
TOC toc;
zerostruct (toc);
return ((CDDeviceWrapper*) handle)->cdH->readTOC (&toc, false);
}
int AudioCDReader::getNumTracks() const
{
return numTracks;
}
int AudioCDReader::getPositionOfTrackStart (int trackNum) const
{
using namespace CDReaderHelpers;
return (trackNum >= 0 && trackNum <= numTracks) ? trackStarts [trackNum] * samplesPerFrame
: 0;
return ((CDDeviceWrapper*) handle)->cdH->readTOC (&toc);
}
void AudioCDReader::refreshTrackLengths()
{
using namespace CDReaderHelpers;
zeromem (trackStarts, sizeof (trackStarts));
trackStartSamples.clear();
zeromem (audioTracks, sizeof (audioTracks));
TOC toc;
zerostruct (toc);
if (((CDDeviceWrapper*)handle)->cdH->readTOC (&toc, false))
if (((CDDeviceWrapper*)handle)->cdH->readTOC (&toc))
{
numTracks = 1 + toc.lastTrack - toc.firstTrack;
int numTracks = 1 + toc.lastTrack - toc.firstTrack;
for (int i = 0; i <= numTracks; ++i)
{
trackStarts[i] = getAddressOf (&toc.tracks[i]);
audioTracks[i] = ((toc.tracks[i].ADR & 4) == 0);
trackStartSamples.add (samplesPerFrame * getAddressOf (&toc.tracks [i]));
audioTracks [i] = ((toc.tracks[i].ADR & 4) == 0);
}
}
else
{
numTracks = 0;
}
lengthInSamples = getPositionOfTrackStart (getNumTracks());
}
bool AudioCDReader::isTrackAudio (int trackNum) const
{
return (trackNum >= 0 && trackNum <= numTracks) ? audioTracks [trackNum]
: false;
return trackNum >= 0 && trackNum < getNumTracks() && audioTracks [trackNum];
}
void AudioCDReader::enableIndexScanning (bool b)
@ -246393,44 +246413,6 @@ const Array <int> AudioCDReader::findIndexesInTrack (const int trackNumber)
return indexes;
}
int AudioCDReader::getCDDBId()
{
using namespace CDReaderHelpers;
refreshTrackLengths();
if (numTracks > 0)
{
TOC toc;
zerostruct (toc);
if (((CDDeviceWrapper*) handle)->cdH->readTOC (&toc, true))
{
int n = 0;
for (int i = numTracks; --i >= 0;)
{
int j = getMSFAddressOf (&toc.tracks[i]);
while (j > 0)
{
n += (j % 10);
j /= 10;
}
}
if (n != 0)
{
const int t = getMSFAddressOf (&toc.tracks[numTracks])
- getMSFAddressOf (&toc.tracks[0]);
return ((n % 0xff) << 24) | (t << 8) | numTracks;
}
}
}
return 0;
}
void AudioCDReader::ejectDisk()
{
using namespace CDReaderHelpers;
@ -261365,16 +261347,6 @@ bool AudioCDReader::isCDStillPresent() const
return false;
}
int AudioCDReader::getNumTracks() const
{
return 0;
}
int AudioCDReader::getPositionOfTrackStart (int trackNum) const
{
return 0;
}
bool AudioCDReader::isTrackAudio (int trackNum) const
{
return false;
@ -261394,11 +261366,6 @@ const Array<int> AudioCDReader::findIndexesInTrack (const int trackNumber)
return Array<int>();
}
int AudioCDReader::getCDDBId()
{
return 0;
}
#endif
/*** End of inlined file: juce_linux_AudioCDReader.cpp ***/
@ -261838,34 +261805,30 @@ void SystemStats::initialiseStats()
{
initialised = true;
#if JUCE_MAC
// extremely annoying: adding this line stops the apple menu items from working. Of
// course, not adding it means that carbon windows (e.g. in plugins) won't get
// any events.
//NSApplicationLoad();
[NSApplication sharedApplication];
#endif
#if JUCE_MAC
[NSApplication sharedApplication];
#endif
#if JUCE_INTEL
unsigned int familyModel, extFeatures;
const unsigned int features = getCPUIDWord (familyModel, extFeatures);
#if JUCE_INTEL
unsigned int familyModel, extFeatures;
const unsigned int features = getCPUIDWord (familyModel, extFeatures);
cpuFlags.hasMMX = ((features & (1 << 23)) != 0);
cpuFlags.hasSSE = ((features & (1 << 25)) != 0);
cpuFlags.hasSSE2 = ((features & (1 << 26)) != 0);
cpuFlags.has3DNow = ((extFeatures & (1 << 31)) != 0);
#else
cpuFlags.hasMMX = false;
cpuFlags.hasSSE = false;
cpuFlags.hasSSE2 = false;
cpuFlags.has3DNow = false;
#endif
cpuFlags.hasMMX = ((features & (1 << 23)) != 0);
cpuFlags.hasSSE = ((features & (1 << 25)) != 0);
cpuFlags.hasSSE2 = ((features & (1 << 26)) != 0);
cpuFlags.has3DNow = ((extFeatures & (1 << 31)) != 0);
#else
cpuFlags.hasMMX = false;
cpuFlags.hasSSE = false;
cpuFlags.hasSSE2 = false;
cpuFlags.has3DNow = false;
#endif
#if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
cpuFlags.numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
#else
cpuFlags.numCpus = (int) MPProcessors();
#endif
#if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
cpuFlags.numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
#else
cpuFlags.numCpus = (int) MPProcessors();
#endif
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
@ -265558,6 +265521,9 @@ END_JUCE_NAMESPACE
[self addSubview: hiddenTextField];
hiddenTextField.delegate = self;
hiddenTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
hiddenTextField.autocorrectionType = UITextAutocorrectionTypeNo;
return self;
}
@ -274322,20 +274288,97 @@ void AudioCDReader::ejectDisk()
// compiled on its own).
#if JUCE_INCLUDED_FILE && JUCE_USE_CDREADER
static void juce_findCDs (Array<File>& cds)
namespace CDReaderHelpers
{
File volumes ("/Volumes");
volumes.findChildFiles (cds, File::findDirectories, false);
inline const XmlElement* getElementForKey (const XmlElement& xml, const String& key)
{
forEachXmlChildElementWithTagName (xml, child, "key")
if (child->getAllSubText() == key)
return child->getNextElement();
for (int i = cds.size(); --i >= 0;)
if (! cds.getReference(i).getChildFile (".TOC.plist").exists())
cds.remove (i);
return 0;
}
static int getIntValueForKey (const XmlElement& xml, const String& key, int defaultValue = -1)
{
const XmlElement* const block = getElementForKey (xml, key);
return block != 0 ? block->getAllSubText().getIntValue() : defaultValue;
}
// Get the track offsets for a CD given an XmlElement representing its TOC.Plist.
// Returns NULL on success, otherwise a const char* representing an error.
static const char* getTrackOffsets (XmlDocument& xmlDocument, Array<int>& offsets)
{
const ScopedPointer<XmlElement> xml (xmlDocument.getDocumentElement());
if (xml == 0)
return "Couldn't parse XML in file";
const XmlElement* const dict = xml->getChildByName ("dict");
if (dict == 0)
return "Couldn't get top level dictionary";
const XmlElement* const sessions = getElementForKey (*dict, "Sessions");
if (sessions == 0)
return "Couldn't find sessions key";
const XmlElement* const session = sessions->getFirstChildElement();
if (session == 0)
return "Couldn't find first session";
const int leadOut = getIntValueForKey (*session, "Leadout Block");
if (leadOut < 0)
return "Couldn't find Leadout Block";
const XmlElement* const trackArray = getElementForKey (*session, "Track Array");
if (trackArray == 0)
return "Couldn't find Track Array";
forEachXmlChildElement (*trackArray, track)
{
const int trackValue = getIntValueForKey (*track, "Start Block");
if (trackValue < 0)
return "Couldn't find Start Block in the track";
offsets.add (trackValue * AudioCDReader::samplesPerFrame - 88200);
}
offsets.add (leadOut * AudioCDReader::samplesPerFrame - 88200);
return 0;
}
static void findDevices (Array<File>& cds)
{
File volumes ("/Volumes");
volumes.findChildFiles (cds, File::findDirectories, false);
for (int i = cds.size(); --i >= 0;)
if (! cds.getReference(i).getChildFile (".TOC.plist").exists())
cds.remove (i);
}
struct TrackSorter
{
static int getCDTrackNumber (const File& file)
{
return file.getFileName().initialSectionContainingOnly ("0123456789").getIntValue();
}
static int compareElements (const File& first, const File& second)
{
const int firstTrack = getCDTrackNumber (first);
const int secondTrack = getCDTrackNumber (second);
jassert (firstTrack > 0 && secondTrack > 0);
return firstTrack - secondTrack;
}
};
}
const StringArray AudioCDReader::getAvailableCDNames()
{
Array<File> cds;
juce_findCDs (cds);
CDReaderHelpers::findDevices (cds);
StringArray names;
@ -274348,7 +274391,7 @@ const StringArray AudioCDReader::getAvailableCDNames()
AudioCDReader* AudioCDReader::createReaderForCD (const int index)
{
Array<File> cds;
juce_findCDs (cds);
CDReaderHelpers::findDevices (cds);
if (cds[index].exists())
return new AudioCDReader (cds[index]);
@ -274378,51 +274421,23 @@ void AudioCDReader::refreshTrackLengths()
{
tracks.clear();
trackStartSamples.clear();
lengthInSamples = 0;
volumeDir.findChildFiles (tracks, File::findFiles | File::ignoreHiddenFiles, false, "*.aiff");
struct CDTrackSorter
{
static int getCDTrackNumber (const File& file)
{
return file.getFileName()
.initialSectionContainingOnly ("0123456789")
.getIntValue();
}
static int compareElements (const File& first, const File& second)
{
const int firstTrack = getCDTrackNumber (first);
const int secondTrack = getCDTrackNumber (second);
jassert (firstTrack > 0 && secondTrack > 0);
return firstTrack - secondTrack;
}
};
CDTrackSorter sorter;
CDReaderHelpers::TrackSorter sorter;
tracks.sort (sorter);
AiffAudioFormat format;
int sample = 0;
const File toc (volumeDir.getChildFile (".TOC.plist"));
for (int i = 0; i < tracks.size(); ++i)
if (toc.exists())
{
trackStartSamples.add (sample);
XmlDocument doc (toc);
const char* error = CDReaderHelpers::getTrackOffsets (doc, trackStartSamples);
(void) error; // could be logged..
FileInputStream* const in = tracks.getReference(i).createInputStream();
if (in != 0)
{
ScopedPointer <AudioFormatReader> r (format.createReaderFor (in, true));
if (r != 0)
sample += (int) r->lengthInSamples;
}
lengthInSamples = trackStartSamples.getLast() - trackStartSamples.getFirst();
}
trackStartSamples.add (sample);
lengthInSamples = sample;
}
bool AudioCDReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
@ -274484,19 +274499,9 @@ bool AudioCDReader::isCDStillPresent() const
return volumeDir.exists();
}
int AudioCDReader::getNumTracks() const
{
return tracks.size();
}
int AudioCDReader::getPositionOfTrackStart (int trackNum) const
{
return trackStartSamples [trackNum];
}
bool AudioCDReader::isTrackAudio (int trackNum) const
{
return tracks [trackNum] != File::nonexistent;
return tracks [trackNum].hasFileExtension (".aiff");
}
void AudioCDReader::enableIndexScanning (bool b)
@ -274514,11 +274519,6 @@ const Array <int> AudioCDReader::findIndexesInTrack (const int trackNumber)
return Array <int>();
}
int AudioCDReader::getCDDBId()
{
return 0; //xxx
}
#endif
/*** End of inlined file: juce_mac_AudioCDReader.mm ***/