Jump to content

  • Log In with Google      Sign In   
  • Create Account

deadstar

Member Since 05 Dec 2007
Offline Last Active Sep 06 2011 05:50 AM

Topics I've Started

Visual C++: Using 'engine' project as dependency for tools

21 August 2011 - 10:32 AM

Hi all,

I have a Visual C++ 2010 solution set up with an 'Engine' project, which depends on Ogre3D. I'm using this Engine project as a dependency for a 3d Studio Max exporter plugin project, which makes use of the 3D mesh file format reader/writer (one .h and one .cpp file) contained within the Engine project.

The problem I'm having is that when I build the Exporter project, it fails to resolve linker dependencies for bits of Ogre, even though none of that stuff is used in the Exporter project (I literally only make use of a 'Mesh' class and its Mesh::Write() function, which just opens a file and dumps data).

How can I set up my solution so that only the required dependencies from the Engine project are linked with the Exporter project? I've tried #ifndef'ing away anything that depends on Ogre with a '3DS_PLUGIN' preprocessor definition, which I've added to the project's settings, but it seems to be ignored when the Exporter project auto-builds Engine as a dependency (I've tested this by added '#error' inside the #ifndef).

Does anyone have ideas how I can achieve this?

Apple CoreAudio - AUGraphStop() takes 25ms to complete

24 March 2011 - 01:21 PM

Hi,

Our audio app is using AUGraphs containing a mixer unit, a converter unit and an output unit. It's a realtime app, so performance is a high concern.

An issue has been flagged up where AUGraphStop() takes 25 milliseconds to complete on the main thread, and our profiler shows that it spends this time sleeping. Could anyone explain why this happens? Is it waiting for the next zero crossover point, or waiting for one more buffer to render?


I've tried several workarounds, including sending one render frame of silence (and setting the kAudioUnitRenderAction_OutputIsSilence flag) before attempting to stop, and calling AUGraphStop() inside the kAudioUnitRenderAction_PostRender notify callback (this has mixed results, and after reading around it doesn't seem a recommended approach).

Here's how we are initialising the graph:


//Configure converter/mixer/output unit descriptors
AudioComponentDescription OutputUnitDesc = { kAudioUnitType_Output ,kAudioUnitSubType_DefaultOutput, kAudioUnitManufacturer_Apple };
AudioComponentDescription MixerUnitDesc = { kAudioUnitType_Mixer, kAudioUnitSubType_MatrixMixer, kAudioUnitManufacturer_Apple };
AudioComponentDescription ConverterUnitDesc = { kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple };

//Create graph
CA_ERR(NewAUGraph(&mAudioGraph));

//Add converter/mixer/output nodes
CA_ERR(AUGraphAddNode(mAudioGraph, &OutputUnitDesc, &mOutputNode));
CA_ERR(AUGraphAddNode(mAudioGraph, &MixerUnitDesc, &mMixerNode));
CA_ERR(AUGraphAddNode(mAudioGraph, &ConverterUnitDesc, &mConverterNode));

//Connect nodes
CA_ERR(AUGraphConnectNodeInput(mAudioGraph, mConverterNode, 0, mMixerNode, 0));
CA_ERR(AUGraphConnectNodeInput(mAudioGraph, mMixerNode, 0, mOutputNode, 0));

//Open the graph (instantiates the units)
CA_ERR(AUGraphOpen(mAudioGraph));

//Get the created units
CA_ERR(AUGraphNodeInfo(mAudioGraph, mOutputNode, NULL, &mOutputUnit));
CA_ERR(AUGraphNodeInfo(mAudioGraph, mMixerNode, NULL, &mMixerUnit));
CA_ERR(AUGraphNodeInfo(mAudioGraph, mConverterNode, NULL, &mConverterUnit));

//Setup stream format description
mStreamDesc.mFormatID = kAudioFormatLinearPCM;
mStreamDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
mStreamDesc.mChannelsPerFrame = Header->nChannels;
mStreamDesc.mSampleRate = (Float64)Header->nSamplesPerSec;
mStreamDesc.mBitsPerChannel = Header->wBitsPerSample;
mStreamDesc.mBytesPerFrame = (Header->wBitsPerSample >> 3) * Header->nChannels;
mStreamDesc.mFramesPerPacket = 1;
mStreamDesc.mBytesPerPacket = mStreamDesc.mBytesPerFrame * mStreamDesc.mFramesPerPacket;
mStreamDesc.mReserved = 0;

//Set data endianness according to file type - TODO: Get endianness from header
AudioSystem::FileType FileType = mSample->GetFiletype();

if(FileType == AudioSystem::WAV)
	mStreamDesc.mFormatFlags |= kAudioFormatFlagsNativeEndian;
else if(FileType == AudioSystem::OGG)
	mStreamDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;

//Configure number of input/output busses for mixer unit
int NumChannelsIn = Header->nChannels;
int NumChannelsOut = (int)AudioSystem::GetOutputChannelConfig();
CA_ERR(AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_BusCount, kAudioUnitScope_Input, 0, &NumChannelsIn, sizeof(u32)));
CA_ERR(AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_BusCount, kAudioUnitScope_Output, 0, &NumChannelsOut, sizeof(u32)));

//Set render callback
AURenderCallbackStruct callback = { AudioRenderCallback, this };
CA_ERR(AUGraphSetNodeInputCallback(mAudioGraph, mConverterNode, 0, &callback));

//Set stream format to something native to CoreAudio
AudioStreamBasicDescription OutputDesc = {0};
UInt32 Size = sizeof(AudioStreamBasicDescription);
CA_ERR(AudioUnitGetProperty(mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &OutputDesc, &Size));

//Set num output channels
OutputDesc.mChannelsPerFrame = (int)AudioSystem::GetOutputChannelConfig();

//Set stream format
CA_ERR(AudioUnitSetProperty(mConverterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &mStreamDesc, sizeof(AudioStreamBasicDescription)));
CA_ERR(AudioUnitSetProperty(mConverterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &OutputDesc, sizeof(AudioStreamBasicDescription)));
CA_ERR(AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &OutputDesc, sizeof(AudioStreamBasicDescription)));
CA_ERR(AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &OutputDesc, sizeof(AudioStreamBasicDescription)));
CA_ERR(AudioUnitSetProperty(mOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &OutputDesc, sizeof(AudioStreamBasicDescription)));

//Initialise graph
CA_ERR(AUGraphInitialize(mAudioGraph));

//Set notification callback
CA_ERR(AUGraphAddRenderNotify(mAudioGraph, AudioNotifyCallback, this));

//Set global mixer volume
CA_ERR(AudioUnitSetParameter(mMixerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Global, 0xFFFFFFFF, 1.0, 0));

//Set input channel volumes
for(int i = 0; i < Header->nChannels; i++)
{
	CA_ERR(AudioUnitSetParameter(mMixerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Input, i, 1.0, 0));
}

//Set output channel volumes
for(int i = 0; i < (int)AudioSystem::GetOutputChannelConfig(); i++)
{
	CA_ERR(AudioUnitSetParameter(mMixerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, i, 1.0, 0));
}



The graph is started and stopped using AUGraphStart() and AUGraphStop(), nothing special. Here's the callstack captured using Shark Profiler:

| | | | | | | | | + 1.3%, AudioUnitGraph::Stop(), AudioToolbox
| | | | | | | | | | + 1.3%, AudioOutputUnitStop, AudioUnit
| | | | | | | | | | | + 1.3%, CallComponentDispatch, CarbonCore
| | | | | | | | | | | | + 1.3%, DefaultOutputAUEntry, CoreAudio
| | | | | | | | | | | | | + 1.3%, AUHALEntry, CoreAudio
| | | | | | | | | | | | | | + 1.3%, usleep$UNIX2003, libSystem.B.dylib
| | | | | | | | | | | | | | | + 1.3%, nanosleep$UNIX2003, libSystem.B.dylib
| | | | | | | | | | | | | | | |   1.3%, __semwait_signal, libSystem.B.dylib

It spends the entirety of AUGraphStop() just sleeping!

I've tried lowering the number of frames per slice, but it doesn't seem to make a difference. I've also tried removing all audio units except the output node, in an attempt to narrow the problem down to a specific unit, but the cost of AUGraphStop() still stands at 25ms.

Any clues?

LEGO Star Wars III: The Clone Wars

22 February 2011 - 03:15 PM

This is the third title released with my name in the credits, and I'm so excited I'm almost shaking! It's out now on Xbox Live (Gold exclusive) - go to Game Marketplace -> Explore -> Games & Demos -> Demos.

Posted Image Posted Image

Laugh your way through an all-new story with the LEGO Star Wars III demo. This demo includes both space and ground levels from the most action-packed LEGO Star Wars game to date. In the full version, the story takes you through 16 different systems and experience brand new features like massive ground battles, boss fights, and multi-layered space combat. Other enhancements include expanded Force abilities, brand new weapons, characters, environments, and over 20 story-based missions.


Eeeeeeeeeeeeeeeeee I can't wait to see it on the shelves!!

Platform abstraction using inheritance and factories

11 January 2011 - 05:24 PM

I'm designing a low-level platform abstraction library (simply for educational purposes), and I'd like to run off my intended plan for how to model it whilst achieving complete transparency to the user.

class Time
{
   public:
  	virtual long GetTicks() = 0;

  	static Time* Create()
  	{
 		#if defined _WIN32
        	return new TimeWin32;
 		#elif defined _LINUX
        	return new TimeLinux;
 		#endif
  	}
};

class TimeWin32
{
   public:
  	long GetTicks() { return SomeWin32GetTimeFunction(); }
};

class TimeLinux
{
   public:
   	long GetTicks() { return SomeLinuxGetTimeFunction(); }
};

//Usage
Time* time = Time::Create();
long CurrTicks = time->GetTicks();

Obviously that wouldn't build off the bat, but you get the idea.

I've done a bit of research, and seen methods like creating a unified header, and putting the function bodies into platform specific .cpp files, then #including the correct ones into the project, but that seems very C-like to me.

Do you have a preferred method?

68000 assembler - how do I define the entry point?

20 December 2010 - 08:54 AM

Long time no see, GD.NET! I've been getting my hands dirty with 68000 assembler, and my weapon of choice is the Atari ST, using DevPac 3.1. I've got as far as being able to move some memory, change registers, handle pointers, jump around subroutines and do some basic maths. Go me!

I'm trying to move some of my subroutines to separate files, using 'include' to reference them, but it results in a bomb immediately on startup. My best guess is that the assembler has no idea which line of code is to be run first, and it bombs on the first 'rts', since there's no routine to return to.

How do I define the entry point? I've looked around the internet in vain. I've found out how it's done for many other assembler languages, but not 68k :(

Thanks in advance.


PARTNERS