Playing a Sound With Monotouch - iphone

No matter what I try (build -> content, NSUrl, filename) I get a 'null exception': file not found when I try to play a .caf sound file in monotouch.
//var path = NSBundle.MainBundle.PathForResource("MatchGame", "caf");
//var gameSong = SystemSound.FromFile( new NSUrl(path, false));
var gameSong = SystemSound.FromFile("MatchGame.caf");
gameSong.PlaySystemSound();
I also try combinations using the folder name "images/MatchGame.caf" and moving MatchGame.caf into the root folder.
What am I missing? Thanks a lot.
Here is a link to a video of adding the sound in monotouch. http://www.screencast.com/t/MmE0ZmFh What is wrong?

Bryan,
From looking at your screencast - you are trying to play a mp3 file and not a caf file. Mp3 files are encoded differently and will not play with the SystemSound class that's there (I can't remember if you can do this in Obj-C or not.)
You'll want to use the AVFoundation Namespace and AVAudioPlayer class.
using Monotouch.AVFoundation;
var mediaFile = NSUrl.FromFilename("myMp3.mp3");
var audioPlayer = AVAudioPlayer.FromUrl(mediaFile);
audioPlayer.FinishedPlaying += delegate { audioPlayer.Dispose(); };
audioPlayer.Play();
You might need to tweak the code above - I don't have MonoDevelop to hand but that should help you a little further.
Cheers,
ChrisNTR

You need the first line:
var path = NSBundle.MainBundle.PathForResource("MatchGame", "caf");
Then make sure that your audio file is included in the application by making sure that your CAF file is flagged as "Content" in the Properties pane, otherwise the file is not copied to the resulting application package (your .app)
You can follow the steps documented here (they are for images, but apply the same to audio files):
http://wiki.monotouch.net/HowTo/Images/Add_an_Image_to_your_Project
Additionally, this is a good resource for where you should store files:
http://wiki.monotouch.net/HowTo/Files/HowTo%3a_Store_Files

Related

Is there a way to work with FileManager and NSBundle to get all the applications that support a given type of file in the /Applications directory?

I'm creating a Commandline tool that will get an input from a user to search for a specific application that supports a certain file extension. For example, if I enter mp4, it will probably show me QuickTime. I'm looking for the specific FileManager manipulation to achieve this in Swift.
I think you are looking for NSWorkspace.urlForApplication(toOpen:). It finds the application that would be opened if you had double clicked on a file, and returns its URL. Since it requires a file to work, you need to first create a temporary empty file somewhere, with the desired extension, then call this method.
let tempFileURL = FileManager.default.temporaryDirectory.appendingPathComponent("foo.mp4")
FileManager.default.createFile(atPath: tempFileURL.path, contents: nil, attributes: nil)
// this gives me the URL for QuickTime Player:
// file:///System/Applications/QuickTime%20Player.app/
let url = NSWorkspace.shared.urlForApplication(toOpen: tempFileURL)

SWIFT - Is it possible to save audio from AVAudioEngine, or from AudioPlayerNode? If yes, how?

I've been looking around Swift documentation to save an audio output from AVAudioEngine but I couldn't find any useful tip.
Any suggestion?
Solution
I found a way around thanks to matt's answer.
Here a sample code of how to save an audio after passing it through an AVAudioEngine (i think that technically it's before)
newAudio = AVAudioFile(forWriting: newAudio.url, settings: nil, error: NSErrorPointer())
//Your new file on which you want to save some changed audio, and prepared to be bufferd in some new data...
var audioPlayerNode = AVAudioPlayerNode() //or your Time pitch unit if pitch changed
//Now install a Tap on the output bus to "record" the transformed file on a our newAudio file.
audioPlayerNode.installTapOnBus(0, bufferSize: (AVAudioFrameCount(audioPlayer.duration)), format: opffb){
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in
if (self.newAudio.length) < (self.audioFile.length){//Let us know when to stop saving the file, otherwise saving infinitely
self.newAudio.writeFromBuffer(buffer, error: NSErrorPointer())//let's write the buffer result into our file
}else{
audioPlayerNode.removeTapOnBus(0)//if we dont remove it, will keep on tapping infinitely
println("Did you like it? Please, vote up for my question")
}
}
Hope this helps !
One issue to solve:
Sometimes, your outputNode is shorter than the input: if you accelerate the time rate by 2, your audio will be 2 times shorter. This is the issue im facing for now since my condition for saving the file is (line 10)
if(newAudio.length) < (self.audioFile.length)//audiofile being the original(long) audio and newAudio being the new changed (shorter) audio.
Any help here?
Yes, it's quite easy. You simply put a tap on a node and save the buffer into a file.
Unfortunately this means you have to play through the node. I was hoping that AVAudioEngine would let me process one sound file into another directly, but apparently that's impossible - you have to play and process in real time.
Offline rendering Worked for me using GenericOutput AudioUnit. Please check this link, I have done mixing two,three audios offline and combine it to a single file. Not the same scenario but it may help you for getting some idea. core audio offline rendering GenericOutput

SKAction playsoundfilenamed fails to load sound

No matter what wav file I tried to play in an project, I keep getting the same error. The error states: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Resource namedfile.wav can not be loaded'
I cannot get any sound of any kind to load using SKAction.playSoundFilenamed. I have made sure that the file is names correctly and that doesn't seem to be the problem.
I have tested this in several projects, including the following test Game project wherein I use all default code except for a call to the SKAction
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "Hello, World!";
myLabel.fontSize = 65;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
let soundfile = SKAction.playSoundFileNamed("soundProject.wav", waitForCompletion: false)
runAction(soundfile)
self.addChild(myLabel)
}
I cannot get any sound of any kind to load using SKAction.playSoundFilenamed. I already checked to made sure that the file is named correctly and that it exits in the bundle. Any help would be greatly appreciated. Thank you
UPDATE I Ran my attached code on a different computer, and it compliled and ran perfectly. There must be something wrong with my xcode/simulator. Does anyone know how to reset it? Thanks
When you select your sound file in XCode, access the inspector on the right side, then make sure the file is selected for your target(s).
What color is your Sounds folder?
If it's blue, it means it's a Folder Reference.
If it's yellow, it's a Group.
You Choose Folder Reference -vs- Group when you import your folder.
I've found that SKAction.playSoundFilenamed functions correctly only when it's loaded as a Group (Yellow).
For me, this was the issue. Both of these compiled fine and gave no errors, but only the latter actually played the sound.
Did not work:
SKAction.playSoundFileNamed("combo.mp3", waitForCompletion: true)
Did work:
node.run(SKAction.playSoundFileNamed("combo.mp3", waitForCompletion: true))
Good luck!
Here is another lead that might help you.
Sometimes SKAction is not very handy with audio files.
I haven't found in which case exactly (might be : size file, sound length, ...).
In that case, you would want to use AVAudioPlayerinstead of it.
In order to not write your own "player", I suggest you to use an existing one. Here is one I've already used (SKTAudio) : https://github.com/raywenderlich/SKTUtils/blob/master/SKTUtils/SKTAudio.swift
Here is how to use it :
// For background audio (playing continuously)
SKTAudio.sharedInstance().playBackgroundMusic("music.wav") // Start the music
SKTAudio.sharedInstance().pauseBackgroundMusic() // Pause the music
SKTAudio.sharedInstance().resumeBackgroundMusic() // Resume the music
// For short sounds
SKTAudio.sharedInstance().playSoundEffect("sound.wav") // Play the sound once
Please let me know if the file is not played even with AVAudioPlayer. If so, it might be a problem with it and not the way it's played.
for swift 3.0:
SKAction.run {
SKAction.playSoundFileNamed("soundProject.wav",
waitForCompletion: false)
}
and of course, verify if the resource is in project/copy Phases.
I identified the issue. I had to change the sound settings on my mac through the system preferences. Once I changes all of the settings to use only the internal speakers, the problem was resolved.
swift 5:
Instead of
SKAction.repeatForever(SKAction.playSoundFileNamed("Sounds/theme.mp3",
waitForCompletion: true))
I wrote
SKNode().run(
SKAction.repeatForever(SKAction.playSoundFileNamed("Sounds/theme.mp3",
waitForCompletion: true))
)
And it works good.

Http live streaming to iphone

I'm trying to play an http live stream to iphone, it looks like i have looked every example, mistakes and everything that i could found on the internet and apple docs about http live stream, and i think i'm in a dead end now.. I'm using MPMoviePlayer as in most of examples. Also i have to add the i can see the stream if i open the url from vlc player.
I succeeded in playing the apple BipBop stream on my iPhone that is here but can't play my stream. I figured that my url shows not in the m3u8 file so i found this terminal command, and successfully used it.
/Applications/VLC.app/Contents/MacOS/VLC --intf=rc rtp://#239.35.86.11:10000
'--sout=#transcode{fps=25,vcodec=h264,venc=x264{aud,profile=baseline,level=30, keyint=30,bframes=0,ref=1,nocabac},acodec=mp3,ab=56,audio-sync,deinterlace}:standard{mux=ts,dst=-,access=file}' | mediastreamsegmenter -b http://192.168.1.16/~Jonas/streaming/ -f
/users/jonas/sites/streaming/ -D
Now i have a playlist m3u8 file locally on my machine. As i understand with the command i download stream divide it into smaller ts files and generate m3u8 file that is like a reference to those ts files. So i've tried to load this, but still no luck. For some reasons i can't even open the m3u8 file in vlc or itunes, it throws me errors. So i guess it is something wrong with the playlist file?
Maybe some of you can see what am i doing wrong here or have some suggestions how to find my problem? I would really appreciate it.
It looks like your iOS code is just fine and that it is your server-side code that is causing issues, primarily with regards to generating the m3u8 playlist and possibly with how you're hosting the ts files that it references.
Unfortunately my example code is a bit noisy as I wrote it a year ago (it is in python) and it does a bit more than you're asking for (it live-transcodes a video into the correct m3u8/ts stuff) but it is tested and functional.
You can take a look at the code here: https://github.com/DFTi/ScribbeoServer/blob/python/transcode.py
I will paste some of the relevant methods here for your convenience; I hope it helps you:
def start_transcoding(self, videoPath):
if DISABLE_LIVE_TRANSCODE:
print "Live transcoding is currently disabled! There is a problem with your configuration."
return
print "Initiating transcode for asset at path: "+videoPath
videoPath = unquote(videoPath)
video_md5 = md5.new(videoPath).hexdigest()
if self.sessions.has_key(video_md5): # Session already exists?
return self.m3u8_bitrates_for(video_md5)
transcodingSession = TranscodeSession(self, videoPath)
if transcodingSession.can_be_decoded():
self.sessions[transcodingSession.md5] = transcodingSession
return self.m3u8_bitrates_for(transcodingSession.md5)
else:
return "Cannot decode this file."
def m3u8_segments_for(self, md5_hash, video_bitrate):
segment = string.Template("#EXTINF:$length,\n$md5hash-$bitrate-$segment.ts\n")
partCount = math.floor(self.sessions[md5_hash].duration / 10)
m3u8_segment_file = "#EXTM3U\n#EXT-X-TARGETDURATION:10\n"
for i in range(0, int(partCount)):
m3u8_segment_file += segment.substitute(length=10, md5hash=md5_hash, bitrate=video_bitrate, segment=i)
last_segment_length = math.ceil((self.sessions[md5_hash].duration - (partCount * 10)))
m3u8_segment_file += segment.substitute(length=last_segment_length, md5hash=md5_hash, bitrate=video_bitrate, segment=i)
m3u8_segment_file += "#EXT-X-ENDLIST"
return m3u8_segment_file
def m3u8_bitrates_for(self, md5_hash):
m3u8_fudge = string.Template(
"#EXTM3U\n"
# "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=384000\n"
# "$hash-384-segments.m3u8\n"
# "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=512000\n"
# "$hash-512-segments.m3u8\n"
"#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n"
"$hash-768-segments.m3u8\n"
# "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1024000\n"
# "$hash-1024-segments.m3u8\n"
)
return m3u8_fudge.substitute(hash=md5_hash)
def segment_path(self, md5_hash, the_bitrate, segment_number):
# A segment was requested.
path = self.sessions[md5_hash].transcode(segment_number, the_bitrate)
if path:
return path
else:
raise "Segment path not found"
That project is all open source now and can be found here: https://github.com/DFTi/ScribbeoServer/tree/python
Binaries can be found here: http://scribbeo.com/server
Good luck!

Titanium Convert TiFile Object to TiFileSystemFile Object

How to save the recorded audio file which is recorded using sound_record.js from Titanium KickenSink Source.
We have,
var file // global variable.
file = recording.stop(); // file will have recorded content which we will convert into media.sound in order to play.
var newDir = Titanium.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory,'audioclips');
Ti.API.info("Created mydir: " + newDir.createDirectory());
var newFile = Titanium.Filesystem.getFile(newDir.nativePath,'newfile.wav');
newFile.write(file.read());
But i am able to save the file which is recorded?
I am not getting how to save this recorded file, I dont knw where i am going wrong.
Please Help,
Thanks in Advance.
I am guessing your are having problem with saving the file. In last line just change
newFile.write(file.read());
to
newFile.write(file);
This should do the trick for you.
Hope this helps.
Edited:
For saving the file try this code:
var newFile =Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,'your_file.wav');
// Write the data.
newFile.write( file );