I am creating MIDI sounds with MusicDeviceMIDIEvent and it's perfectly fine, I use some aupreset files I've created. One for each instrument.
My code is basically the example from apple: LoadPresetDemo. All I use is:
- (void)loadPreset:(id)sender instrumentName:(const char *)instrumentName {
NSString *presetURL1 = [NSString stringWithCString:instrumentName encoding:NSUTF8StringEncoding];
NSString *path = [[NSBundle mainBundle] pathForResource:presetURL1 ofType:#"aupreset"];
NSURL *presetURL = [[NSURL alloc] initFileURLWithPath: path];
if (presetURL) {
NSLog(#"Attempting to load preset '%#'\n", [presetURL description]);
}
else {
NSLog(#"COULD NOT GET PRESET PATH!");
}
[self loadSynthFromPresetURL: presetURL];
}
To load my aupreset file, then:
- (void) noteOn:(id)sender midiNumber:(int)midiNumber {
UInt32 noteNum = midiNumber;
UInt32 onVelocity = 127;
UInt32 noteCommand = kMIDIMessage_NoteOn << 4 | 0;
OSStatus result = noErr;
require_noerr (result = MusicDeviceMIDIEvent (self.samplerUnit, noteCommand, noteNum, onVelocity, 0), logTheError);
logTheError:
if (result != noErr) NSLog (#"Unable to start playing the low note. Error code: %d '%.4s'\n", (int) result, (const char *)&result);
}
to play the note of the previously loaded aupreset, and:
- (void) noteOff:(id)sender midiNumber:(int)midiNumber
when I want it to stop.
Now I would like to play one note of each instrument simultaneously. What is the easiest way of doing this?
Related
I want to record audio and streaming on another iPhone.
Is this format correct for record and streaming?
format -> mSampleRate = 44100.00; //
format -> mFormatID = kAudioFormatLinearPCM; //
format -> mFramesPerPacket = 1;
format -> mChannelsPerFrame = 1; //
format -> mBitsPerChannel = 16; //
format -> mReserved = 0;
format -> mBytesPerPacket = 2;
format -> mBytesPerFrame = 2;
format -> mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
call for start recording:
- (void) startRecordingInQueue {
[self setupAudioFormat:&recordState.dataFormat];
recordState.currentPacket = 0;
OSStatus status;
status = AudioQueueNewInput(&recordState.dataFormat, AudioInputCallback, &recordState, CFRunLoopGetCurrent(),kCFRunLoopCommonModes, 0, &recordState.queue);
status = 0;
if(status == 0) {
//Prime recording buffers with empty data
AudioQueueBufferRef buffer;
for (int i=0; i < NUM_BUFFERS; i++) {
AudioQueueAllocateBuffer(recordState.queue, SAMPLERATE, &recordState.buffers[i]);
AudioQueueEnqueueBuffer(recordState.queue, recordState.buffers[i], 0, NULL);
}
status = AudioFileCreateWithURL(fileURL, kAudioFileAIFFType, &recordState.dataFormat, kAudioFileFlags_EraseFile, &recordState.audioFile);
NSLog(#"ss %i",status);
status = 0;
if (status == 0) {
recordState.recording = true;
status = AudioQueueStart(recordState.queue, NULL);
if(status == 0) {
NSLog(#"-----------Recording--------------");
NSLog(#"File URL : %#", fileURL);
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#",fileURL] relativeToURL:NULL];
[[NSUserDefaults standardUserDefaults] setURL:url forKey:#"fileUrl"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
}
if (status != 0) {
[self stopRecordingInQueue];
}
}
if it ok،
How to get out audio buffer data for sending to the server in this code?
And how to play its data in other devices?
void AudioInputCallback(void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription * inPacketDescs)
{
RecordState * recordState = (RecordState*)inUserData;
if (!recordState->recording)
{
printf("Not recording, returning\n");
}
printf("Writing buffer %lld\n", recordState->currentPacket);
OSStatus status = AudioFileWritePackets(recordState->audioFile,
false,
inBuffer->mAudioDataByteSize,
inPacketDescs,
recordState->currentPacket,
&inNumberPacketDescriptions,
inBuffer->mAudioData);
if (status == 0)
{
recordState->currentPacket += inNumberPacketDescriptions;
AudioQueueEnqueueBuffer(recordState->queue, inBuffer, 0, NULL);
}
}
if anyone has complete code for this project please link me to source.
thanks
This one of my code you try it to change the formate
Here I stopped the audio recording after that I'm sending to server. This is my requirement. For this I'm converting audio file into .wav. After sending into server also it's playing successfully. Try it...
- (IBAction)stop:(id)sender { // On tap stop button
NSString *urlString;
NSLog(#"Stop Recording");
if ([audioRecorder isRecording]) // If recording audio
{
[audioRecorder stop]; //Stop it
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:NO error:nil];
NSLog(#"%#", audioRecorder.url);
unsigned long long size = [[NSFileManager defaultManager] attributesOfItemAtPath:[audioRecorder.url path] error:nil].fileSize;//Get audio file path
NSLog(#"This is the file size of the recording in bytes: %llu", size); // Audio file size in bytes
Here my file saved in documents directory with filename "Audio". So no fetched that file and I changed file name into 56e254fa816e8_1519650589.wav and I'm sending that file to server.
self.sendFileName = [#"56e254fa816e8" stringByAppendingString:#"_"];
self.sendFileName = [self.sendFileName stringByAppendingString:[#(self.unixTimeStamp) stringValue]];
self.sendFileName = [self.sendFileName stringByAppendingString:#".wav"]; // Here name converted in to .wav completely
NSLog(#"%#", self.sendFileName);//See here the file formate
urlString = [audioRecorder.url.absoluteString stringByReplacingOccurrencesOfString:#"Audio" withString:self.sendFileName];
self.sendingURL = [NSURL URLWithString:urlString];
NSLog(#"%#", self.sendingURL);//Complete file url
}
}
Try this...
I'm successfully loading a Sound Font (.sf2) to a MusicSequence when the MusicSequence it's loaded by file (.mid) like the following:
//the interesting code ...
NSString *midiFilePath = [[NSBundle mainBundle]
pathForResource:#"song"
ofType:#"mid"];
// Create a new URL which points to the MIDI file
NSURL * midiFileURL = [NSURL fileURLWithPath:filePath];
MusicSequenceFileLoad(s, (__bridge CFURLRef) midiFileURL, 0, 0);
// Create a new music player
MusicPlayer p;
// Initialise the music player
NewMusicPlayer(&p);
// ************* Set the endpoint of the sequence to be our virtual endpoint
MusicSequenceSetMIDIEndpoint(s, virtualEndpoint);
// Load the sound font from file
NSURL *presetURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Full Grand Piano" ofType:#"sf2"]];
// Initialise the sound font
[self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)10];
// Load the sequence into the music player
MusicPlayerSetSequence(p, s);
// Called to do some MusicPlayer setup. This just
// reduces latency when MusicPlayerStart is called
MusicPlayerPreroll(p);
// Starts the music playing
MusicPlayerStart(p);
//code continues here ...
-(OSStatus) loadFromDLSOrSoundFont: (NSURL *)bankURL withPatch: (int)presetNumber {
OSStatus result = noErr;
// fill out a bank preset data structure
AUSamplerBankPresetData bpdata;
bpdata.bankURL = (__bridge CFURLRef) bankURL;
bpdata.bankMSB = kAUSampler_DefaultMelodicBankMSB;
bpdata.bankLSB = kAUSampler_DefaultBankLSB;
bpdata.presetID = (UInt8) presetNumber;
// set the kAUSamplerProperty_LoadPresetFromBank property
result = AudioUnitSetProperty(self.samplerUnit,
kAUSamplerProperty_LoadPresetFromBank,
kAudioUnitScope_Global,
0,
&bpdata,
sizeof(bpdata));
// check for errors
NSCAssert (result == noErr,
#"Unable to set the preset property on the Sampler. Error code:%d '%.4s'",
(int) result,
(const char *)&result);
return result;
}
But If I want to apply the same to a MusicSequence with a MusicTrack build with MIDINoteMessages:
//the interesting code here
MusicSequenceNewTrack(musicSequence, &musicTrack);
MusicSequenceGetIndTrack(musicSequence, 0, &(musicTrack));
MIDINoteMessage aMessage;
aMessage.channel = 1;
aMessage.duration = 0.3f;
aMessage.velocity = 200;
for(int i=0; i<numerator; ++i)
{
if (i==0) {
aMessage.note = 80;
}else {
aMessage.note = 60;
}
MusicTrackNewMIDINoteEvent(musicTrack, i, &aMessage);
}
MusicSequenceSetMIDIEndpoint(musicSequence, virtualEndpoint);
// Load the sound font from file
NSURL *presetURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Full Grand Piano" ofType:#"sf2"]];
// Initialise the sound font
[self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)10];
//code continues here
I'm getting a (lldb) error. Any idea how to solve this?
This is the sound font relevant code from my github project. This loads the sound font into your sampler unit. If you need more on setting up the augraph see the project or read this post.
func loadSF2Preset(preset:UInt8) {
// This is the MuseCore soundfont. Change it to the one you have.
if let bankURL = NSBundle.mainBundle().URLForResource("GeneralUser GS MuseScore v1.442", withExtension: "sf2") {
var instdata = AUSamplerInstrumentData(fileURL: Unmanaged.passUnretained(bankURL),
instrumentType: UInt8(kInstrumentType_DLSPreset),
bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB),
bankLSB: UInt8(kAUSampler_DefaultBankLSB),
presetID: preset)
var status = AudioUnitSetProperty(
self.samplerUnit,
AudioUnitPropertyID(kAUSamplerProperty_LoadInstrument),
AudioUnitScope(kAudioUnitScope_Global),
0,
&instdata,
UInt32(sizeof(AUSamplerInstrumentData)))
CheckError(status)
}
}
You associate the augraph with the MusicSequence like this
MusicSequenceSetAUGraph(musicSequence, self.processingGraph)
In my blog post on MIDI callbacks I've included a github project that has code to create a MusicSequence on the fly as you are trying to do.
when i play my sound it says there is something wrong with the code but i cannot see what it is. The game runs fine until i try to play the sound which is when it terminates with uncaught exception of type NSException. It is not the best example of Open Al but can anybody see what is wrong with it?
- (id)init
{
self = [super init];
if (self)
{
openALDevice = alcOpenDevice(NULL);
openALContext = alcCreateContext(openALDevice, NULL);
alcMakeContextCurrent(openALContext);
}
return self;
}
-(void)playSound {
NSUInteger sourceID;
alGenSources(1, &sourceID);
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"flyby" ofType:#"caf"];
NSURL *audioFileURL = [NSURL fileURLWithPath:audioFilePath];
AudioFileID afid;
OSStatus openAudioFileResult = AudioFileOpenURL((__bridge CFURLRef)audioFileURL, kAudioFileReadPermission, 0, &afid);
if (0 != openAudioFileResult)
{
NSLog(#"An error occurred when attempting to open the audio file %#: %ld", audioFilePath, openAudioFileResult);
return;
}
UInt64 audioDataByteCount = 0;
UInt32 propertySize = sizeof(audioDataByteCount);
OSStatus getSizeResult = AudioFileGetProperty(afid, kAudioFilePropertyAudioDataByteCount, &propertySize, &audioDataByteCount);
if (0 != getSizeResult)
{
NSLog(#"An error occurred when attempting to determine the size of audio file %#: %ld", audioFilePath, getSizeResult);
}
UInt32 bytesRead = (UInt32)audioDataByteCount;
void *audioData = malloc(bytesRead);
OSStatus readBytesResult = AudioFileReadBytes(afid, false, 0, &bytesRead, audioData);
if (0 != readBytesResult)
{
NSLog(#"An error occurred when attempting to read data from audio file %#: %ld", audioFilePath, readBytesResult);
}
AudioFileClose(afid);
ALuint outputBuffer;
alGenBuffers(1, &outputBuffer);
alBufferData(outputBuffer, AL_FORMAT_STEREO16, audioData, bytesRead, 44100);
if (audioData)
{
free(audioData);
audioData = NULL;
}
alSourcef(sourceID, AL_PITCH, 1.0f);
alSourcef(sourceID, AL_GAIN, 1.0f);
alSourcei(sourceID, AL_BUFFER, outputBuffer);
alSourcePlay(sourceID);
}
i'm using OpenAL to play background music and sound effects in a game, the code to play background music is this;
- (void) playSoundBack
{
alGenSources(1, &sourceIDBack);
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"wav"];
NSURL *audioFileURL = [NSURL fileURLWithPath:audioFilePath];
AudioFileID afid;
OSStatus openAudioFileResult = AudioFileOpenURL((__bridge CFURLRef)audioFileURL, kAudioFileReadPermission, 0, &afid);
if (0 != openAudioFileResult)
{
NSLog(#"An error occurred when attempting to open the audio file %#: %ld", audioFilePath, openAudioFileResult);
return;
}
UInt64 audioDataByteCount = 0;
UInt32 propertySize = sizeof(audioDataByteCount);
OSStatus getSizeResult = AudioFileGetProperty(afid, kAudioFilePropertyAudioDataByteCount, &propertySize, &audioDataByteCount);
if (0 != getSizeResult)
{
NSLog(#"An error occurred when attempting to determine the size of audio file %#: %ld", audioFilePath, getSizeResult);
}
UInt32 bytesRead = (UInt32)audioDataByteCount;
void *audioData = malloc(bytesRead);
OSStatus readBytesResult = AudioFileReadBytes(afid, false, 0, &bytesRead, audioData);
if (0 != readBytesResult)
{
NSLog(#"An error occurred when attempting to read data from audio file %#: %ld", audioFilePath, readBytesResult);
}
AudioFileClose(afid);
ALuint outputBuffer;
alGenBuffers(1, &outputBuffer);
alBufferData(outputBuffer, AL_FORMAT_STEREO16, audioData, bytesRead, 44100);
if (audioData)
{
free(audioData);
audioData = NULL;
}
alSourcef(sourceIDBack, AL_GAIN, 0.1f);
alSourcei(sourceIDBack, AL_BUFFER, outputBuffer);
alSourcei(sourceIDBack, AL_LOOPING, AL_TRUE);
alSourcePlay(sourceIDBack);
}
With another similar block of code i play some effects during the game. All the sound are played but i have a problem with volumes... The background music volume change and it seems not an absolute value... When the other effects are playing the background music volume is low as i have set in with AL_GAIN,but when no other effect is playing the background music sounds too loud (or at least this is my sensation...). Why the music has this behaviour? The volume setting like 0.1 are relative? It is possible to set a fixed and universal value?
I've successfully gotten iOS to play a .mid (midi) file with a soundfont sample using the following code:
-(void) playMusic:(NSString*) name
{
NSString *presetURLPath = [[NSBundle mainBundle] pathForResource:#"GortsMiniPianoJ1" ofType:#"SF2"];
NSURL * presetURL = [NSURL fileURLWithPath:presetURLPath];
[self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)3];
NSString *midiFilePath = [[NSBundle mainBundle] pathForResource:name ofType:#"mid"];
NSURL * midiFileURL = [NSURL fileURLWithPath:midiFilePath];
NewMusicPlayer(&musicPlayer);
if (NewMusicSequence(&musicSequence) != noErr)
{
[NSException raise:#"play" format:#"Can't create MusicSequence"];
}
if(MusicSequenceFileLoad(musicSequence, (CFURLRef)midiFileURL, 0, 0 != noErr))
{
[NSException raise:#"play" format:#"Can't load MusicSequence"];
}
MusicPlayerSetSequence(musicPlayer, musicSequence);
MusicSequenceSetAUGraph(musicSequence, _processingGraph);
MusicPlayerPreroll(musicPlayer);
MusicPlayerStart(musicPlayer);
}
However, the problem comes when I then try to play a second file when the first is still playing.
I've tried many variations. Firstly, the above code will play both tracks simultaneously. Or, I've tried:
DisposeMusicPlayer(musicPlayer);
DisposeMusicSequence(musicSequence);
Before the NewMusicPlayer(&musicPlayer), but this produces a weird version of the tune with only sporadic notes being played.
I'd love to simply call this method, and the next track to be played.
Ok, I found the answer on how to properly dispose of a MusicPlayer and MusicSequence.
-(void) stop
{
OSStatus result = noErr;
result = MusicPlayerStop(musicPlayer);
UInt32 trackCount;
MusicSequenceGetTrackCount(musicSequence, &trackCount);
MusicTrack track;
for(int i=0;i<trackCount;i++)
{
MusicSequenceGetIndTrack (musicSequence, i, &track);
result = MusicSequenceDisposeTrack(musicSequence, track);
}
result = DisposeMusicPlayer(musicPlayer);
result = DisposeMusicSequence(musicSequence);
result = DisposeAUGraph(_processingGraph);
}