Reputation: 28720
i want to store audio files(any of these formats mp3,wav,and iphone supported) in database and play them in iphone...any idea how to do this?
Upvotes: 3
Views: 7016
Reputation: 319
It's not always best to store the file on disk. Have a look at this comparison:
http://www.sqlite.org/intern-v-extern-blob.html
Here is how I do it using ruby and the sequel gem:
Create a table using this schema. The file is a blob, the sha is the name of the file. In this case, all my files are variable bit rate mono mp3 files, 2K-3K in size. I have about 40 000 files in the db. I'm using a sha1 value as file name since I have a lot of entries that have the same sound so I'm saving some space.
CREATE TABLE `sound` (`id` integer PRIMARY KEY AUTOINCREMENT, `sha` text, `file` blob); CREATE INDEX `sound_sha_index` ON `sound` (`sha`);
Using ruby you can create the db like this:
db = Sequel.sqlite('./sound.db')
db.create_table :sound do
primary_key :id, :index => true
column :sha, :text, :index => true
column :file, :blob
end
Load the files into the database. Assuming you have the files in a directory called 'sound', here is how:
DB = Sequel.sqlite('./sound.db')
files = Dir['./sound/*.mp3']
files.each_with_index do |f, i|
# progress
print "\r #{((i.to_f / files.size)*100).round(2)}%"
# get the file name without directory and extension
f =~ /\/sound\/(.+)\.mp3/
# insert into db
DB[:sound].insert :sha => $1, :file => File.read("#{f}").to_sequel_blob
end
Play sound in the iPhone app. Copy the sound.db file to your iPhone project. This is the code I'm using. It's based on FMDB and AVAudioPlayer.
SoundPlayer.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import "FMDatabase.h"
#import "FMDatabaseQueue.h"
@interface SoundPlayer : NSObject
{
FMDatabaseQueue *db;
}
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
- (void)play:(NSString *)sha;
- (void)free;
@end
SoundPlayer.m
#import "SoundPlayer.h"
#import "DictAppDelegate.h"
@implementation SoundPlayer
- (SoundPlayer*)init
{
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"sound.db"];
db = [FMDatabaseQueue databaseQueueWithPath: dbPath];
return self;
}
- (void)play:(NSString *)sha
{
[db inDatabase:^(FMDatabase *connection) {
// Execute and fetch result
NSString *query = [NSString stringWithFormat:@"select file from sound where sha = '%@' limit 1", sha];
FMResultSet *rs = [connection executeQuery:query];
while([rs next]) {
NSData *file = [rs dataForColumn: @"file"];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithData: file error:&error];
self.audioPlayer.numberOfLoops = 0;
self.audioPlayer.volume = 1.0f;
[self.audioPlayer prepareToPlay];
if (self.audioPlayer == nil) {
NSLog(@"Error playing sound: %@", [error description]);
} else {
[self.audioPlayer play];
}
}
}];
}
// Cleanup
- (void)free {
[db close];
}
@end
Use the file from somewhere in your code like this:
self.soundPlayer = [[SoundPlayer alloc] init];
[self.soundPlayer play:[entry valueForKey:@"sha"]];
where [entry valueForKey:@"sha"]] returns a NSString which is the file name I have stored in my other table of entries.
Upvotes: 3
Reputation: 4664
In general it's best to not store binary files in any database. You are better off writing that file to the disk as a file and then storing the path in the database.
Upvotes: 2
Reputation: 39760
I don't know why you would want to store the audio files in a SQL database but sqlite3 supports BLOB. So store them as BLOB and retrieve them.
Alternatively why not store references to the files that you want to play?
Upvotes: 6