25 May '13 - 06:26 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: 1 ... 17 18 [19] 20 21 ... 36
  Reply  |  Print  
Author Topic: BASS for iOS (iPhone/iPad)  (Read 110131 times)
sui
Guest
« Reply #360 on: 24 Jan '12 - 07:45 »
Reply with quoteQuote

Streaming AAC from the internet on iOS is pretty complicated. Probably not the best choice for a 1st project Smiley

The problem is that the buffered file system isn't supported when using a CoreAudio codec (eg. for AAC); if it was supported, you could simply use BASS_StreamCreateURL and not bother with BASS_StreamCreateFileUser. That means you can't use STREAMFILE_BUFFERPUSH in your BASS_StreamCreateFileUser call; FILESYSTEM_NOBUFFER (the unbuffered file system) is the only option available when playing AAC. That introduces another problem in that it expects the data to be available immediately and any delays (eg. waiting for data to download) will block the decoding thread, possibly resulting in breaks in the output, but that can be mitigated by having a dedicated thread hosting the stream decoding. Here's a previous thread on the subject...

   www.un4seen.com/forum/?topic=13185

OK, I read this subject and I try to write a decoding channel. But I need some help to write my callbacks. When I create this stream by calling :

decoder = BASS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, BASS_STREAM_DECODE, &fileprocs, data);

I always get an error (41, BASS_ERROR_FILEFORM), even if I feed 'data' with a MP3 file...

Someone can help me to write my callbacks ? I don't know how to read data from a NSMutableData.

Thanks Smiley
Logged
einsteinx2
Posts: 61


« Reply #361 on: 24 Jan '12 - 19:18 »
Reply with quoteQuote

@sui, In createFileUser, you would generally not send your audio data in the user parameter, that would usually be some identifying information about that stream, or a reference to self so you can access class properties and methods, however you certainly can in the case of reading directly from an NSData object.

As a quick example, you could do a simple stream like this (assuming you have initialized BASS already):

Creating the stream:
BASS_FILEPROCS fileProcs = {MyFileCloseProc, MyFileLenProc, MyFileReadProc, MyFileSeekProc}; // callback table
HSTREAM stream = BASS_StreamCreateFileUser(STREAMFILE_NOBUFFER, BASS_STREAM_DECODE, &fileProcs, userInfo); // Note userInfo is a custom object I created to hold information about that stream, it can be anything you want
BASS_ChannelSetSync(fileStream1, BASS_SYNC_FREE, 0, MyStreamFreeCallback, userInfo); // call back I created to release my userInfo object

The callbacks:
NSUInteger filePosition = 0;
void CALLBACK MyStreamFreeCallback(HSYNC handle, DWORD channel, DWORD data, void *user)
{
// Stream is done, release the user info object
BassUserInfo *userInfo = (BassUserInfo *)user;
[userInfo release];
// also maybe release your NSData object
}

void CALLBACK MyFileCloseProc(void *user)
{
// Close the file handle
BassUserInfo *userInfo = (BassUserInfo *)user;
//fclose(userInfo.myFileHandle); // Only used if reading from a file, if reading from NSData then not needed
}

QWORD CALLBACK MyFileLenProc(void *user)
{
BassUserInfo *userInfo = (BassUserInfo *)user;
//return [[[NSFileManager defaultManager] attributesOfItemAtPath:userInfo.mySong.localPath error:NULL] fileSize]; // that's for file on disk
return [userInfo.myData length]; // return size of nsdata
}

DWORD CALLBACK MyFileReadProc(void *buffer, DWORD length, void *user)
{
// Read from the file
BassUserInfo *userInfo = (BassUserInfo *)user;
//return fread(buffer, 1, length, userInfo.myFileHandle); // this would be for reading from a file
[userInfo.myData getBytes:buffer range:NSRangeMake(filePosition, length)];
NSUInteger numBytesGrabbed = filePosition + length <= [userInfo.myData length] ? length : [userInfo.myData length] - filePosition;
filePosition += numBytesGrabbed;
return numBytesGrabbed;
}

BOOL CALLBACK MyFileSeekProc(QWORD offset, void *user)
{
// Seek to the requested offset (returns false if data not that large)
BassUserInfo *userInfo = (BassUserInfo *)user;
//return !fseek(userInfo.myFileHandle, offset, SEEK_SET); // this would be for reading from a file
if (offset > [userInfo.myData length])
return NO;
filePosition = offset;
return YES;
}

Note none of this code is tested (I'm reading from files in my own code) but it's adapted directly from my code.

Hope that helps Smiley
« Last Edit: 24 Jan '12 - 19:34 by einsteinx2 » Logged
einsteinx2
Posts: 61


« Reply #362 on: 24 Jan '12 - 19:32 »
Reply with quoteQuote

@Ian, Sorry, I need to clarify what I wrote. In re-reading it I realize it is misleading.

The sound quality issue I'm having with BASS is for all music played back using BASS to handle the output. It's not the quality of the resampling I'm worried about there (with the exception of those higher than 96KHz files I was having issues with the hiss). For whatever reason, any music played using BASS for the audio output results in about 20-30% lower volume than using Audio Queue Services and has less thickness in the mids and low end, sounding kind of tinny.

At first I was worried it was some problem deep in BASS's audio processing and it was just producing poor quality audio, so to verify, I tried using just the decoded output from a BASS file stream and passing those audio packets to an Audio Queue. That totally fixed the audio quality issues I was experiencing. So it seems like either the Audio Queue does some kind of special processing that BASS's audio output doesn't do, or there is some bug in the way BASS outputs audio on the iOS platform that causes lower volume and perceived quality.

Where I ran into the resampling issue, is when I tried to take non-44.1KHz files decoded with BASS and run them through an Audio Queue at 44.1KHz. First I was getting audio playing at different speeds, then I used BASSMix but got poor results. This is different from the issues I have with >96KHz files, as when passing audio to an audio queue and resampling using BASSMix, even files that played perfectly using BASS's output don't play well now. Essentially anything but 44.1KHz files don't play properly.

I'll try and get a recording today and upload it to your FTP, but here's the code I'm using to resample that's not working. It plays at the correct speed but it very choppy:

// Choose the proper sample rate
NSInteger streamSampleRate = [self bassStreamSampleRate:fileStream1];
NSInteger preferredSampleRate = [self preferredSampleRate:streamSampleRate];

// Initialize the audio queue with the preferred sample rate
[self aqsInit:preferredSampleRate];

// Check the actual sample rate and modify the stream if necessary
NSInteger audioQueueSampleRate = [self audioQueueSampleRate];
if (audioQueueSampleRate != streamSampleRate)
{
fileStreamResample1 = BASS_Mixer_StreamCreate(audioQueueSampleRate, 2, BASS_STREAM_DECODE|BASS_MIXER_END);
BASS_Mixer_StreamAddChannel(fileStreamResample1, fileStream1, 0);
}
« Last Edit: 24 Jan '12 - 19:36 by einsteinx2 » Logged
Ian @ un4seen
Administrator
Posts: 15276


« Reply #363 on: 25 Jan '12 - 13:21 »
Reply with quoteQuote

Hi - I am trying to track down and fix the cause of a freeze/deadlock issue like the one described here...

To narrow-down the cause, please try running your app under the debugger, and then post each thread's callstack when the deadlock occurs.

OK, I read this subject and I try to write a decoding channel. But I need some help to write my callbacks. When I create this stream by calling :

decoder = BASS_StreamCreateFileUser(STREAMFILE_BUFFERPUSH, BASS_STREAM_DECODE, &fileprocs, data);

I always get an error (41, BASS_ERROR_FILEFORM), even if I feed 'data' with a MP3 file...

Someone can help me to write my callbacks ? I don't know how to read data from a NSMutableData.

I'm not sure it's worthwhile bothering with that, as it won't help you to play AAC due to the lack of support for the buffered file system (eg. STREAMFILE_BUFFERPUSH). I'll see if something can be done to add support for the buffered file system (including BASS_StreamCreateURL) when using CoreAudio codecs.

For whatever reason, any music played using BASS for the audio output results in about 20-30% lower volume than using Audio Queue Services and has less thickness in the mids and low end, sounding kind of tinny.

That's strange. Would it be possible to create a little test app to reproduce the problem in order to investigate?

I'll try and get a recording today and upload it to your FTP, but here's the code I'm using to resample that's not working. It plays at the correct speed but it very choppy:

Please also post the code where you're calling BASS_ChannelGetData to get data from the mixer. It sounds like the problem may be in there, eg. perhaps not getting enough data.
Logged
Chun-Koo Park
Guest
« Reply #364 on: 25 Jan '12 - 14:48 »
Reply with quoteQuote

I tested BASS library(January 20/mp3_free version), with iOS native AVPlayer.
There is a notable volume difference between the two. I guess mp3_free version's
mp3 decoding uses native iOS decoder, but there's about 6 dB difference in the output.
AVPlayer's output is louder.

BASS_Init(-1, 44000, 0, self, NULL);
chan = BASS_StreamCreateFile(FALSE,[filepath UTF8String],0,0,0);
BASS_ChannelPlay(chan, YES);
//BASS_ChannelSetAttribute(chan, BASS_ATTRIB_VOL, 1.0);

setting the volume to 1.0 produces the same result.
I also tried using 32-bit float output, same result.

Any ideas why the output volume is so different?
Logged
Ian @ un4seen
Administrator
Posts: 15276


« Reply #365 on: 25 Jan '12 - 18:03 »
Reply with quoteQuote

You're right! Comparing the 2 just now, the BASS output does seem to be around 6dB lower. I'm not sure where that's coming from though (the output mix looks fine). I'll look into it.
Logged
einsteinx2
Posts: 61


« Reply #366 on: 25 Jan '12 - 21:09 »
Reply with quoteQuote

You're right! Comparing the 2 just now, the BASS output does seem to be around 6dB lower. I'm not sure where that's coming from though (the output mix looks fine). I'll look into it.

Glad to see you I'm not the only one Tongue

Also, it doesn't seem to just be the volume, it also has the side affect of the low/mid section not being as "thick" (only word I can think of to describe it) and the high end being extra sharp/tinny, even when adjusting volumes to match (e.g. lowering the volume when using an audio queue to match the BASS volume, then switching back and forth between the two app versions playing the same song).

-------

Regarding my resampling issue, here's the code in my get data method (has extra logic for gapless playback):

- (DWORD)bassGetOutputData:(void *)buffer length:(DWORD)length
{
DWORD r;
if (BASSisFilestream1 && BASS_ChannelIsActive(fileStream1))
{
//HSTREAM stream = fileStreamTempo1 ? fileStreamTempo1 : fileStream1;

// Read data from stream1
if (fileStreamTempo1)
r = BASS_ChannelGetData(fileStreamTempo1, buffer, length);
else
r = BASS_ChannelGetData(fileStream1, buffer, length);

// Check if stream1 is now complete
if (!BASS_ChannelIsActive(fileStream1))
{
// Stream1 is done, free the stream
DLog(@"stream 1 is done");
BASS_StreamFree(fileStream1);
if (fileStreamTempo1) BASS_StreamFree(fileStreamTempo1);
fileStreamTempo1 = 0;

// Increment current playlist index
[currPlaylistDAO performSelectorOnMainThread:@selector(incrementIndex) withObject:nil waitUntilDone:YES];

// Send song end notification
[NSNotificationCenter postNotificationToMainThreadWithName:ISMSNotification_SongPlaybackEnded];

// Check to see if there is another song to play
DLog(@"fileStream2: %i", fileStream2);
if (BASS_ChannelIsActive(fileStream2))
{
// Notify Subsonic that this song is being played

DLog(@"TEST starting stream2: %i", fileStream2);

// Send song start notification
[NSNotificationCenter postNotificationToMainThreadWithName:ISMSNotification_SongPlaybackStarted];

// Read data from stream2
[self setStartByteOffset:0];
BASSisFilestream1 = NO;
if (fileStreamTempo2)
r = BASS_ChannelGetData(fileStreamTempo2, buffer, length);
else
r = BASS_ChannelGetData(fileStream2, buffer, length);
DLog(@"error code: %i", BASS_ErrorGetCode());

// Prepare the next song for playback
[self prepareNextSongStreamInBackground];
}
}
}
else if (BASS_ChannelIsActive(fileStream2))
{
// Read data from stream2
if (fileStreamTempo2)
r = BASS_ChannelGetData(fileStreamTempo2, buffer, length);
else
r = BASS_ChannelGetData(fileStream2, buffer, length);

// Check if stream2 is now complete
if (!BASS_ChannelIsActive(fileStream2))
{
// Stream2 is done, free the stream
DLog(@"stream 2 is done");
BASS_StreamFree(fileStream2);
if (fileStreamTempo2) BASS_StreamFree(fileStreamTempo2);
fileStreamTempo2 = 0;

// Increment current playlist index
[currPlaylistDAO performSelectorOnMainThread:@selector(incrementIndex) withObject:nil waitUntilDone:YES];

// Send song done notification
[NSNotificationCenter postNotificationToMainThreadWithName:ISMSNotification_SongPlaybackEnded];

DLog(@"fileStream1: %i", fileStream1);
if (BASS_ChannelIsActive(fileStream1))
{
DLog(@"TEST starting stream1: %i", fileStream1);
// Send song start notification
[NSNotificationCenter postNotificationToMainThreadWithName:ISMSNotification_SongPlaybackStarted];

[self setStartByteOffset:0];
BASSisFilestream1 = YES;
if (fileStreamTempo1)
r = BASS_ChannelGetData(fileStreamTempo1, buffer, length);
else
r = BASS_ChannelGetData(fileStream1, buffer, length);
DLog(@"error code: %i", BASS_ErrorGetCode());

[self prepareNextSongStreamInBackground];
}
}
}
else
{
DLog(@"Stream not active, freeing BASS");
r = BASS_STREAMPROC_END;
[self performSelectorOnMainThread:@selector(bassFree) withObject:nil waitUntilDone:NO];
}

return r;
}

And my file read proc for the original stream is just calling fread(buffer, 1, length, userInfo.myFileHandle); and returning it's return value.
Logged
sui
Guest
« Reply #367 on: 26 Jan '12 - 09:17 »
Reply with quoteQuote

Thanks einsteinx2, I am now able to play an AAC from remote source. Do you know if it is possible to stream an AAC starting to an offset ? Like BASS_StreamCreateURL(
    char *url,
    DWORD offset,
    DWORD flags,
    DOWNLOADPROC *proc,
    void *user
);
Logged
einsteinx2
Posts: 61


« Reply #368 on: 26 Jan '12 - 22:36 »
Reply with quoteQuote

@sui, I haven't used BASS_StreamCreateURL because I'm doing the downloading myself, but it seems like there are some issues starting an aac file from the middle. I believe you have to start on a frame boundary or it doesn't work. In any case, I haven't been able to get a BASS file stream created from an AAC file that was downloaded in the middle. Working on that now actually.
Logged
einsteinx2
Posts: 61


« Reply #369 on: 27 Jan '12 - 00:57 »
Reply with quoteQuote

@Ian, strangely, the resampling seems to be working perfectly now! No idea why it's working now and it was playing so poorly before, as I didn't change anything in that area. Maybe something else I did over the course of the last two days fixed it, I must have been blocking the read thread in some way.

Also using the filter option drastically improved playback of very high sample rate files, so that seems to be fixed as well.

The only issue I have left now is that I can't start AAC files from within the middle of the file. So for example if someone wants to skip further into the song than has downloaded, I start a new download at the position they want to listen, and try and play that. BASS never seems to properly recognize that it's an AAC file though and fails to play. Doing that with other file types works fine though.

Btw, I want to thank you for being so active on your forum and providing all the help that you do. BASS is an amazingly powerful audio library, but I wouldn't have been able to use it were it not for all your help. Cool
« Last Edit: 27 Jan '12 - 01:13 by einsteinx2 » Logged
Ian @ un4seen
Administrator
Posts: 15276


« Reply #370 on: 27 Jan '12 - 18:17 »
Reply with quoteQuote

@Ian, strangely, the resampling seems to be working perfectly now! No idea why it's working now and it was playing so poorly before, as I didn't change anything in that area. Maybe something else I did over the course of the last two days fixed it, I must have been blocking the read thread in some way.

Also using the filter option drastically improved playback of very high sample rate files, so that seems to be fixed as well.

Good to hear Smiley

The only issue I have left now is that I can't start AAC files from within the middle of the file. So for example if someone wants to skip further into the song than has downloaded, I start a new download at the position they want to listen, and try and play that. BASS never seems to properly recognize that it's an AAC file though and fails to play. Doing that with other file types works fine though.

BASS leaves the AAC detection to the CoreAudio codec/parser, but it does appear that the CoreAudio AAC codec/parser won't accept data that doesn't begin on a frame boundary. Here's an update to try, in which BASS will look for a frame for it...

   www.un4seen.com/stuff/libbass.a

This update should also sort the volume level issue. Please check if you still hear the low/mid section problem you mentioned with it, and if so, upload a file that is particularly affected to test with...

   ftp.un4seen.com/incoming/
Logged
mix1009
Posts: 5


« Reply #371 on: 28 Jan '12 - 01:36 »
Reply with quoteQuote

This update should also sort the volume level issue. Please check if you still hear the low/mid section problem you mentioned with it, and if so, upload a file that is particularly affected to test with...

Could you check if you updated the simulator version. On simulator the 6dB volume difference still exists.
I don't have usb cable now, so i'll test on device when i get hold of one.

thank you.
Logged
mix1009
Posts: 5


« Reply #372 on: 28 Jan '12 - 06:28 »
Reply with quoteQuote

This update should also sort the volume level issue. Please check if you still hear the low/mid section problem you mentioned with it, and if so, upload a file that is particularly affected to test with...

Could you check if you updated the simulator version. On simulator the 6dB volume difference still exists.
I don't have usb cable now, so i'll test on device when i get hold of one.

thank you.

I tested on my iPhone4S/iPad2 and the volume is still about 6dB lower.
I did not notice any distortion in sound, it's just lower.
Logged
Ian @ un4seen
Administrator
Posts: 15276


« Reply #373 on: 30 Jan '12 - 14:46 »
Reply with quoteQuote

That's strange. Are you definitely linking with the updated library? You can use BASS_GetVersion to check that: it should return 0x0204080A.
Logged
mix1009
Posts: 5


« Reply #374 on: 30 Jan '12 - 23:01 »
Reply with quoteQuote

That's strange. Are you definitely linking with the updated library? You can use BASS_GetVersion to check that: it should return 0x0204080A.

My xcode project was messed up.

It's now working Smiley Thank you.
« Last Edit: 31 Jan '12 - 00:04 by mix1009 » Logged
Delphinus
Guest
« Reply #375 on: 2 Feb '12 - 10:14 »
Reply with quoteQuote

Hi,

I try to set a custom loop using BASS_ChannelSetSync and BASS_Channel_SetPosition, I think that's what I should use to do that. But here's the problem, when using the sync it seems that it sync everytime not just when it reaches a specific position.

Here's the code:

Quote

void CALLBACK LoopSyncProc(HSYNC handle, DWORD channel, DWORD data, void* user)
{
    BASS_ChannelSetPosition(channel, [sharedBassManager getLoopIN], BASS_POS_BYTE);
    NSLog(@"SYNCPROC CALLBACK! %d", pos);
}


- (BOOL) PlayMusicLoop:(NSString *)fileName cueIndex:(QWORD)offset endPoint:(QWORD)end
{
    filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"mp3"];
    [self setFilePath:filePath];
    NSLog(@"OFFSET %llu end %llu", offset, end);
    chan = BASS_StreamCreateFile(0, [filePath UTF8String], offset, 0, BASS_STREAM_DECODE | BASS_STREAM_PRESCAN);
    chan = BASS_FX_TempoCreate(chan, BASS_SAMPLE_SOFTWARE | BASS_FX_FREESOURCE);
    if (chan == 0)
        return NO;
    if ((BASS_ChannelPlay(chan, FALSE)) == TRUE)
    {
        isPlaying = TRUE;
        NSLog(@"CHANNEL PLAY TRUE!!");
    }
    HSYNC sync =  BASS_ChannelSetSync(chan, BASS_SYNC_POS, end, (SYNCPROC *)&LoopSyncProc, 0);
    if (sync == 0)
    {
        NSLog(@"SYNC FAILED %d", BASS_ErrorGetCode());
        return NO;
    }
    return YES;
}

If I understand the SetSync function, when the channel reaches the "end" position it goes to the callback function "LoopSyncProc" right? Then in the callback function I set the position channel to a specific position. So it should read from that specific position.
What am I misunderstanding?
Logged
Delphinus
Guest
« Reply #376 on: 2 Feb '12 - 15:11 »
Reply with quoteQuote

Argh... It works I figured it out myself I just got confused with all those flags like BASS_POS_BYTE and BASS_FILEPOS_DECODE.
Logged
Ian @ un4seen
Administrator
Posts: 15276


« Reply #377 on: 2 Feb '12 - 15:58 »
Reply with quoteQuote

I would recommend adding the BASS_SYNC_MIXTIME flag to your BASS_ChannelSetSync call, to have the sync triggered when the decoder reaches the loop position (rather than delaying it until it's heard). I think you may also need to set the sync on the source (use BASS_FX_TempoGetSource) rather than the tempo stream; try that if you find that the loop isn't occurring exactly at the requested position. In that case, you don't need to bother with adding the MIXTIME flag as it will be implied due to the source being a "decoding channel". Please see the BASS_ChannelSetSync documentation for more info.
Logged
Delphinus
Posts: 39


« Reply #378 on: 3 Feb '12 - 10:15 »
Reply with quoteQuote

Thanks it all works Smiley

This lib is really great!
Logged
NetGuru
Posts: 1


« Reply #379 on: 5 Feb '12 - 19:00 »
Reply with quoteQuote

IOS- I'm trying to find an example/info on how to play several audio files at the same time and then record them in a new audio file.  Can someone point me in the right direction?  Thanks Smiley
Logged
Pages: 1 ... 17 18 [19] 20 21 ... 36
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines