I'm writing a command line tool and want to handle various inputs and also want to fire a Timer() on a specific command and also stop it on an other command.
Unfortunately this does not work
import Foundation
class timerTest : NSObject {
var myTimer : Timer? = nil
func startTimer() {
myTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: {_ in
print("Hello")
})
let runLoop = RunLoop()
runLoop.add(myTimer!, forMode: .defaultRunLoopMode)
RunLoop.current.run()
}
func stopTimer() {
myTimer?.invalidate()
}
}
var a = timerTest()
print("Ready")
while true {
var keyboard = FileHandle.standardInput
var inputData = keyboard.availableData
var string = NSString(data: inputData, encoding:String.Encoding.utf8.rawValue) as! String
string = string.trimmingCharacters(in: .whitespacesAndNewlines)
if string == "timer" { a.startTimer() }
if string == "stop" { a.stopTimer() }
}
You can use something like this:
import Foundation
var shouldKeepRunning = true
class CLIInput:NSObject {
var inputTimer:Timer? = nil
var myTimer:Timer? = nil
func getInput() {
inputTimer = Timer.scheduledTimer(withTimeInterval:1, repeats:false, block: {_ in
var input = readLine()!
input = input.trimmingCharacters(in: .whitespacesAndNewlines)
print("Input: \(input)")
if input == "timer" {
print("Start timer")
self.myTimer = Timer.scheduledTimer(withTimeInterval:1, repeats: true, block: {_ in
print("Hello")
})
}
if input == "stop" {
print("Stop timer")
self.myTimer?.invalidate()
self.myTimer = nil
}
if input == "exit" {
print("Time to exit")
self.inputTimer?.invalidate()
self.inputTimer = nil
shouldKeepRunning = false
return
}
// Otherwise, set up timer again
self.getInput()
})
}
}
print("Start")
var cli = CLIInput()
cli.getInput()
let theRL = RunLoop.current
while shouldKeepRunning && theRL.run(mode: .defaultRunLoopMode, before: .distantFuture) { }
However, any time you are waiting for input from standard input, you'll find that your timer block output does not display because output is blocked till your input is complete. As long as your timer process does not need to do any output, the above might (or might not, depending on your requirements) work ...
Related
How make CountdownTimer and how make let elapsed = public var . I want to make the variable constantly decrease life.
For example, as in Tamagotchi - You need to constantly feed the animal so that it does not die.
This timer should continuously run until it reaches 0. When the tamagotchi eats, the value is again added to the variable, which decreases over time.
class Stopwatch: ObservableObject {
/// String to show in UI
#Published private(set) var message = "Not running"
/// Is the timer running?
#Published private(set) var isRunning = false
/// Time that we're counting from
private var startTime: Date? { didSet { saveStartTime() } }
/// The timer
private var timer: AnyCancellable?
init() {
startTime = fetchStartTime()
if startTime != nil {
start()
}
}
}
extension Stopwatch {
func start() {
timer?.cancel() // cancel timer if any
if startTime == nil {
startTime = Date()
}
message = ""
timer = Timer
.publish(every: 0.1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
guard
let self = self,
let startTime = self.startTime
else { return }
let now = Date()
let elapsed = now.timeIntervalSince(startTime)
guard elapsed < 60 else {
self.stop()
return
}
self.message = String(format: "%0.1f", elapsed)
}
isRunning = true
}
func stop() {
timer?.cancel()
timer = nil
startTime = nil
isRunning = false
message = "Not running"
}
}
private extension Stopwatch {
func saveStartTime() {
if let startTime = startTime {
UserDefaults.standard.set(startTime, forKey: "startTime")
} else {
UserDefaults.standard.removeObject(forKey: "startTime")
}
}
func fetchStartTime() -> Date? {
UserDefaults.standard.object(forKey: "startTime") as? Date
}
}
I'm quite new to this and really enjoying swift, I have managed to work must stuff out but this has me stumped. I want to get just the x value (a double) from my accelerometer data.
The below pulls the data and prints out :x 0.476379 y -0.849365 z -0.041885 # 568028.476360
This is great, but I just want :0.476379 - any ideas?
class ViewController: UIViewController {
#objc func update() {
if let accelerometerData = motionManager.accelerometerData {
print(accelerometerData)
}
}
let motionManager = CMMotionManager()
var timer: Timer!
override func viewDidLoad()
{
super.viewDidLoad()
motionManager.startAccelerometerUpdates()
timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(ViewController.update), userInfo: nil, repeats: true)
}
SwiftUI
let accelTuple = (acceleration.x)
import Foundation
import CoreMotion
class Motion {
var motion = CMMotionManager()
#Published var timer = Timer()
private var motionManager = CMMotionManager()
func startAccelerometer() {
if motion.isAccelerometerAvailable {
self.motion.accelerometerUpdateInterval = 5
motion.startAccelerometerUpdates()
self.timer = Timer(fire: Date(), interval: (10),
repeats: true, block: { (timer) in
if let data = self.motion.accelerometerData {
let acceleration = data.acceleration
self.accelerometerData = ("Accelerometer data : \(data)")
print(self.accelerometerData)
let accelTuple = (acceleration.x, acceleration.y, acceleration.z)
valuesArray.append(accelTuple)
}
})
RunLoop.current.add(timer, forMode: .default)
}
}
func startGyroscope() {
if motion.isGyroAvailable {
self.motion.gyroUpdateInterval = 5
motion.startGyroUpdates()
self.timer = Timer(fire: Date(), interval: (10),
repeats: true, block: { (timer) in
if let data = self.motion.gyroData {
let x = data.rotationRate.x
let y = data.rotationRate.y
let z = data.rotationRate.z
self.gyroscopeData = ("Gyroscope data : \(data)")
print(self.gyroscopeData)
let gyroTuple = (x, y, z)
valuesArray.append(gyroTuple)
}
})
RunLoop.current.add(timer, forMode: .default)
}
}
func startMagnetometer() {
if motion.isMagnetometerAvailable {
self.motion.magnetometerUpdateInterval = 5
motion.startMagnetometerUpdates()
self.timer = Timer(fire: Date(), interval: (10),
repeats: true, block: { (timer) in
if let data = self.motion.magnetometerData {
let acceleration = data.magneticField
self.magnetometerData = ("Magnetometer data : \(data)")
print(self.magnetometerData)
let magneTuple = (acceleration.x, acceleration.y, acceleration.z)
valuesArray.append(magneTuple)
}
})
RunLoop.current.add(timer, forMode: .default)
}
}
}
Working code thanks to Nick:
class ViewController: UIViewController {
#objc func update() {
if let accelerometerData = motionManager.accelerometerData?.acceleration.x {
print(accelerometerData)
}
}
I call the following function in a while loop but the asynchronous code doesn't run even with the dispatch_group being used. Does anyone know what I may be doing incorrectly? *I am trying to essentially get the while loop to wait for the asynchronous code to be executed before continuing.
override func viewDidAppear(animated: Bool) {
if(ended != true) {
if(count2 < 2) {
print("current count is < 2")
} else {
var playRef = ref.child("LiveGames").child("05-25-17").child("RedSox")
asyncCall(playRef, ended: ended, count: count2)
}
print("successful delay")
count2++
//playIsntThere()
}//this is where the else loop ends
count2++
}
func asyncCall(ref:FIRDatabaseReference, ended:Bool, count:Int) {
var count2 = count
let myGroup = dispatch_group_create()
dispatch_group_enter(myGroup)
ref.child(String(count2-2)).observeSingleEventOfType(.Value, withBlock: { (snapshot2) in
var hitterRef = snapshot2.childSnapshotForPath("/Hitter")
var pitcherRef = snapshot2.childSnapshotForPath("/Pitcher")
pitcherEra.text = String(pitcherRef.childSnapshotForPath("/ERA").value!)
})
dispatch_group_leave(myGroup)
dispatch_group_notify(myGroup, dispatch_get_main_queue()) {
print("code completed")
}
print("successful delay")
count2++
}
I am not able to understand why I am getting these errors. someone please help me. Here is the source code
import UIKit
import AVFoundation
// MARK: - PlaySoundsViewController: AVAudioPlayerDelegate
extension PlaySoundsViewController: AVAudioPlayerDelegate {
var audioEngine = AVAudioEngine()
// MARK: Alerts
struct Alerts {
static let DismissAlert = "Dismiss"
static let RecordingDisabledTitle = "Recording disabled"
static let RecordginDisabledMessage = "Youve disabled this app from recording your microphone. Check settings"
static let RecodingFailedTitle = "Recording failed"
static let RecordingFailedMessage = "Something went wrong with the recording"
static let AudioRecordedError = "Audio Recorder Error"
static let AudioSessionError = "Audio Session Error"
static let AudioRecordingError = "Audio Recording Error"
static let AudioFileError = "Audio File Error"
static let AudioEngineError = "Audio Engine Error"
}
// MARK: PlayingState (raw values correspond to sender tags)
enum PlayingState { case playing, notPlaying }
// MARK: Audio Functions
func setupAudio() {
// initialize (recording) audio file
do {
audioFile = try AVAudioFile(forReading: recordedAudioURL as URL)
} catch {
showAlert(Alerts.AudioFileError, message: String(describing: error))
}
}
func playSound(rate: Float? = nil, pitch: Float? = nil, echo: Bool = false, reverb: Bool = false) {
// initialize audio engine components
audioEngine = AVAudioEngine()
// node for playing audio
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attach(audioPlayerNode)
// node for adjusting rate/pitch
let changeRatePitchNode = AVAudioUnitTimePitch()
if let pitch = pitch {
changeRatePitchNode.pitch = pitch
}
if let rate = rate {
changeRatePitchNode.rate = rate
}
audioEngine.attach(changeRatePitchNode)
// node for echo
let echoNode = AVAudioUnitDistortion()
echoNode.loadFactoryPreset(.multiEcho1)
audioEngine.attach(echoNode)
// node for reverb
let reverbNode = AVAudioUnitReverb()
reverbNode.loadFactoryPreset(.cathedral)
reverbNode.wetDryMix = 50
audioEngine.attach(reverbNode)
// connect nodes
if echo == true && reverb == true {
connectAudioNodes(audioPlayerNode, changeRatePitchNode, echoNode, reverbNode, audioEngine.outputNode)
} else if echo == true {
connectAudioNodes(audioPlayerNode, changeRatePitchNode, echoNode, audioEngine.outputNode)
} else if reverb == true {
connectAudioNodes(audioPlayerNode, changeRatePitchNode, reverbNode, audioEngine.outputNode)
} else {
connectAudioNodes(audioPlayerNode, changeRatePitchNode, audioEngine.outputNode)
}
// schedule to play and start the engine!
audioPlayerNode.stop()
audioPlayerNode.scheduleFile(audioFile, at: nil) {
var delayInSeconds: Double = 0
if let lastRenderTime = self.audioPlayerNode.lastRenderTime, let playerTime = self.audioPlayerNode.playerTime(forNodeTime: lastRenderTime) {
if let rate = rate {
delayInSeconds = Double(self.audioFile.length - playerTime.sampleTime) / Double(self.audioFile.processingFormat.sampleRate) / Double(rate)
} else {
delayInSeconds = Double(self.audioFile.length - playerTime.sampleTime) / Double(self.audioFile.processingFormat.sampleRate)
}
}
// schedule a stop timer for when audio finishes playing
self.stopTimer = Timer(timeInterval: delayInSeconds, target: self, selector: #selector(PlaySoundsViewController.stopAudio), userInfo: nil, repeats: false)
RunLoop.main.add(self.stopTimer!, forMode: RunLoopMode.defaultRunLoopMode)
}
do {
try audioEngine.start()
} catch {
showAlert(Alerts.AudioEngineError, message: String(describing: error))
return
}
// play the recording!
audioPlayerNode.play()
}
func stopAudio() {
if let audioPlayerNode = audioPlayerNode {
audioPlayerNode.stop()
}
if let stopTimer = stopTimer {
stopTimer.invalidate()
}
configureUI(.notPlaying)
if let audioEngine = audioEngine {
audioEngine.stop()
audioEngine.reset()
}
}
// MARK: Connect List of Audio Nodes
func connectAudioNodes(_ nodes: AVAudioNode...) {
for x in 0..<nodes.count-1 {
audioEngine.connect(nodes[x], to: nodes[x+1], format: audioFile.processingFormat)
}
}
// MARK: UI Functions
func configureUI(_ playState: PlayingState) {
switch(playState) {
case .playing:
setPlayButtonsEnabled(false)
stopButton.isEnabled = true
case .notPlaying:
setPlayButtonsEnabled(true)
stopButton.isEnabled = false
}
}
func setPlayButtonsEnabled(_ enabled: Bool) {
snailButton.isEnabled = enabled
chipmunkButton.isEnabled = enabled
rabbitButton.isEnabled = enabled
vaderButton.isEnabled = enabled
echoButton.isEnabled = enabled
reverbButton.isEnabled = enabled
}
func showAlert(_ title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: Alerts.DismissAlert, style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
The screenshot of the error is in the link below.
Screenshot!
You can not declare var audioEngine = AVAudioEngine() inside an extension. Declare it inside PlaySoundsViewController class instead.
Extensions are meant to augment behaviours, not fundamentally change a class.
#source: Why can't you add stored properties to extensions?
I have 2 (or more) reusable collectionView cell and each one have to play a different audio. My problem is that when the audio1 finish, audio2 file start in the same cell of the audio2. If I manually play on each cell there's no problem, but if I want to play all audio automatically one after the other, all audio are played in the same cell. How I can start the next audio in the next cell if the cell has not yet been created?
Here how I append to array:
func appendToArray() {
for (_, page) in self.resources.enumerate() {
for (index,resource) in page.enumerate() {
print("Passa di qui") // Qui passa
if resource.fileType() == .Audio {
S3Client.sharedInstance.downloadResource(resourceKey: resource.value, completion: { (success, file) in
// let files = String(file)
self.audioURLs.append(file)
/**
if self.audioURLs.count == self.resources.count {
// print("audioURLs \(self.audioURLs[index])")
MediaAudioPlayer.sharedInstance.queueTrack(self.audioURLs)
}
*/
})
}
}
}
}
This is the cellForItemAtIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
case .Audio:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(MediaAudioCell.kCellIdentifier, forIndexPath: indexPath) as! MediaAudioCell
cell.activityIndicator.startAnimating()
cell.activityIndicator.hidden = false
S3Client.sharedInstance.downloadResource(resourceKey: resource.value, completion: { (success, file) in
if success == true && file != nil {
cell.activityIndicator.stopAnimating()
cell.activityIndicator.hidden = true
cell.audioURL = file!
// Make slider indipendent from cell to another
cell.sliderAudio.tag = indexPath.row
cell.sliderAudio.addTarget(self, action: "sliderChange:", forControlEvents: .ValueChanged)
// print("ArrayURL: \(file)")
// print("CiaoCell : \(self.audioURLs.count)")
// print("Ciaoself.resources.countCell : \(self.resources.count)")
/**
if self.audioURLs.count == self.resources.count {
// print("audioURLs \(self.audioURLs[index])")
let item = self.audioURLs[indexPath.row] print("item: \(item)")
}
if self.audioURLs.count == self.resources.count {
// print("audioURLs \(self.audioURLs[index])")
// MediaAudioPlayer.sharedInstance.queueTrack(self.audioURLs)
}
*/
// Display total audio leinght
let asset = AVURLAsset(URL: file!, options: nil)
let audios = asset.tracksWithMediaType(AVMediaTypeAudio)
if let audios: AVAssetTrack = audios[0] {
let audioDuration:CMTime = audios.timeRange.duration
let seconds:Float64 = CMTimeGetSeconds(audioDuration)
cell.labelAudio.text = cell.stringFromTimeInterval(NSTimeInterval(seconds)) as String
}
}
})
return cell
}
This is part of cell's Class:
override func awakeFromNib() {
super.awakeFromNib()
// Partenza automatica, dopo 2secondi, se Accessibilità su ON
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
if self.defaults.boolForKey("AutomaticStart") == true && self.defaults.boolForKey("goBackPressed") == false {
if let audioURL = self.audioURL {
// Set AVAudioSession for recording and playing at the same time
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
try session.setActive(true)
} catch _ {}
// If audio is playing, do not pass to next if cell is created, but continue to playing.
if MediaAudioPlayer.sharedInstance.player?.playing == true { // Se metto a 'false', ed elimino 'else', non parte in automatico.
} else {
MediaVideoPlayer.sharedInstance.stop()
MediaAudioPlayer.sharedInstance.playPauseAudio(audioURL: audioURL, delegate: self)
}
}
}
}
}
And this is the player class:
class MediaAudioPlayer: NSObject, AVAudioPlayerDelegate {
static let sharedInstance = MediaAudioPlayer()
private var delegate: MediaAudioPlayerDelegate?
var player: AVAudioPlayer?
private var lastURL: NSURL?
private var timer: NSTimer?
internal var sliderTouched: Bool = false
var tracks = Array<NSURL?>()
var currentTrackIndex = 0
override init() {
super.init()
}
// MARK: Setup
func playPauseAudio(audioURL url: NSURL, delegate: MediaAudioPlayerDelegate) {
self.delegate?.playing = true // Set default play button on last delegate
self.delegate = delegate // Save delegate
self.sliderTouched = false
// Setup as new only when this audio has not been already set up
if (self.lastURL == nil) || (url != self.lastURL) {
self.lastURL = url
self.setupAudioSession(category: AVAudioSessionCategoryPlayback)
do { // Setup Player
self.player = try AVAudioPlayer(contentsOfURL: url)
} catch _ {}
self.player?.delegate = self
self.player?.prepareToPlay()
timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MediaAudioPlayer.update), userInfo: nil, repeats: true)
}
// Play - Pause
if self.player?.playing == true {
self.player?.pause()
self.delegate?.playing = true
} else {
self.player?.play()
self.delegate?.playing = false
}
}
// Transform second to minute
func stringFromTimeInterval(interval: NSTimeInterval) -> NSString {
let ti = NSInteger(interval)
let seconds = ti % 60
let minutes = (ti / 60) % 60
return NSString(format: "%0.2d:%0.2d", minutes, seconds)
}
// MARK: Audio Session
private func setupAudioSession(category category: String) {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(category)
try session.setActive(true)
} catch _ {}
}
// MARK: Stop
func stop() {
self.player?.stop()
self.player = nil // Deinit player
self.delegate?.playing = true
self.delegate = nil // Deinit delegate
self.timer?.invalidate(); self.timer = nil
self.lastURL = nil
}
// MARK: Playing
internal func playing() -> Bool {
if player != nil {
return player?.rate == 1.0 ? true : false
}
return false
}
// MARK: Seek
func seekToPosition(position position: Float) {
if let duration = self.player?.duration {
player?.currentTime = Double(position) * duration
self.delegate?.currentTimeAudio = stringFromTimeInterval((player?.currentTime)!) as String
}
}
func update() {
if sliderTouched == false {
if let currentTime = self.player?.currentTime, duration = player?.duration {
let time = Float(currentTime) / Float(duration)
self.delegate?.sliderPosition = time
self.delegate?.currentTimeAudio = stringFromTimeInterval((player?.currentTime)!) as String
}
}
}
// MARK: Delegate
var counter = 0
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
print("Called")
self.lastURL = nil
self.delegate?.playing = true
/**
if flag == true {
nextSong(true)
}*/
/**
if ((counter + 1) == tracks.count) {
counter = 0
self.delegate?.playing = false
nextSong(false)
} else {
self.delegate?.playing = true
nextSong(true)
}
*/
}
}
Thank you!!