SwiftAudioPlayer - Swift-based audio player with AVAudioEngine as its base

Overview

SwiftAudioPlayer

Version License Platform

Swift-based audio player with AVAudioEngine as its base. Allows for: streaming online audio, playing local file, changing audio speed (3.5X, 4X, 32X), pitch, and real-time audio manipulation using custom audio enhancements.

This player was built for podcasting. We originally used AVPlayer for playing audio but we wanted to manipulate audio that was being streamed. We set up AVAudioEngine at first just to play a file saved on the phone and it worked great, but AVAudioEngine on its own doesn't support streaming audio as easily as AVPlayer.

Thus, using AudioToolbox, we are able to stream audio and convert the downloaded data into usable data for the AVAudioEngine to play. For an overview of our solution check out our blog post.

Basic Features

  1. Realtime audio manipulation that includes going up to 10x speed, using equalizers and other manipulations
  2. Stream online audio using AVAudioEngine
  3. Stream radio
  4. Play locally saved audio with the same API
  5. Download audio
  6. Queue up downloaded and streamed audio for autoplay
  7. Uses only 1-2% CPU for optimal performance for the rest of your app
  8. You're able to install taps and any other AVAudioEngine features to do cool things like skipping silences

Special Features

These are community supported audio manipulation features using this audio engine. You can implement your own version of these features and you can look at SAPlayerFeatures to learn how they were implemented using the library.

  1. Skip silences in audio
  2. Sleep timer to stop playing audio after a delay

Requirements

iOS 10.0 and higher.

Getting Started

Running the Example Project

  1. Clone repo
  2. CD to the Example folder where the Example app lives
  3. Run pod install in terminal
  4. Build and run

Installation

SwiftAudioPlayer is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'SwiftAudioPlayer'

Usage

Import the player at the top:

import SwiftAudioPlayer

Important: For app in background downloading please refer to note.

To play remote audio:

let url = URL(string: "https://randomwebsite.com/audio.mp3")!
SAPlayer.shared.startRemoteAudio(withRemoteUrl: url)
SAPlayer.shared.play()

To set the display information for the lockscreen:

let info = SALockScreenInfo(title: "Random audio", artist: "Foo", artwork: UIImage(), releaseDate: 123456789)
SAPlayer.shared.mediaInfo = info

To receive streaming progress (for buffer progress %):

@IBOutlet weak var bufferProgress: UIProgressView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    _ = SAPlayer.Updates.StreamingBuffer.subscribe{ [weak self] (url, buffer) in
        guard let self = self else { return }
        guard url == self.selectedAudioUrl else { return }

        let progress = Float((buffer.totalDurationBuffered + buffer.startingBufferTimePositon) / self.duration)

        self.bufferProgress.progress = progress

        self.isPlayable = buffer.isReadyForPlaying
    }
}

Look at the Updates section to see usage details and other updates to follow.

For realtime audio manipulations, AVAudioUnit nodes are used. For example to adjust the reverb through a slider in the UI:

@IBOutlet weak var reverbSlider: UISlider!

override func viewDidLoad() {
    super.viewDidLoad()

    let node = AVAudioUnitReverb()
    SAPlayer.shared.audioModifiers.append(node)
    node.wetDryMix = 300
}

@IBAction func reverbSliderChanged(_ sender: Any) {
    if let node = SAPlayer.shared.audioModifiers[1] as? AVAudioUnitReverb {
            node.wetDryMix = reverbSlider.value
        }
}

For a more detailed explanation on usage, look at the Realtime Audio Manipulations section.

For more details and specifics look at the API documentation below.

Contact

Issues

Submit any issues or requests on the Github repo.

Any questions?

Feel free to reach out to either of us:

tanhakabir, [email protected] JonMercer, [email protected]

License

SwiftAudioPlayer is available under the MIT license. See the LICENSE file for more info.


API in detail

SAPlayer

Access the player and all of its fields and functions through SAPlayer.shared.

Supported file types

Known supported file types are .mp3 and .wav.

Playing Audio (Basic Commands)

To set up player with audio to play, use either:

  • startSavedAudio(withSavedUrl url: URL, mediaInfo: SALockScreenInfo?) to play audio that is saved on the device.
  • startRemoteAudio(withRemoteUrl url: URL, bitrate: SAPlayerBitrate, mediaInfo: SALockScreenInfo?) to play audio streamed from a remote location.

Both of these expect a URL of the location of the audio and an optional media information to display on the lockscreen. For streamed audio you can optionally set the bitrate to be .high or .low. High is more performant but won't work well for radio streams; for radio streams you should use low. The default bitrate if you don't set it is .high.

For streaming remote audio, subscribe to SAPlayer.Updates.StreamingBuffer for updates on streaming progress.

Basic controls available:

play()
pause()
togglePlayAndPause()
seekTo(seconds: Double)
skipForward()
skipBackwards()

Queuing Audio for Autoplay

You can queue either remote or locally saved audio to be played automatically next.

To queue:

SAPlayer.shared.queueSavedAudio(withSavedUrl: C://random_folder/audio.mp3) // or
SAPlayer.shared.queueRemoteAudio(withRemoteUrl: https://randomwebsite.com/audio.mp3)

Important

The engine can handle audio manipulations like speed, pitch, effects, etc. To do this, nodes for effects must be finalized before initialize is called. Look at audio manipulation documentation for more information.

Lockscreen Media Player

Update and set what displays on the lockscreen's media player when the player is active.

skipForwardSeconds and skipBackwardSeconds for the intervals to skip forward and back with.

mediaInfo for the audio's information to display on the lockscreen. Is of type SALockScreenInfo which contains:

title: String
artist: String
artwork: UIImage?
releaseDate: UTC // Int

playbackRateOfAudioChanged(rate: Float) is used to update the lockscreen media player that the playback rate has changed.

SAPlayer.Downloader

Use functionaity from Downloader to save audio files from remote locations for future offline playback.

Audio files are saved under custom naming scheme on device and are recoverable with original remote URL for file.

Important step for background downloads

To ensure that your app will keep downloading audio in the background be sure to add the following to AppDelegate.swift:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    SAPlayer.Downloader.setBackgroundCompletionHandler(completionHandler)
}

Downloading

All downloads will be paused when audio is streamed from a URL. They will automatically resume when streaming is done.

Use the following to start downloading audio in the background:

func downloadAudio(withRemoteUrl url: URL, completion: @escaping (_ savedUrl: URL) -> ())

It will call the completion handler you pass after successful download with the location of the downloaded file on the device.

Subscribe to SAPlayer.Updates.AudioDownloading for downloading progress updates.

And use the following to stop any active or prevent future downloads of the corresponding remote URL:

func cancelDownload(withRemoteUrl url: URL)

By default downloading will be allowed on cellular data. If you would like to turn this off set:

SAPlayer.Downloader.allowUsingCellularData = false

You can also retrieve what preference you have set for cellular downloads through allowUsingCellularData.

Manage Downloaded

Use the following to manage downloaded audio files.

Checks if downloaded already:

func isDownloaded(withRemoteUrl url: URL) -> Bool

Get URL of audio file saved on device corresponding to remote location:

func getSavedUrl(forRemoteUrl url: URL) -> URL?

Delete downloaded audio if it exists:

func deleteDownloaded(withSavedUrl url: URL)

NOTE: You're in charge or clearing downloads when your don't need them anymore

SAPlayer.Updates

Receive updates for changing values from the player, such as the duration, elapsed time of playing audio, download progress, and etc.

All subscription functions for updates take the form of:

func subscribe(_ closure: @escaping (_ url: URL, _ payload:  ) -> ()) -> UInt
  • closure: The closure that will receive the updates. It's recommended to have a weak reference to a class that uses these functions.
  • url: The corresponding remote URL for the update. In the case there might be multiple files observed, such as downloading many files at once or switching over from playing one audio to another and the updates corresponding to the previous aren't silenced on switch-over.
  • payload: The updated value.
  • Returns: the id for the subscription in the case you would like to unsubscribe to updates for the closure.

Similarily unsubscribe takes the form of:

func unsubscribe(_ id: UInt)
  • id: The closure with this id will stop receiving updates.

ElapsedTime

Payload = Double

Changes in the timestamp/elapsed time of the current initialized audio. Aka, where the scrubber's pointer of the audio should be at.

Subscribe to this to update views on changes in position of which part of audio is being played.

Duration

Payload = Double

Changes in the duration of the current initialized audio. Especially helpful for audio that is being streamed and can change with more data. The engine makes a best effort guess as to the duration of the audio. The guess gets better with more bytes streamed from the web.

PlayingStatus

Payload = SAPlayingStatus

Changes in the playing status of the player. Can be one of the following 4: playing, paused, buffering, ended (audio ended).

StreamingBuffer

Payload = SAAudioAvailabilityRange

Changes in the progress of downloading audio for streaming. Information about range of audio available and if the audio is playable. Look at SAAudioAvailabilityRange for more information.

For progress of downloading audio that saves to the phone for playback later, look at AudioDownloading instead.

AudioDownloading

Payload = Double

Changes in the progress of downloading audio in the background. This does not correspond to progress in streaming downloads, look at StreamingBuffer for streaming progress.

Audio Effects

Realtime Audio Manipulation

All audio effects on the player is done through AVAudioUnit nodes. These include adding reverb, changing pitch and playback rate, and adding distortion. Full list of effects available here.

The effects intended to use are stored in audioModifiers as a list of nodes. These nodes are in the order that the engine will attach them to one another.

Note: By default SAPlayer starts off with one node, an AVAudioUnitTimePitch node, that is set to change the rate of audio without changing the pitch of the audio (intended for changing the rate of spoken word).

Important

All the nodes intended to be used on the playing audio must be finalized before calling initializeSavedAudio(...) or initializeRemoteAudio(...). Any changes to list of nodes after initialize is called for a given audio file will not be reflected in playback.

Once all nodes are added to audioModifiers and the player has been initialized, any manipulations done with the nodes are performed in realtime. The example app shows manipulating the playback rate in realtime:

let speed = rateSlider.value
if let node = SAPlayer.shared.audioModifiers[0] as? AVAudioUnitTimePitch {
    node.rate = speed
    SAPlayer.shared.playbackRateOfAudioChanged(rate: speed)
}

Note: if the rate of the audio is changed, playbackRateOfAudioChanged should also be called to update the lockscreen's media player.

Comments
  • Radio stream support

    Radio stream support

    When I play a radio stream with startRemoteAudio, it's really buggy. A lot of times it will pause shortly after, or increase the playback rate automatically, or not even play at all. Does the player expect a stream with a known length or something?

    opened by dylancom 16
  • bug: Lockscreen info not displayed anymore

    bug: Lockscreen info not displayed anymore

    Since I recently upgraded to the latest pod of this project, the lock screen doesn't show info anymore (artist, title & artwork). I also tested the Example project to make sure it's not related to my code and also there I don't see any lock screen info.

    I found that self.mediaInfo is nil at: https://github.com/tanhakabir/SwiftAudioPlayer/blob/master/Source/SAPlayerPresenter.swift#L123

    opened by dylancom 10
  • Application freezes under undetermined conditions

    Application freezes under undetermined conditions

    Actually, it doesnt freeze, becuase I use Flutter, which has it's own rendering threads, but it stops receiving any touch events. Seems to be like the seek function causes that. This is what I see in the debugger when I click the debugger pause button at any time when application is frozen.

    UPD: it almost 100% happens when I seek to the very end of file, and also sometimes if I try to seek fast.

    image

    opened by nt4f04uNd 9
  • Handle error if the user did download the wrong link

    Handle error if the user did download the wrong link

    it will be great if support handles errors like:

      SAPlayer.Downloader.downloadAudio(withRemoteUrl: urlAudio, completion: { [weak self] (url, error) in
        guard let self = self else { return }
        if let error = error {
          print("can't download audio")
        }
      })
    
    opened by EssamSoft 7
  • Icy metadata and custom headers

    Icy metadata and custom headers

    Hi, I just discovered your library and I was wondering if it implements icy-metadata (timedMetadata in AVPlayer) and also custom headers (like using a custom user-agent). Thanks!

    opened by nosenergies 7
  • #77: Add in pause after specific interval,

    #77: Add in pause after specific interval, "skip" silences

    PR adds a crude implementation on skipping silences. It basically checks when the average power for the currently playing buffer drops below an arbitrary value, and then increases the rate. Once the power returns above the value, the rate is reduced back to 1.0.

    Pausing after a time just runs a timer for that period and then calls pause. Perhaps it should also observe the playing status and remove itself if the audio file ends prior to the timer completing?

    opened by jw1540 7
  • Bug: play / pause work incorrect by seeking streamed audio, resulting in blank playback

    Bug: play / pause work incorrect by seeking streamed audio, resulting in blank playback

    When the audio seeking on the lock screen is used and the track is changed to different positions, than blank empty audio is played and the play/pause button cannot be triggered to pause and is always playing

    moreover when enabling debug, i always get a bunch of

    [DEBUG] AudioConverterErrors.swift:errorDescription:72:: Not enough data for read-conversion operation

    no matter the source or the stream

    opened by peterpaulis 7
  • required condition is false: nil == owningEngine || GetEngine() == owningEngine

    required condition is false: nil == owningEngine || GetEngine() == owningEngine

    Hello. I use MPMediaPickerController to play files. It works fine with first file, but if I add the second file I get crash with error:

    required condition is false: nil == owningEngine || GetEngine() == owningEngine

    This is my code for MPMediaPickerController:

    func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
    
            dismiss(animated: true, completion: nil)
            let item: MPMediaItem = mediaItemCollection.items[0]
            let pathURL = item.value(forProperty: MPMediaItemPropertyAssetURL) as? URL
            SAPlayer.shared.startSavedAudio(withSavedUrl: pathURL!)
            SAPlayer.shared.play()
        }
    
    
    opened by ucelme 6
  • Crash on iOS < 14 while trying to stream any remote media

    Crash on iOS < 14 while trying to stream any remote media

    Just run the example on a simulator with iOS version < 14 and you will get this crash

    using xcode 12.4~5

    Screenshot 2021-04-28 at 19 39 35
    2021-04-28 19:38:05.991557+0100 SwiftAudioPlayer_Example[70293:2041877] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x60000295ed40> F8BB1C28-BAE8-11D6-9C31-00039315CD46
    2021-04-28 19:38:06.768135+0100 SwiftAudioPlayer_Example[70293:2042003]  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
    2021-04-28 19:38:06.768600+0100 SwiftAudioPlayer_Example[70293:2042003]  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
    2021-04-28 19:38:06.781695+0100 SwiftAudioPlayer_Example[70293:2042003] [aqme] AQME.h:254:IOProcFailure: AQDefaultDevice (1): output stream 0: null buffer
    2021-04-28 19:38:06.781959+0100 SwiftAudioPlayer_Example[70293:2042003] [aqme] AQMEIO_HAL.cpp:1774:IOProc: EXCEPTION thrown (-50): error != 0
    2021-04-28 19:38:21.042975+0100 SwiftAudioPlayer_Example[70293:2041876] [aqme] AQMEIO.cpp:179:AwaitIOCycle: timed out after 15.000s (0 1); suspension count=0 (IOSuspensions: )
    2021-04-28 19:38:21.043630+0100 SwiftAudioPlayer_Example[70293:2041876] CA_UISoundClient.cpp:241:StartPlaying_block_invoke: CA_UISoundClientBase::StartPlaying: AddRunningClient failed (status = -66681).
    2021-04-28 19:38:42.653143+0100 SwiftAudioPlayer_Example[70293:2042920]  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
    2021-04-28 19:38:42.653351+0100 SwiftAudioPlayer_Example[70293:2042920]  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
    2021-04-28 19:38:42.665862+0100 SwiftAudioPlayer_Example[70293:2042920] [aqme] AQME.h:254:IOProcFailure: AQDefaultDevice (1): output stream 0: null buffer
    2021-04-28 19:38:42.666545+0100 SwiftAudioPlayer_Example[70293:2042920] [aqme] AQMEIO_HAL.cpp:1774:IOProc: EXCEPTION thrown (-50): error != 0
    2021-04-28 19:38:50.928011+0100 SwiftAudioPlayer_Example[70293:2041874] Start: Mach message timeout. Apparently deadlocked. Aborting now.
    CoreSimulator 732.18.6 - Device: iPad Air (3rd generation) (04DF0CEA-C177-4C33-B8B2-D4987E3B0A4C) - Runtime: iOS 13.7 (17H22) - DeviceType: iPad Air (3rd generation)
    
    opened by cheemau 5
  • Library Stopped working after upgrading to Xcode 12

    Library Stopped working after upgrading to Xcode 12

    Please can you advise on this issue after upgrading to xcode 12 IOS 14 here is the error log & the code that has the problem in AudioParser.swift

     init(withRemoteUrl url: AudioURL, parsedFileAudioFormatCallback: @escaping(AVAudioFormat) -> ()) throws {
            self.url = url
            self.parsedFileAudioFormatCallback = parsedFileAudioFormatCallback
            self.throttler = AudioThrottler(withRemoteUrl: url, withDelegate: self)
            
            let context = unsafeBitCast(self, to: UnsafeMutableRawPointer.self)
            //Open the stream and when we call parse data is fed into this stream
            guard AudioFileStreamOpen(context, ParserPropertyListener, **ParserPacketListener**, kAudioFileMP3Type, &streamID) == noErr else {
                throw ParserError.couldNotOpenStream
            }
        }
    

    Cannot convert value of type '(UnsafeMutableRawPointer, UInt32, UInt32, UnsafeRawPointer, UnsafeMutablePointer) -> ()' to expected argument type 'AudioFileStream_PacketsProc' (aka '@convention(c) (UnsafeMutableRawPointer, UInt32, UInt32, UnsafeRawPointer, Optional<UnsafeMutablePointer>) -> ()')

    opened by bahaahany-eg 5
  • Streaming/Subsonic server issue

    Streaming/Subsonic server issue

    Trying to get this library to work with a subsonic server, I see the server transcoding and serving the audio, but the player only ever gets into the buffering state, no playback actuall occurs.

    Any ideas?

    opened by fizzyade 5
  • handleSkipBackward going back incorrect number of seconds

    handleSkipBackward going back incorrect number of seconds

    I've configured both skipForwardSeconds and skipBackwardSeconds like this:

    player.skipForwardSeconds = 30
    player.skipBackwardSeconds = 15
    

    but I've noticed that handleSkipBackward goes back 30 seconds, not 15.

    opened by pietrorea 1
  • AVAudioPCMBuffer  func pullBuffer() throws -> AVAudioPCMBuffer {} :  118

    AVAudioPCMBuffer func pullBuffer() throws -> AVAudioPCMBuffer {} : 118

    The crash is here guard let converter = converter else { Log.debug("reader_error trying to read before converter has been created") throw ConverterError.cannotCreatePCMBufferWithoutConverter }

    opened by Sethi1998 0
  • feat(SAPlayer) avoid shared instance

    feat(SAPlayer) avoid shared instance

    This is addressing the following:

    • #54
    • #166

    Basically I've removed the shared instance and made the SAPlayer public. This allows whoever uses the library to play simultaneously more than one audio file. The caveat is that the AVAudioEngine must be created outside of the library.

    let engine = AVAudioEngine()
    let player1 = SAPlayer(engine: engine)
    let player2 = SAPlayer(engine: engine)
    

    I've played around with the demo, and everything seems to keep working as before. I'm sorry for the big diff, I launched a swiftformat inside the project.

    Only question, I commented the pause on the numberOfBuffersScheduledInTotal#didSet

    private var numberOfBuffersScheduledInTotal = 0 {
            didSet {
                Log.debug("number of buffers scheduled in total: \(numberOfBuffersScheduledInTotal)")
                if numberOfBuffersScheduledInTotal == 0 {
                    if playingStatus == .playing { wasPlaying = true }
                    pause()
                    // Pausing here triggers an odd state where, while downloading the audio the player will not resume playing when the first buffer is ready
    //                pause()
                    //                delegate?.didError()
                    // TODO: we should not have an error here. We should instead have the throttler
                    // propegate when it doesn't enough buffers while they were playing
                    // TODO: "Make this a legitimate warning to user about needing more data from stream"
                }
                
                if numberOfBuffersScheduledInTotal > MIN_BUFFERS_TO_BE_PLAYABLE && wasPlaying {
    
                if numberOfBuffersScheduledInTotal > MIN_BUFFERS_TO_BE_PLAYABLE, wasPlaying {
                    wasPlaying = false
                    play()
                }
            }
        }
    

    Nothing seems to change. What was that pause() guarding?

    opened by kuamanet 0
  • ‼️ Crash on iOS 16 for 100% users – signal SIGABRT

    ‼️ Crash on iOS 16 for 100% users – signal SIGABRT

    #11	0x000000010066a680 in AudioParser.determineIfMoreDataNeedsToBeParsed(index:) at AudioParser.swift:218
    
    
    stella(637,0x1701eb000) malloc: Heap corruption detected, free list is damaged at 0x281eb6080
    *** Incorrect guard value: 0
    stella(637,0x1701eb000) malloc: *** set a breakpoint in malloc_error_break to debug
    stella(637,0x1701eb000) malloc: Heap corruption detected, free list is damaged at 0x281eb6080
    *** Incorrect guard value: 0
    (lldb) 
    
    opened by snowtema 20
Releases(5.0.0)
AudioKit Sample Player (ROM Player) - EXS24, Sound Font, Wave Player

AudioKit ROM / Sample Player Welcome to the official AudioKit example of a sample-based music instrument written in Swift. It can be modified to play

AudioKit 500 Dec 27, 2022
The Amazing Audio Engine is a sophisticated framework for iOS audio applications, built so you don't have to.

Important Notice: The Amazing Audio Engine has been retired. See the announcement here The Amazing Audio Engine The Amazing Audio Engine is a sophisti

null 523 Nov 12, 2022
AudiosPlugin is a Godot iOS Audio Plugin that resolves the audio recording issue in iOS for Godot Engine.

This plugin solves the Godot game engine audio recording and playback issue in iOS devices. Please open the Audios Plugin XCode Project and compile the project. You can also use the libaudios_plugin.a binary in your project.

null 3 Dec 22, 2022
Multiple Audio Player With Swift

MultipleAudioPlayer I needed to play sequential audio files in a number of places so I made a package. Usage There are 2 inits, one takes filenames fr

chris cieslak 1 Apr 14, 2022
Music Player for iOS which looks & feels like classic player

Prodigal Music Player APP looks and feels like a classic device. Bring back the good old player to life. Screenshots Home Page Album Gallery Home Page

bob.sun 40 Nov 11, 2022
I'm trying to make Flutter based Audio Unit Extensions possible.

Flutter AUv3 Audio Unit Error Demo Motivation We are the developers of Audanika, a professional MIDI Controller app written in Flutter. Many of our us

Gabriel Gatzsche 0 Jan 5, 2022
🅿️ PandoraPlayer is a lightweight music player for iOS, based on AudioKit and completely written in Swift.

Made by Applikey Solutions Find this project on Dribbble Table of Contents Purpose Features Supported OS & SDK Versions Installation Usage Demo Releas

Applikey Solutions 1.1k Dec 26, 2022
Beethoven is an audio processing Swift library

Beethoven is an audio processing Swift library that provides an easy-to-use interface to solve an age-old problem of pitch detection of musical signals.

Vadym Markov 735 Dec 24, 2022
Swift audio synthesis, processing, & analysis platform for iOS, macOS and tvOS

AudioKit AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS (including Catalyst), and tvOS. Installation To add AudioKit

AudioKit 8.7k Sep 30, 2021
Voice Memos is an audio recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Swift.

VoiceMemos Voice Memos is a voice recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Sw

Zhouqi Mo 322 Aug 4, 2022
Functional DSP / Audio Framework for Swift

Lullaby Lullaby is an audio synthesis framework for Swift that supports both macOS and Linux! It was inspired by other audio environments like FAUST,

Jae 16 Nov 5, 2022
KeyAudioManager - A swift package to make it a lot easier to play audio in your app

KeyAudioManager A swift package to make it a lot easier to play audio in your ap

Pedro Esli 3 Apr 28, 2022
AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS, and tvOS.

AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS (including Catalyst), and tvOS. Installation To add AudioKit

AudioKit 9.5k Dec 31, 2022
AudioPlayer is syntax and feature sugar over AVPlayer. It plays your audio files (local & remote).

AudioPlayer AudioPlayer is a wrapper around AVPlayer. It also offers cool features such as: Quality control based on number of interruption (buffering

Kevin Delannoy 676 Dec 25, 2022
AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.

AudioPlayer AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.

Tom Baranes 260 Nov 27, 2022
FDWaveformView is an easy way to display an audio waveform in your app

FDWaveformView is an easy way to display an audio waveform in your app. It is a nice visualization to show a playing audio file or to select a position in a file.

William Entriken 1.1k Dec 21, 2022
YiVideoEditor is a library for rotating, cropping, adding layers (watermark) and as well as adding audio (music) to the videos.

YiVideoEditor YiVideoEditor is a library for rotating, cropping, adding layers (watermark) and as well as adding audio (music) to the videos. YiVideoE

coderyi 97 Dec 14, 2022
App for adding and listening audio files

SomeSa SomeSa (самса) – приложение, позволяющее загружать и воспроизводить произвольные аудиофайлы. Протестировано на форматах файлов .wav и .mp3, раз

Yegor Dobrodeyev 0 Nov 7, 2021
Painless high-performance audio on iOS and Mac OS X

An analgesic for high-performance audio on iOS and OSX. Really fast audio in iOS and Mac OS X using Audio Units is hard, and will leave you scarred an

Alex Wiltschko 2.2k Nov 23, 2022