1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-05 03:50:07 +00:00

Added a method to String and fixed a glitch in the win32 amalgamated build

This commit is contained in:
Julian Storer 2009-10-13 09:59:54 +01:00
parent 0280c57ff0
commit 409c952072
5 changed files with 675 additions and 10 deletions

View file

@ -11974,6 +11974,11 @@ const String String::dropLastCharacters (const int numberToDrop) const throw()
jmax (0, CharacterFunctions::length (text->text) - numberToDrop));
}
const String String::getLastCharacters (const int numCharacters) const throw()
{
return String (text->text + jmax (0, CharacterFunctions::length (text->text) - jmax (0, numCharacters)));
}
const String String::fromFirstOccurrenceOf (const tchar* const sub,
const bool includeSubString,
const bool ignoreCase) const throw()
@ -261137,6 +261142,637 @@ bool WebBrowserComponent::pageAboutToLoad (const String& url)
// compiled on its own).
#ifdef JUCE_INCLUDED_FILE
@interface UIKitAUIOHost : UIViewController
{
@public
/** READONLY The audio format of the data stream. */
AudioStreamBasicDescription format;
AURenderCallbackStruct inputProc;
Float64 hwSampleRate;
AudioUnit rioUnit;
UGen rawInput;
UGen postFadeOutput;
UGen preFadeOutput;
int bufferSize;
float *floatBuffer;
UInt32 audioInputIsAvailable;
UInt32 numInputChannels;
UInt32 numOutputChannels;
bool isRunning;
float fadeInTime;
UGenArray others;
NSLock* nsLock;
}
/** Initialises the AudioUnit framework and structures.
Do not call this method, it is called automatically when the application launches. */
- (void)initAudio;
/** Construct a UGen graph.
You must implement this in your subclass. You should return a UGen which will be the UGen graph which is
performed and rendered to the host. The input parameter may be ignored if only signal generation is required
or may be used if a processing algorithm is being implemented (e.g., filtering incoming audio data).
@param input The input UGen which will contain audio data from the host.
@return the UGen graph which will be performed */
- (UGen)constructGraph:(UGen)input;
- (void)addOther:(UGen)ugen;
- (void)lock;
- (void)unlock;
- (BOOL)tryLock;
@end
#define NUM_CHANNELS 2
void SetFormat(AudioStreamBasicDescription& format)
{
memset(&format, 0, sizeof(AudioStreamBasicDescription));
format.mFormatID = kAudioFormatLinearPCM;
int sampleSize = sizeof(AudioSampleType);
format.mFormatFlags = kAudioFormatFlagsCanonical;
format.mBitsPerChannel = 8 * sampleSize;
format.mChannelsPerFrame = NUM_CHANNELS;
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame = sampleSize;
format.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
}
int SetupRemoteIO (AudioUnit& inRemoteIOUnit, AURenderCallbackStruct inRenderProc, AudioStreamBasicDescription& outFormat)
{
// Open the output unit
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent comp = AudioComponentFindNext (NULL, &desc);
AudioComponentInstanceNew (comp, &inRemoteIOUnit);
const UInt32 one = 1;
AudioUnitSetProperty(inRemoteIOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one));
AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &inRenderProc, sizeof(inRenderProc));
AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outFormat, sizeof(outFormat));
AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outFormat, sizeof(outFormat));
AudioUnitInitialize(inRemoteIOUnit);
return 0;
}
static const float FloatToFixed824_Factor = 16777216.f;
static const float Fixed824ToFloat_Factor = 5.960464477539e-08f;
static const float FloatToPCM16Bit_Factor = 32767.f;
static const float PCM16BitToFloat_Factor = 3.051850947600e-05f;
static OSStatus PerformThru(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
OSStatus err = 0;
UIKitAUIOHost *x = (UIKitAUIOHost *)inRefCon;
[x lock];
if(x->audioInputIsAvailable)
{
err = AudioUnitRender(x->rioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, ioData);
if (err) { printf("PerformThru: error %d\n", (int)err); return err; }
}
if(inNumberFrames > x->bufferSize)
{
delete [] x->floatBuffer;
x->bufferSize = inNumberFrames;
x->floatBuffer = new float[inNumberFrames * NUM_CHANNELS];
}
long blockID = UGen::getNextBlockID(inNumberFrames);
float *floatBufferData[2];
floatBufferData[0] = x->floatBuffer;
floatBufferData[1] = floatBufferData[0] + inNumberFrames;
if(x->audioInputIsAvailable)
{
for (UInt32 channel = 0; channel < x->numInputChannels; channel++)
{
AudioSampleType *audioUnitBuffer = (AudioSampleType*)ioData->mBuffers[0].mData;
float *floatBuffer = floatBufferData[channel];
for(int sample = 0; sample < inNumberFrames; sample++)
{
floatBuffer[sample] = (float)audioUnitBuffer[sample] * PCM16BitToFloat_Factor;
}
}
x->rawInput.getSource().setInputs((const float**)floatBufferData, inNumberFrames, x->numInputChannels);
}
else
{
memset(x->floatBuffer, 0, x->numInputChannels * inNumberFrames * sizeof(float));
}
x->postFadeOutput.setOutputs(floatBufferData, inNumberFrames, 2);
x->postFadeOutput.prepareAndProcessBlock(inNumberFrames, blockID);
for (UInt32 channel = 0; channel < ioData->mNumberBuffers; channel++)
{
AudioSampleType *audioUnitBuffer = (AudioSampleType*)ioData->mBuffers[channel].mData;
float *floatBuffer = floatBufferData[channel];
for(int sample = 0; sample < inNumberFrames; sample++)
{
audioUnitBuffer[sample] = (AudioSampleType)(floatBuffer[sample] * FloatToPCM16Bit_Factor);
}
}
for(int i = 0; i < x->others.size(); i++)
{
x->others[i].prepareAndProcessBlock(inNumberFrames, blockID);
}
[x unlock];
return err;
}
void propListener(void * inClientData,
AudioSessionPropertyID inID,
UInt32 inDataSize,
const void * inPropertyValue)
{
printf("Property changed!\n");
UIKitAUIOHost *x = (UIKitAUIOHost *)inClientData;
if(!x->isRunning) return;
if(inPropertyValue)
{
CFDictionaryRef routeChangeDictionary = (CFDictionaryRef)inPropertyValue;
CFNumberRef routeChangeReasonRef =
(CFNumberRef)CFDictionaryGetValue (routeChangeDictionary,
CFSTR (kAudioSession_AudioRouteChangeKey_Reason));
SInt32 routeChangeReason;
CFNumberGetValue(routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
CFStringRef newAudioRoute;
UInt32 propertySize = sizeof (CFStringRef);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &newAudioRoute);
printf("route=%s\n", CFStringGetCStringPtr(newAudioRoute, CFStringGetSystemEncoding()));
}
UInt32 size = sizeof(UInt32);
AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &size, &x->numInputChannels);
AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &size, &x->numOutputChannels);
AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &x->audioInputIsAvailable);
printf("inputs=%d outputs=%d audioInputIsAvailable=%d\n", x->numInputChannels, x->numOutputChannels, x->audioInputIsAvailable);
if(x->rioUnit)
{
AudioComponentInstanceDispose(x->rioUnit);
}
SetFormat(x->format);
SetupRemoteIO(x->rioUnit, x->inputProc, x->format);
x->rawInput.setSource(AudioIn::AR(x->numInputChannels), true);
x->postFadeOutput = Plug::AR(UGen::emptyChannels(x->preFadeOutput.getNumChannels()));
x->postFadeOutput.fadeSourceAndRelease(x->preFadeOutput, x->fadeInTime);
AudioSessionSetActive(true);
AudioOutputUnitStart(x->rioUnit);
}
void rioInterruptionListener(void *inClientData, UInt32 inInterruption)
{
printf("Session interrupted! --- %s ---\n", inInterruption == kAudioSessionBeginInterruption ? "Begin Interruption" : "End Interruption");
UIKitAUIOHost *x = (UIKitAUIOHost *)inClientData;
if (inInterruption == kAudioSessionEndInterruption) {
// make sure we are again the active session
//AudioSessionSetActive(false);
AudioSessionSetActive(true);
x->isRunning = true;
AudioOutputUnitStart(x->rioUnit);
}
if (inInterruption == kAudioSessionBeginInterruption) {
x->isRunning = false;
AudioOutputUnitStop(x->rioUnit);
printf("rioInterruptionListener audioInputIsAvailable=%d\n", x->audioInputIsAvailable);
UIAlertView *baseAlert = [[UIAlertView alloc] initWithTitle:@"Audio interrupted"
message:@"This could have been interrupted by another application or due to unplugging a headset:"
delegate:x
cancelButtonTitle:nil
otherButtonTitles:@"Resume", @"Cancel", nil];
[baseAlert show];
}
}
@implementation UIKitAUIOHost
- (id)init
{
if (self = [super init])
{
nsLock = [[NSLock alloc] init];
fadeInTime = 1.0;
[self performSelector:@selector(initAudio) withObject:nil afterDelay:1.0];
}
return self;
}
- (void)initAudio
{
// render proc
inputProc.inputProc = PerformThru;
inputProc.inputProcRefCon = self;
// session
AudioSessionInitialize (NULL, NULL, rioInterruptionListener, self);
AudioSessionSetActive (true);
UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self);
UInt32 size = sizeof(hwSampleRate);
AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &size, &hwSampleRate);
Float32 bufferDuration = 512 / hwSampleRate;
AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(bufferDuration), &bufferDuration);
UGen::initialise();
UGen::prepareToPlay(hwSampleRate, 512);
rawInput = Plug::AR(UGen::emptyChannels(2));
preFadeOutput = [self constructGraph: rawInput];
rioUnit = NULL;
isRunning = true;
propListener((void*)self, 0,0,0);
size = sizeof(format);
AudioUnitGetProperty(rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &format, &size);
//Float32 bufferDuration;
size = sizeof(bufferDuration);
AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &bufferDuration);
bufferSize = (int)(hwSampleRate*bufferDuration+0.5);
floatBuffer = new float[bufferSize * NUM_CHANNELS];
}
- (UGen)constructGraph:(UGen)input
{
return UGen::emptyChannels(NUM_CHANNELS);
}
- (void)addOther:(UGen)ugen
{
[self lock];
others <<= ugen;
[self unlock];
}
- (void)lock
{
[nsLock lock];
}
- (void)unlock
{
[nsLock unlock];
}
- (BOOL)tryLock
{
return [nsLock tryLock];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
printf("buttonIndex=%d\n", buttonIndex);
if(buttonIndex == 0)
{
// resume
isRunning = true;
propListener((void*)self, 0,0,0);
}
[alertView release];
}
-(void) dealloc
{
UGen::shutdown();
delete [] floatBuffer;
[nsLock release];
[super dealloc];
}
@end
class IPhoneAudioIODevice : public AudioIODeviceType
{
public:
IPhoneAudioIODevice (const String& deviceName, const bool isInput_)
: AudioIODevice (deviceName, T("Audio")),
isInput (isInput_),
isOpen_ (false),
isStarted (false)
{
}
~IPhoneAudioIODeviceType()
{
}
const StringArray getOutputChannelNames()
{
StringArray s;
if (! isInput)
{
s.add ("Left");
s.add ("Right");
}
return s;
}
const StringArray getInputChannelNames()
{
StringArray s;
if (isInput)
{
s.add ("Left");
s.add ("Right");
}
return s;
}
int getNumSampleRates()
{
return sampleRates.size();
}
double getSampleRate (int index)
{
return sampleRates [index];
}
int getNumBufferSizesAvailable()
{
return bufferSizes.size();
}
int getBufferSizeSamples (int index)
{
return bufferSizes [index];
}
int getDefaultBufferSize()
{
for (int i = 0; i < getNumBufferSizesAvailable(); ++i)
if (getBufferSizeSamples(i) >= 512)
return getBufferSizeSamples(i);
return 512;
}
const String open (const BitArray& inputChannels,
const BitArray& outputChannels,
double sampleRate,
int bufferSizeSamples)
{
isOpen_ = true;
if (bufferSizeSamples <= 0)
bufferSizeSamples = getDefaultBufferSize();
lastError = String::empty;
isOpen_ = lastError.isEmpty();
return lastError;
}
void close()
{
isOpen_ = false;
}
bool isOpen()
{
return isOpen_;
}
int getCurrentBufferSizeSamples()
{
return internal != 0 ? internal->getBufferSize() : 512;
}
double getCurrentSampleRate()
{
return internal != 0 ? internal->getSampleRate() : 0;
}
int getCurrentBitDepth()
{
return 32; // no way to find out, so just assume it's high..
}
const BitArray getActiveOutputChannels() const
{
return internal != 0 ? internal->activeOutputChans : BitArray();
}
const BitArray getActiveInputChannels() const
{
BitArray chans;
if (internal != 0)
{
chans = internal->activeInputChans;
if (internal->inputDevice != 0)
chans.orWith (internal->inputDevice->activeInputChans);
}
return chans;
}
int getOutputLatencyInSamples()
{
if (internal == 0)
return 0;
// this seems like a good guess at getting the latency right - comparing
// this with a round-trip measurement, it gets it to within a few millisecs
// for the built-in mac soundcard
return internal->outputLatency + internal->getBufferSize() * 2;
}
int getInputLatencyInSamples()
{
if (internal == 0)
return 0;
return internal->inputLatency + internal->getBufferSize() * 2;
}
void start (AudioIODeviceCallback* callback)
{
if (internal != 0 && ! isStarted)
{
if (callback != 0)
callback->audioDeviceAboutToStart (this);
isStarted = true;
internal->start (callback);
}
}
void stop()
{
if (isStarted && internal != 0)
{
AudioIODeviceCallback* const lastCallback = internal->callback;
isStarted = false;
internal->stop (true);
if (lastCallback != 0)
lastCallback->audioDeviceStopped();
}
}
bool isPlaying()
{
if (internal->callback == 0)
isStarted = false;
return isStarted;
}
const String getLastError()
{
return lastError;
}
int inputIndex, outputIndex;
juce_UseDebuggingNewOperator
private:
CoreAudioInternal* internal;
bool isOpen_, isStarted;
String lastError;
static OSStatus hardwareListenerProc (AudioDeviceID /*inDevice*/, UInt32 /*inLine*/, const AudioObjectPropertyAddress* pa, void* inClientData)
{
CoreAudioInternal* const intern = (CoreAudioInternal*) inClientData;
switch (pa->mSelector)
{
case kAudioHardwarePropertyDevices:
intern->deviceDetailsChanged();
break;
case kAudioHardwarePropertyDefaultOutputDevice:
case kAudioHardwarePropertyDefaultInputDevice:
case kAudioHardwarePropertyDefaultSystemOutputDevice:
break;
}
return noErr;
}
CoreAudioIODevice (const CoreAudioIODevice&);
const CoreAudioIODevice& operator= (const CoreAudioIODevice&);
};
class IPhoneAudioIODeviceType : public AudioIODeviceType
{
public:
IPhoneAudioIODeviceType()
: AudioIODeviceType (T("iPhone Audio")),
hasScanned (false)
{
}
~IPhoneAudioIODeviceType()
{
}
void scanForDevices()
{
}
const StringArray getDeviceNames (const bool wantInputNames) const
{
StringArray s;
return s;
}
int getDefaultDeviceIndex (const bool forInput) const
{
return 0;
}
int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
{
return 0;
}
bool hasSeparateInputsAndOutputs() const { return true; }
AudioIODevice* createDevice (const String& outputDeviceName,
const String& inputDeviceName)
{
if (outputDeviceName.isNotEmpty() && inputDeviceName.isNotEmpty())
return new CoreAudioIODevice (deviceName,
inputIds [inputIndex],
inputIndex,
outputIds [outputIndex],
outputIndex);
return 0;
}
juce_UseDebuggingNewOperator
private:
IPhoneAudioIODeviceType (const IPhoneAudioIODeviceType&);
const IPhoneAudioIODeviceType& operator= (const IPhoneAudioIODeviceType&);
};
AudioIODeviceType* juce_createAudioIODeviceType_iPhoneAudio()
{
return new IPhoneAudioIODeviceType();
}
#endif
/********* End of inlined file: juce_iphone_Audio.cpp *********/

View file

@ -1905,7 +1905,7 @@ public:
@param startIndex the index of the start of the substring needed
@param endIndex all characters from startIndex up to (but not including)
this index are returned
@see fromFirstOccurrenceOf, dropLastCharacters, upToFirstOccurrenceOf
@see fromFirstOccurrenceOf, dropLastCharacters, getLastCharacters, upToFirstOccurrenceOf
*/
const String substring (int startIndex,
int endIndex) const throw();
@ -1916,7 +1916,7 @@ public:
of the string, an empty string is returned. If it is zero or
less, the whole string is returned.
@returns the substring from startIndex up to the end of the string
@see dropLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf
@see dropLastCharacters, getLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf
*/
const String substring (const int startIndex) const throw();
@ -1931,6 +1931,15 @@ public:
*/
const String dropLastCharacters (const int numberToDrop) const throw();
/** Returns a number of characters from the end of the string.
This returns the last numCharacters characters from the end of the string. If the
string is shorter than numCharacters, the whole string is returned.
@see substring, dropLastCharacters, getLastCharacter
*/
const String getLastCharacters (const int numCharacters) const throw();
/** Returns a section of the string starting from a given substring.
This will search for the first occurrence of the given substring, and
@ -1982,6 +1991,7 @@ public:
/** Returns the start of this string, up to the last occurrence of a substring.
Similar to upToFirstOccurrenceOf(), but this finds the last occurrence rather than the first.
If the substring isn't found, this will return an empty string.
@see upToFirstOccurrenceOf, fromFirstOccurrenceOf
*/
@ -53543,9 +53553,8 @@ private:
#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__
#define __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__
// this is used to disable QuickTime, and is defined in juce_Config.h
#if JUCE_QUICKTIME || DOXYGEN
// (NB: This stuff mustn't go inside the "#if QUICKTIME" block, or it'll break the
// amalgamated build)
#if JUCE_WINDOWS
/********* Start of inlined file: juce_ActiveXControlComponent.h *********/
@ -53660,6 +53669,9 @@ private:
typedef NSViewComponent QTCompBaseClass;
#endif
// this is used to disable QuickTime, and is defined in juce_Config.h
#if JUCE_QUICKTIME || DOXYGEN
/**
A window that can play back a QuickTime movie.

View file

@ -28,9 +28,8 @@
#include "../../../io/files/juce_File.h"
// this is used to disable QuickTime, and is defined in juce_Config.h
#if JUCE_QUICKTIME || DOXYGEN
// (NB: This stuff mustn't go inside the "#if QUICKTIME" block, or it'll break the
// amalgamated build)
#if JUCE_WINDOWS
#include "juce_ActiveXControlComponent.h"
typedef ActiveXControlComponent QTCompBaseClass;
@ -39,6 +38,9 @@
typedef NSViewComponent QTCompBaseClass;
#endif
// this is used to disable QuickTime, and is defined in juce_Config.h
#if JUCE_QUICKTIME || DOXYGEN
//==============================================================================
/**
A window that can play back a QuickTime movie.

View file

@ -1595,6 +1595,11 @@ const String String::dropLastCharacters (const int numberToDrop) const throw()
jmax (0, CharacterFunctions::length (text->text) - numberToDrop));
}
const String String::getLastCharacters (const int numCharacters) const throw()
{
return String (text->text + jmax (0, CharacterFunctions::length (text->text) - jmax (0, numCharacters)));
}
const String String::fromFirstOccurrenceOf (const tchar* const sub,
const bool includeSubString,
const bool ignoreCase) const throw()

View file

@ -510,7 +510,7 @@ public:
@param startIndex the index of the start of the substring needed
@param endIndex all characters from startIndex up to (but not including)
this index are returned
@see fromFirstOccurrenceOf, dropLastCharacters, upToFirstOccurrenceOf
@see fromFirstOccurrenceOf, dropLastCharacters, getLastCharacters, upToFirstOccurrenceOf
*/
const String substring (int startIndex,
int endIndex) const throw();
@ -521,7 +521,7 @@ public:
of the string, an empty string is returned. If it is zero or
less, the whole string is returned.
@returns the substring from startIndex up to the end of the string
@see dropLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf
@see dropLastCharacters, getLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf
*/
const String substring (const int startIndex) const throw();
@ -536,6 +536,15 @@ public:
*/
const String dropLastCharacters (const int numberToDrop) const throw();
/** Returns a number of characters from the end of the string.
This returns the last numCharacters characters from the end of the string. If the
string is shorter than numCharacters, the whole string is returned.
@see substring, dropLastCharacters, getLastCharacter
*/
const String getLastCharacters (const int numCharacters) const throw();
//==============================================================================
/** Returns a section of the string starting from a given substring.
@ -588,6 +597,7 @@ public:
/** Returns the start of this string, up to the last occurrence of a substring.
Similar to upToFirstOccurrenceOf(), but this finds the last occurrence rather than the first.
If the substring isn't found, this will return an empty string.
@see upToFirstOccurrenceOf, fromFirstOccurrenceOf
*/