Remove per-call overhead from API access and text conversion
Two hot-path optimizations for the device's Cortex-M7 (and debug simulator builds): - The ten sub-API pointers are cached once in Playdate.initialize(with:); wrapper accessors now return UnsafePointer and call sites read a single field through it, instead of unwrapping the optional API struct and copying a whole sub-API struct of function pointers on every call. Nested sub-APIs (sound classes, effects, video, tilemap, http/tcp) derive from the cached pointers with one field load. - String -> C conversions (withPlaydateCString, and a new withPlaydateUTF8 used by the text drawing/measuring APIs) use withUnsafeTemporaryAllocation instead of building a ContiguousArray, so logging and drawText in the update loop no longer heap-allocate per call. Verified within the Embedded Swift subset by the device cross-compile. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,49 +9,49 @@ internal import CPlaydate
|
|||||||
public enum Display {}
|
public enum Display {}
|
||||||
|
|
||||||
extension Display {
|
extension Display {
|
||||||
private static var api: playdate_display { Playdate.api.display.pointee }
|
private static var api: UnsafePointer<playdate_display> { Playdate.displayAPI }
|
||||||
|
|
||||||
/// The display width in pixels, taking the current scale into account.
|
/// The display width in pixels, taking the current scale into account.
|
||||||
public static var width: Int { Int(api.getWidth.unsafelyUnwrapped()) }
|
public static var width: Int { Int(api.pointee.getWidth.unsafelyUnwrapped()) }
|
||||||
|
|
||||||
/// The display height in pixels, taking the current scale into account.
|
/// The display height in pixels, taking the current scale into account.
|
||||||
public static var height: Int { Int(api.getHeight.unsafelyUnwrapped()) }
|
public static var height: Int { Int(api.pointee.getHeight.unsafelyUnwrapped()) }
|
||||||
|
|
||||||
/// Sets the nominal refresh rate in frames per second. Pass 0 to update
|
/// Sets the nominal refresh rate in frames per second. Pass 0 to update
|
||||||
/// as fast as possible (the update callback drives the pace).
|
/// as fast as possible (the update callback drives the pace).
|
||||||
public static func setRefreshRate(_ rate: Float) {
|
public static func setRefreshRate(_ rate: Float) {
|
||||||
api.setRefreshRate.unsafelyUnwrapped(rate)
|
api.pointee.setRefreshRate.unsafelyUnwrapped(rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current nominal refresh rate.
|
/// The current nominal refresh rate.
|
||||||
public static var refreshRate: Float { api.getRefreshRate.unsafelyUnwrapped() }
|
public static var refreshRate: Float { api.pointee.getRefreshRate.unsafelyUnwrapped() }
|
||||||
|
|
||||||
/// The measured average frames per second.
|
/// The measured average frames per second.
|
||||||
public static var fps: Float { api.getFPS.unsafelyUnwrapped() }
|
public static var fps: Float { api.pointee.getFPS.unsafelyUnwrapped() }
|
||||||
|
|
||||||
/// Draws the frame white-on-black when `true`.
|
/// Draws the frame white-on-black when `true`.
|
||||||
public static func setInverted(_ inverted: Bool) {
|
public static func setInverted(_ inverted: Bool) {
|
||||||
api.setInverted.unsafelyUnwrapped(inverted ? 1 : 0)
|
api.pointee.setInverted.unsafelyUnwrapped(inverted ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the display scale factor: 1, 2, 4, or 8.
|
/// Sets the display scale factor: 1, 2, 4, or 8.
|
||||||
public static func setScale(_ scale: UInt32) {
|
public static func setScale(_ scale: UInt32) {
|
||||||
api.setScale.unsafelyUnwrapped(scale)
|
api.pointee.setScale.unsafelyUnwrapped(scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a mosaic effect. Valid values for each axis are 0...3.
|
/// Adds a mosaic effect. Valid values for each axis are 0...3.
|
||||||
public static func setMosaic(x: UInt32, y: UInt32) {
|
public static func setMosaic(x: UInt32, y: UInt32) {
|
||||||
api.setMosaic.unsafelyUnwrapped(x, y)
|
api.pointee.setMosaic.unsafelyUnwrapped(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flips the display on the given axes.
|
/// Flips the display on the given axes.
|
||||||
public static func setFlipped(x: Bool, y: Bool) {
|
public static func setFlipped(x: Bool, y: Bool) {
|
||||||
api.setFlipped.unsafelyUnwrapped(x ? 1 : 0, y ? 1 : 0)
|
api.pointee.setFlipped.unsafelyUnwrapped(x ? 1 : 0, y ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Offsets the display by the given amount. Areas outside the frame
|
/// Offsets the display by the given amount. Areas outside the frame
|
||||||
/// buffer draw black.
|
/// buffer draw black.
|
||||||
public static func setOffset(x: Int, y: Int) {
|
public static func setOffset(x: Int, y: Int) {
|
||||||
api.setOffset.unsafelyUnwrapped(Int32(x), Int32(y))
|
api.pointee.setOffset.unsafelyUnwrapped(Int32(x), Int32(y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-17
@@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var fileAPI: playdate_file { Playdate.api.file.pointee }
|
private var fileAPI: UnsafePointer<playdate_file> { Playdate.fileAPI }
|
||||||
|
|
||||||
/// The most recent file system error as a thrown error.
|
/// The most recent file system error as a thrown error.
|
||||||
private func lastFileError() -> PlaydateError {
|
private func lastFileError() -> PlaydateError {
|
||||||
PlaydateError(cString: fileAPI.geterr.unsafelyUnwrapped())
|
PlaydateError(cString: fileAPI.pointee.geterr.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The file API: access to the game's Data directory and pdx contents.
|
/// The file API: access to the game's Data directory and pdx contents.
|
||||||
@@ -62,7 +62,7 @@ extension File {
|
|||||||
var callback = each
|
var callback = each
|
||||||
return path.withPlaydateCString { cPath in
|
return path.withPlaydateCString { cPath in
|
||||||
withUnsafeMutablePointer(to: &callback) { callbackPointer in
|
withUnsafeMutablePointer(to: &callback) { callbackPointer in
|
||||||
fileAPI.listfiles.unsafelyUnwrapped(cPath, { cName, userdata in
|
fileAPI.pointee.listfiles.unsafelyUnwrapped(cPath, { cName, userdata in
|
||||||
guard let cName, let userdata else { return }
|
guard let cName, let userdata else { return }
|
||||||
let each = userdata.assumingMemoryBound(to: ((String) -> Void).self).pointee
|
let each = userdata.assumingMemoryBound(to: ((String) -> Void).self).pointee
|
||||||
each(String(playdateCString: cName))
|
each(String(playdateCString: cName))
|
||||||
@@ -76,7 +76,7 @@ extension File {
|
|||||||
/// Information about the file or directory at `path`.
|
/// Information about the file or directory at `path`.
|
||||||
public static func stat(_ path: String) throws(PlaydateError) -> Stat {
|
public static func stat(_ path: String) throws(PlaydateError) -> Stat {
|
||||||
var stat = FileStat()
|
var stat = FileStat()
|
||||||
let result = path.withPlaydateCString { fileAPI.stat.unsafelyUnwrapped($0, &stat) }
|
let result = path.withPlaydateCString { fileAPI.pointee.stat.unsafelyUnwrapped($0, &stat) }
|
||||||
if result != 0 { throw lastFileError() }
|
if result != 0 { throw lastFileError() }
|
||||||
return Stat(
|
return Stat(
|
||||||
isDirectory: stat.isdir != 0,
|
isDirectory: stat.isdir != 0,
|
||||||
@@ -88,7 +88,7 @@ extension File {
|
|||||||
|
|
||||||
/// Creates a directory (and intermediate directories) in the Data directory.
|
/// Creates a directory (and intermediate directories) in the Data directory.
|
||||||
public static func mkdir(_ path: String) throws(PlaydateError) {
|
public static func mkdir(_ path: String) throws(PlaydateError) {
|
||||||
let result = path.withPlaydateCString { fileAPI.mkdir.unsafelyUnwrapped($0) }
|
let result = path.withPlaydateCString { fileAPI.pointee.mkdir.unsafelyUnwrapped($0) }
|
||||||
if result != 0 { throw lastFileError() }
|
if result != 0 { throw lastFileError() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ extension File {
|
|||||||
/// `recursive` to be deleted with their contents.
|
/// `recursive` to be deleted with their contents.
|
||||||
public static func unlink(_ path: String, recursive: Bool = false) throws(PlaydateError) {
|
public static func unlink(_ path: String, recursive: Bool = false) throws(PlaydateError) {
|
||||||
let result = path.withPlaydateCString {
|
let result = path.withPlaydateCString {
|
||||||
fileAPI.unlink.unsafelyUnwrapped($0, recursive ? 1 : 0)
|
fileAPI.pointee.unlink.unsafelyUnwrapped($0, recursive ? 1 : 0)
|
||||||
}
|
}
|
||||||
if result != 0 { throw lastFileError() }
|
if result != 0 { throw lastFileError() }
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ extension File {
|
|||||||
public static func rename(from: String, to: String) throws(PlaydateError) {
|
public static func rename(from: String, to: String) throws(PlaydateError) {
|
||||||
let result = from.withPlaydateCString { cFrom in
|
let result = from.withPlaydateCString { cFrom in
|
||||||
to.withPlaydateCString { cTo in
|
to.withPlaydateCString { cTo in
|
||||||
fileAPI.rename.unsafelyUnwrapped(cFrom, cTo)
|
fileAPI.pointee.rename.unsafelyUnwrapped(cFrom, cTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if result != 0 { throw lastFileError() }
|
if result != 0 { throw lastFileError() }
|
||||||
@@ -123,7 +123,7 @@ extension File {
|
|||||||
/// Opens the file at `path`.
|
/// Opens the file at `path`.
|
||||||
public init(path: String, mode: Options) throws(PlaydateError) {
|
public init(path: String, mode: Options) throws(PlaydateError) {
|
||||||
let pointer = path.withPlaydateCString {
|
let pointer = path.withPlaydateCString {
|
||||||
fileAPI.open.unsafelyUnwrapped($0, mode.cValue)
|
fileAPI.pointee.open.unsafelyUnwrapped($0, mode.cValue)
|
||||||
}
|
}
|
||||||
guard let pointer else { throw lastFileError() }
|
guard let pointer else { throw lastFileError() }
|
||||||
self.pointer = pointer
|
self.pointer = pointer
|
||||||
@@ -131,7 +131,7 @@ extension File {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if !isClosed {
|
if !isClosed {
|
||||||
_ = fileAPI.close.unsafelyUnwrapped(pointer)
|
_ = fileAPI.pointee.close.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,13 +139,13 @@ extension File {
|
|||||||
public func close() throws(PlaydateError) {
|
public func close() throws(PlaydateError) {
|
||||||
guard !isClosed else { return }
|
guard !isClosed else { return }
|
||||||
isClosed = true
|
isClosed = true
|
||||||
if fileAPI.close.unsafelyUnwrapped(pointer) != 0 { throw lastFileError() }
|
if fileAPI.pointee.close.unsafelyUnwrapped(pointer) != 0 { throw lastFileError() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads up to `buffer.count` bytes into `buffer`. Returns the number
|
/// Reads up to `buffer.count` bytes into `buffer`. Returns the number
|
||||||
/// of bytes read; 0 indicates end of file.
|
/// of bytes read; 0 indicates end of file.
|
||||||
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(PlaydateError) -> Int {
|
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(PlaydateError) -> Int {
|
||||||
let result = fileAPI.read.unsafelyUnwrapped(
|
let result = fileAPI.pointee.read.unsafelyUnwrapped(
|
||||||
pointer, buffer.baseAddress, UInt32(buffer.count))
|
pointer, buffer.baseAddress, UInt32(buffer.count))
|
||||||
if result < 0 { throw lastFileError() }
|
if result < 0 { throw lastFileError() }
|
||||||
return Int(result)
|
return Int(result)
|
||||||
@@ -155,7 +155,7 @@ extension File {
|
|||||||
public func read(length: Int) throws(PlaydateError) -> [UInt8] {
|
public func read(length: Int) throws(PlaydateError) -> [UInt8] {
|
||||||
var bytes = [UInt8](repeating: 0, count: length)
|
var bytes = [UInt8](repeating: 0, count: length)
|
||||||
let result = bytes.withUnsafeMutableBytes { buffer in
|
let result = bytes.withUnsafeMutableBytes { buffer in
|
||||||
fileAPI.read.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
fileAPI.pointee.read.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
||||||
}
|
}
|
||||||
if result < 0 { throw lastFileError() }
|
if result < 0 { throw lastFileError() }
|
||||||
bytes.removeLast(length - Int(result))
|
bytes.removeLast(length - Int(result))
|
||||||
@@ -165,7 +165,7 @@ extension File {
|
|||||||
/// Writes the buffer to the file. Returns the number of bytes written.
|
/// Writes the buffer to the file. Returns the number of bytes written.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func write(_ buffer: UnsafeRawBufferPointer) throws(PlaydateError) -> Int {
|
public func write(_ buffer: UnsafeRawBufferPointer) throws(PlaydateError) -> Int {
|
||||||
let result = fileAPI.write.unsafelyUnwrapped(
|
let result = fileAPI.pointee.write.unsafelyUnwrapped(
|
||||||
pointer, buffer.baseAddress, UInt32(buffer.count))
|
pointer, buffer.baseAddress, UInt32(buffer.count))
|
||||||
if result < 0 { throw lastFileError() }
|
if result < 0 { throw lastFileError() }
|
||||||
return Int(result)
|
return Int(result)
|
||||||
@@ -175,7 +175,7 @@ extension File {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public func write(_ bytes: [UInt8]) throws(PlaydateError) -> Int {
|
public func write(_ bytes: [UInt8]) throws(PlaydateError) -> Int {
|
||||||
let result = bytes.withUnsafeBytes { buffer in
|
let result = bytes.withUnsafeBytes { buffer in
|
||||||
fileAPI.write.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
fileAPI.pointee.write.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
||||||
}
|
}
|
||||||
if result < 0 { throw lastFileError() }
|
if result < 0 { throw lastFileError() }
|
||||||
return Int(result)
|
return Int(result)
|
||||||
@@ -190,21 +190,21 @@ extension File {
|
|||||||
/// Flushes buffered writes to disk. Returns the bytes written.
|
/// Flushes buffered writes to disk. Returns the bytes written.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func flush() throws(PlaydateError) -> Int {
|
public func flush() throws(PlaydateError) -> Int {
|
||||||
let result = fileAPI.flush.unsafelyUnwrapped(pointer)
|
let result = fileAPI.pointee.flush.unsafelyUnwrapped(pointer)
|
||||||
if result < 0 { throw lastFileError() }
|
if result < 0 { throw lastFileError() }
|
||||||
return Int(result)
|
return Int(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current read/write offset.
|
/// The current read/write offset.
|
||||||
public func tell() throws(PlaydateError) -> Int {
|
public func tell() throws(PlaydateError) -> Int {
|
||||||
let result = fileAPI.tell.unsafelyUnwrapped(pointer)
|
let result = fileAPI.pointee.tell.unsafelyUnwrapped(pointer)
|
||||||
if result < 0 { throw lastFileError() }
|
if result < 0 { throw lastFileError() }
|
||||||
return Int(result)
|
return Int(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the read/write offset to `offset` relative to `origin`.
|
/// Moves the read/write offset to `offset` relative to `origin`.
|
||||||
public func seek(to offset: Int, from origin: SeekOrigin = .start) throws(PlaydateError) {
|
public func seek(to offset: Int, from origin: SeekOrigin = .start) throws(PlaydateError) {
|
||||||
if fileAPI.seek.unsafelyUnwrapped(pointer, Int32(offset), origin.rawValue) != 0 {
|
if fileAPI.pointee.seek.unsafelyUnwrapped(pointer, Int32(offset), origin.rawValue) != 0 {
|
||||||
throw lastFileError()
|
throw lastFileError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ internal import CPlaydate
|
|||||||
/// The graphics API: drawing, bitmaps, fonts, tilemaps, and video.
|
/// The graphics API: drawing, bitmaps, fonts, tilemaps, and video.
|
||||||
public enum Graphics {}
|
public enum Graphics {}
|
||||||
|
|
||||||
var gfx: playdate_graphics { Playdate.api.graphics.pointee }
|
var gfx: UnsafePointer<playdate_graphics> { Playdate.graphicsAPI }
|
||||||
|
|
||||||
extension Graphics {
|
extension Graphics {
|
||||||
// MARK: - Screen constants
|
// MARK: - Screen constants
|
||||||
@@ -185,100 +185,100 @@ extension Graphics {
|
|||||||
|
|
||||||
/// Clears the entire display, filling it with `color`.
|
/// Clears the entire display, filling it with `color`.
|
||||||
public static func clear(color: Color = .white) {
|
public static func clear(color: Color = .white) {
|
||||||
color.withLCDColor { gfx.clear.unsafelyUnwrapped($0) }
|
color.withLCDColor { gfx.pointee.clear.unsafelyUnwrapped($0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the background color shown when the display is offset or for
|
/// Sets the background color shown when the display is offset or for
|
||||||
/// clear pixels in drawn images.
|
/// clear pixels in drawn images.
|
||||||
public static func setBackgroundColor(_ color: SolidColor) {
|
public static func setBackgroundColor(_ color: SolidColor) {
|
||||||
gfx.setBackgroundColor.unsafelyUnwrapped(color.cValue)
|
gfx.pointee.setBackgroundColor.unsafelyUnwrapped(color.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the mode that determines how source pixels combine with the
|
/// Sets the mode that determines how source pixels combine with the
|
||||||
/// destination. Returns the previous mode.
|
/// destination. Returns the previous mode.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func setDrawMode(_ mode: DrawMode) -> DrawMode {
|
public static func setDrawMode(_ mode: DrawMode) -> DrawMode {
|
||||||
DrawMode(gfx.setDrawMode.unsafelyUnwrapped(mode.cValue))
|
DrawMode(gfx.pointee.setDrawMode.unsafelyUnwrapped(mode.cValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Offsets all subsequent drawing by (dx, dy).
|
/// Offsets all subsequent drawing by (dx, dy).
|
||||||
public static func setDrawOffset(dx: Int, dy: Int) {
|
public static func setDrawOffset(dx: Int, dy: Int) {
|
||||||
gfx.setDrawOffset.unsafelyUnwrapped(Int32(dx), Int32(dy))
|
gfx.pointee.setDrawOffset.unsafelyUnwrapped(Int32(dx), Int32(dy))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the clip rect in world coordinates (affected by the draw offset).
|
/// Sets the clip rect in world coordinates (affected by the draw offset).
|
||||||
public static func setClipRect(x: Int, y: Int, width: Int, height: Int) {
|
public static func setClipRect(x: Int, y: Int, width: Int, height: Int) {
|
||||||
gfx.setClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
gfx.pointee.setClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the clip rect in screen coordinates (unaffected by the draw offset).
|
/// Sets the clip rect in screen coordinates (unaffected by the draw offset).
|
||||||
public static func setScreenClipRect(x: Int, y: Int, width: Int, height: Int) {
|
public static func setScreenClipRect(x: Int, y: Int, width: Int, height: Int) {
|
||||||
gfx.setScreenClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
gfx.pointee.setScreenClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func clearClipRect() {
|
public static func clearClipRect() {
|
||||||
gfx.clearClipRect.unsafelyUnwrapped()
|
gfx.pointee.clearClipRect.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func setLineCapStyle(_ style: LineCapStyle) {
|
public static func setLineCapStyle(_ style: LineCapStyle) {
|
||||||
gfx.setLineCapStyle.unsafelyUnwrapped(style.cValue)
|
gfx.pointee.setLineCapStyle.unsafelyUnwrapped(style.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the stencil applied to subsequent drawing. If `tile` is `true`
|
/// Sets the stencil applied to subsequent drawing. If `tile` is `true`
|
||||||
/// the stencil image is tiled, and its width must be a multiple of 32.
|
/// the stencil image is tiled, and its width must be a multiple of 32.
|
||||||
/// Pass `nil` to clear the stencil.
|
/// Pass `nil` to clear the stencil.
|
||||||
public static func setStencil(_ image: Bitmap?, tile: Bool = false) {
|
public static func setStencil(_ image: Bitmap?, tile: Bool = false) {
|
||||||
gfx.setStencilImage.unsafelyUnwrapped(image?.pointer, tile ? 1 : 0)
|
gfx.pointee.setStencilImage.unsafelyUnwrapped(image?.pointer, tile ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes a new drawing context targeting `target`, or the display if
|
/// Pushes a new drawing context targeting `target`, or the display if
|
||||||
/// `target` is `nil`.
|
/// `target` is `nil`.
|
||||||
public static func pushContext(_ target: Bitmap? = nil) {
|
public static func pushContext(_ target: Bitmap? = nil) {
|
||||||
gfx.pushContext.unsafelyUnwrapped(target?.pointer)
|
gfx.pointee.pushContext.unsafelyUnwrapped(target?.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func popContext() {
|
public static func popContext() {
|
||||||
gfx.popContext.unsafelyUnwrapped()
|
gfx.pointee.popContext.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Shapes
|
// MARK: - Shapes
|
||||||
|
|
||||||
public static func drawLine(x1: Int, y1: Int, x2: Int, y2: Int, width: Int, color: Color) {
|
public static func drawLine(x1: Int, y1: Int, x2: Int, y2: Int, width: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.drawLine.unsafelyUnwrapped(Int32(x1), Int32(y1), Int32(x2), Int32(y2), Int32(width), $0)
|
gfx.pointee.drawLine.unsafelyUnwrapped(Int32(x1), Int32(y1), Int32(x2), Int32(y2), Int32(width), $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func fillTriangle(x1: Int, y1: Int, x2: Int, y2: Int, x3: Int, y3: Int, color: Color) {
|
public static func fillTriangle(x1: Int, y1: Int, x2: Int, y2: Int, x3: Int, y3: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.fillTriangle.unsafelyUnwrapped(Int32(x1), Int32(y1), Int32(x2), Int32(y2),
|
gfx.pointee.fillTriangle.unsafelyUnwrapped(Int32(x1), Int32(y1), Int32(x2), Int32(y2),
|
||||||
Int32(x3), Int32(y3), $0)
|
Int32(x3), Int32(y3), $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func drawRect(x: Int, y: Int, width: Int, height: Int, color: Color) {
|
public static func drawRect(x: Int, y: Int, width: Int, height: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.drawRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height), $0)
|
gfx.pointee.drawRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height), $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func fillRect(x: Int, y: Int, width: Int, height: Int, color: Color) {
|
public static func fillRect(x: Int, y: Int, width: Int, height: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.fillRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height), $0)
|
gfx.pointee.fillRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height), $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func drawRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int,
|
public static func drawRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int,
|
||||||
lineWidth: Int, color: Color) {
|
lineWidth: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.drawRoundRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
gfx.pointee.drawRoundRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
||||||
Int32(radius), Int32(lineWidth), $0)
|
Int32(radius), Int32(lineWidth), $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func fillRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int, color: Color) {
|
public static func fillRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.fillRoundRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
gfx.pointee.fillRoundRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
||||||
Int32(radius), $0)
|
Int32(radius), $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ extension Graphics {
|
|||||||
public static func drawEllipse(x: Int, y: Int, width: Int, height: Int, lineWidth: Int,
|
public static func drawEllipse(x: Int, y: Int, width: Int, height: Int, lineWidth: Int,
|
||||||
startAngle: Float = 0, endAngle: Float = 0, color: Color) {
|
startAngle: Float = 0, endAngle: Float = 0, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.drawEllipse.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
gfx.pointee.drawEllipse.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
||||||
Int32(lineWidth), startAngle, endAngle, $0)
|
Int32(lineWidth), startAngle, endAngle, $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +296,7 @@ extension Graphics {
|
|||||||
public static func fillEllipse(x: Int, y: Int, width: Int, height: Int,
|
public static func fillEllipse(x: Int, y: Int, width: Int, height: Int,
|
||||||
startAngle: Float = 0, endAngle: Float = 0, color: Color) {
|
startAngle: Float = 0, endAngle: Float = 0, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
gfx.fillEllipse.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
gfx.pointee.fillEllipse.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height),
|
||||||
startAngle, endAngle, $0)
|
startAngle, endAngle, $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,7 +313,7 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
color.withLCDColor { cColor in
|
color.withLCDColor { cColor in
|
||||||
coordinates.withUnsafeMutableBufferPointer { buffer in
|
coordinates.withUnsafeMutableBufferPointer { buffer in
|
||||||
gfx.fillPolygon.unsafelyUnwrapped(Int32(points.count), buffer.baseAddress,
|
gfx.pointee.fillPolygon.unsafelyUnwrapped(Int32(points.count), buffer.baseAddress,
|
||||||
cColor, fillRule.cValue)
|
cColor, fillRule.cValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,13 +321,13 @@ extension Graphics {
|
|||||||
|
|
||||||
/// Sets the pixel at (x, y) in the current drawing context.
|
/// Sets the pixel at (x, y) in the current drawing context.
|
||||||
public static func setPixel(x: Int, y: Int, color: Color) {
|
public static func setPixel(x: Int, y: Int, color: Color) {
|
||||||
color.withLCDColor { gfx.setPixel.unsafelyUnwrapped(Int32(x), Int32(y), $0) }
|
color.withLCDColor { gfx.pointee.setPixel.unsafelyUnwrapped(Int32(x), Int32(y), $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an 8×8 pattern from the bitmap starting at (x, y).
|
/// Reads an 8×8 pattern from the bitmap starting at (x, y).
|
||||||
public static func colorToPattern(from bitmap: Bitmap, x: Int, y: Int) -> Pattern {
|
public static func colorToPattern(from bitmap: Bitmap, x: Int, y: Int) -> Pattern {
|
||||||
var color: LCDColor = 0
|
var color: LCDColor = 0
|
||||||
gfx.setColorToPattern.unsafelyUnwrapped(&color, bitmap.pointer, Int32(x), Int32(y))
|
gfx.pointee.setColorToPattern.unsafelyUnwrapped(&color, bitmap.pointer, Int32(x), Int32(y))
|
||||||
var pattern = Pattern(bytes: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
var pattern = Pattern(bytes: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
||||||
if let source = UnsafeRawPointer(bitPattern: UInt(color)) {
|
if let source = UnsafeRawPointer(bitPattern: UInt(color)) {
|
||||||
withUnsafeMutableBytes(of: &pattern.bytes) { destination in
|
withUnsafeMutableBytes(of: &pattern.bytes) { destination in
|
||||||
@@ -342,41 +342,39 @@ extension Graphics {
|
|||||||
/// Draws `text` at (x, y) using the current font. Returns the drawn width.
|
/// Draws `text` at (x, y) using the current font. Returns the drawn width.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func drawText(_ text: String, x: Int, y: Int) -> Int {
|
public static func drawText(_ text: String, x: Int, y: Int) -> Int {
|
||||||
let utf8 = ContiguousArray(text.utf8)
|
text.withPlaydateUTF8 { bytes, count in
|
||||||
return utf8.withUnsafeBufferPointer { buffer in
|
Int(gfx.pointee.drawText.unsafelyUnwrapped(bytes, count,
|
||||||
Int(gfx.drawText.unsafelyUnwrapped(buffer.baseAddress, buffer.count,
|
kUTF8Encoding, Int32(x), Int32(y)))
|
||||||
kUTF8Encoding, Int32(x), Int32(y)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws `text` wrapped and aligned inside the given rectangle.
|
/// Draws `text` wrapped and aligned inside the given rectangle.
|
||||||
public static func drawText(_ text: String, x: Int, y: Int, width: Int, height: Int,
|
public static func drawText(_ text: String, x: Int, y: Int, width: Int, height: Int,
|
||||||
wrap: TextWrappingMode = .word, align: TextAlignment = .left) {
|
wrap: TextWrappingMode = .word, align: TextAlignment = .left) {
|
||||||
let utf8 = ContiguousArray(text.utf8)
|
text.withPlaydateUTF8 { bytes, count in
|
||||||
utf8.withUnsafeBufferPointer { buffer in
|
gfx.pointee.drawTextInRect.unsafelyUnwrapped(bytes, count, kUTF8Encoding,
|
||||||
gfx.drawTextInRect.unsafelyUnwrapped(buffer.baseAddress, buffer.count, kUTF8Encoding,
|
Int32(x), Int32(y), Int32(width), Int32(height),
|
||||||
Int32(x), Int32(y), Int32(width), Int32(height),
|
wrap.cValue, align.cValue)
|
||||||
wrap.cValue, align.cValue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the font used by subsequent text drawing.
|
/// Sets the font used by subsequent text drawing.
|
||||||
public static func setFont(_ font: Font) {
|
public static func setFont(_ font: Font) {
|
||||||
gfx.setFont.unsafelyUnwrapped(font.pointer)
|
gfx.pointee.setFont.unsafelyUnwrapped(font.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extra space added between letters, in pixels.
|
/// Extra space added between letters, in pixels.
|
||||||
public static func setTextTracking(_ tracking: Int) {
|
public static func setTextTracking(_ tracking: Int) {
|
||||||
gfx.setTextTracking.unsafelyUnwrapped(Int32(tracking))
|
gfx.pointee.setTextTracking.unsafelyUnwrapped(Int32(tracking))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var textTracking: Int {
|
public static var textTracking: Int {
|
||||||
Int(gfx.getTextTracking.unsafelyUnwrapped())
|
Int(gfx.pointee.getTextTracking.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adjusts the line height used when drawing multi-line text.
|
/// Adjusts the line height used when drawing multi-line text.
|
||||||
public static func setTextLeading(_ lineHeightAdjustment: Int) {
|
public static func setTextLeading(_ lineHeightAdjustment: Int) {
|
||||||
gfx.setTextLeading.unsafelyUnwrapped(Int32(lineHeightAdjustment))
|
gfx.pointee.setTextLeading.unsafelyUnwrapped(Int32(lineHeightAdjustment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Framebuffer
|
// MARK: - Framebuffer
|
||||||
@@ -384,42 +382,42 @@ extension Graphics {
|
|||||||
/// The current working framebuffer. Rows are `rowSize` bytes.
|
/// The current working framebuffer. Rows are `rowSize` bytes.
|
||||||
/// Call `markUpdatedRows(from:to:)` after writing directly.
|
/// Call `markUpdatedRows(from:to:)` after writing directly.
|
||||||
public static var frame: UnsafeMutablePointer<UInt8>? {
|
public static var frame: UnsafeMutablePointer<UInt8>? {
|
||||||
gfx.getFrame.unsafelyUnwrapped()
|
gfx.pointee.getFrame.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The framebuffer currently shown on the display. Rows are `rowSize` bytes.
|
/// The framebuffer currently shown on the display. Rows are `rowSize` bytes.
|
||||||
public static var displayFrame: UnsafeMutablePointer<UInt8>? {
|
public static var displayFrame: UnsafeMutablePointer<UInt8>? {
|
||||||
gfx.getDisplayFrame.unsafelyUnwrapped()
|
gfx.pointee.getDisplayFrame.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bitmap view of the display framebuffer. Simulator only; `nil` on device.
|
/// A bitmap view of the display framebuffer. Simulator only; `nil` on device.
|
||||||
public static var debugBitmap: Bitmap? {
|
public static var debugBitmap: Bitmap? {
|
||||||
guard let getDebugBitmap = gfx.getDebugBitmap,
|
guard let getDebugBitmap = gfx.pointee.getDebugBitmap,
|
||||||
let pointer = getDebugBitmap() else { return nil }
|
let pointer = getDebugBitmap() else { return nil }
|
||||||
return Bitmap(pointer: pointer, isOwned: false)
|
return Bitmap(pointer: pointer, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bitmap referencing the display framebuffer (not a copy).
|
/// A bitmap referencing the display framebuffer (not a copy).
|
||||||
public static var displayBufferBitmap: Bitmap? {
|
public static var displayBufferBitmap: Bitmap? {
|
||||||
guard let pointer = gfx.getDisplayBufferBitmap.unsafelyUnwrapped() else { return nil }
|
guard let pointer = gfx.pointee.getDisplayBufferBitmap.unsafelyUnwrapped() else { return nil }
|
||||||
return Bitmap(pointer: pointer, isOwned: false)
|
return Bitmap(pointer: pointer, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A copy of the working framebuffer as a new bitmap.
|
/// A copy of the working framebuffer as a new bitmap.
|
||||||
public static func copyFrameBufferBitmap() -> Bitmap? {
|
public static func copyFrameBufferBitmap() -> Bitmap? {
|
||||||
guard let pointer = gfx.copyFrameBufferBitmap.unsafelyUnwrapped() else { return nil }
|
guard let pointer = gfx.pointee.copyFrameBufferBitmap.unsafelyUnwrapped() else { return nil }
|
||||||
return Bitmap(pointer: pointer, isOwned: true)
|
return Bitmap(pointer: pointer, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tells the system which rows (inclusive) were changed by direct
|
/// Tells the system which rows (inclusive) were changed by direct
|
||||||
/// framebuffer writes and need redisplay.
|
/// framebuffer writes and need redisplay.
|
||||||
public static func markUpdatedRows(from start: Int, to end: Int) {
|
public static func markUpdatedRows(from start: Int, to end: Int) {
|
||||||
gfx.markUpdatedRows.unsafelyUnwrapped(Int32(start), Int32(end))
|
gfx.pointee.markUpdatedRows.unsafelyUnwrapped(Int32(start), Int32(end))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manually flushes the framebuffer to the display. Only needed when
|
/// Manually flushes the framebuffer to the display. Only needed when
|
||||||
/// drawing outside the normal update cycle.
|
/// drawing outside the normal update cycle.
|
||||||
public static func display() {
|
public static func display() {
|
||||||
gfx.display.unsafelyUnwrapped()
|
gfx.pointee.display.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ extension Graphics {
|
|||||||
/// Allocates a new bitmap filled with `backgroundColor`.
|
/// Allocates a new bitmap filled with `backgroundColor`.
|
||||||
public convenience init(width: Int, height: Int, backgroundColor: Color = .clear) {
|
public convenience init(width: Int, height: Int, backgroundColor: Color = .clear) {
|
||||||
let pointer = backgroundColor.withLCDColor {
|
let pointer = backgroundColor.withLCDColor {
|
||||||
gfx.newBitmap.unsafelyUnwrapped(Int32(width), Int32(height), $0)
|
gfx.pointee.newBitmap.unsafelyUnwrapped(Int32(width), Int32(height), $0)
|
||||||
}
|
}
|
||||||
self.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
self.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
@@ -31,14 +31,14 @@ extension Graphics {
|
|||||||
/// Loads a bitmap from a file in the game's pdx or Data directory.
|
/// Loads a bitmap from a file in the game's pdx or Data directory.
|
||||||
public convenience init(path: String) throws(PlaydateError) {
|
public convenience init(path: String) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
let pointer = path.withPlaydateCString { gfx.loadBitmap.unsafelyUnwrapped($0, &error) }
|
let pointer = path.withPlaydateCString { gfx.pointee.loadBitmap.unsafelyUnwrapped($0, &error) }
|
||||||
guard let pointer else { throw PlaydateError(cString: error) }
|
guard let pointer else { throw PlaydateError(cString: error) }
|
||||||
self.init(pointer: pointer, isOwned: true)
|
self.init(pointer: pointer, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
gfx.freeBitmap.unsafelyUnwrapped(pointer)
|
gfx.pointee.freeBitmap.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ extension Graphics {
|
|||||||
var width: Int32 = 0, height: Int32 = 0, rowBytes: Int32 = 0
|
var width: Int32 = 0, height: Int32 = 0, rowBytes: Int32 = 0
|
||||||
var mask: UnsafeMutablePointer<UInt8>?
|
var mask: UnsafeMutablePointer<UInt8>?
|
||||||
var data: UnsafeMutablePointer<UInt8>?
|
var data: UnsafeMutablePointer<UInt8>?
|
||||||
gfx.getBitmapData.unsafelyUnwrapped(pointer, &width, &height, &rowBytes, &mask, &data)
|
gfx.pointee.getBitmapData.unsafelyUnwrapped(pointer, &width, &height, &rowBytes, &mask, &data)
|
||||||
return Data(width: Int(width), height: Int(height), rowBytes: Int(rowBytes),
|
return Data(width: Int(width), height: Int(height), rowBytes: Int(rowBytes),
|
||||||
mask: mask, data: data)
|
mask: mask, data: data)
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ extension Graphics {
|
|||||||
|
|
||||||
/// The color of the pixel at (x, y).
|
/// The color of the pixel at (x, y).
|
||||||
public func pixel(x: Int, y: Int) -> SolidColor {
|
public func pixel(x: Int, y: Int) -> SolidColor {
|
||||||
SolidColor(gfx.getBitmapPixel.unsafelyUnwrapped(pointer, Int32(x), Int32(y)))
|
SolidColor(gfx.pointee.getBitmapPixel.unsafelyUnwrapped(pointer, Int32(x), Int32(y)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Operations
|
// MARK: Operations
|
||||||
@@ -76,23 +76,23 @@ extension Graphics {
|
|||||||
/// Replaces the bitmap's contents with the image at `path`.
|
/// Replaces the bitmap's contents with the image at `path`.
|
||||||
public func load(path: String) throws(PlaydateError) {
|
public func load(path: String) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
path.withPlaydateCString { gfx.loadIntoBitmap.unsafelyUnwrapped($0, pointer, &error) }
|
path.withPlaydateCString { gfx.pointee.loadIntoBitmap.unsafelyUnwrapped($0, pointer, &error) }
|
||||||
if let error { throw PlaydateError(cString: error) }
|
if let error { throw PlaydateError(cString: error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fills the bitmap with `color`.
|
/// Fills the bitmap with `color`.
|
||||||
public func clear(color: Color) {
|
public func clear(color: Color) {
|
||||||
color.withLCDColor { gfx.clearBitmap.unsafelyUnwrapped(pointer, $0) }
|
color.withLCDColor { gfx.pointee.clearBitmap.unsafelyUnwrapped(pointer, $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public func copy() -> Bitmap {
|
public func copy() -> Bitmap {
|
||||||
Bitmap(pointer: gfx.copyBitmap.unsafelyUnwrapped(pointer).unsafelyUnwrapped, isOwned: true)
|
Bitmap(pointer: gfx.pointee.copyBitmap.unsafelyUnwrapped(pointer).unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new bitmap rotated by `degrees` (clockwise) and scaled.
|
/// Returns a new bitmap rotated by `degrees` (clockwise) and scaled.
|
||||||
public func rotated(by degrees: Float, xScale: Float = 1, yScale: Float = 1) -> Bitmap? {
|
public func rotated(by degrees: Float, xScale: Float = 1, yScale: Float = 1) -> Bitmap? {
|
||||||
var allocatedSize: Int32 = 0
|
var allocatedSize: Int32 = 0
|
||||||
guard let rotated = gfx.rotatedBitmap.unsafelyUnwrapped(
|
guard let rotated = gfx.pointee.rotatedBitmap.unsafelyUnwrapped(
|
||||||
pointer, degrees, xScale, yScale, &allocatedSize) else { return nil }
|
pointer, degrees, xScale, yScale, &allocatedSize) else { return nil }
|
||||||
return Bitmap(pointer: rotated, isOwned: true)
|
return Bitmap(pointer: rotated, isOwned: true)
|
||||||
}
|
}
|
||||||
@@ -100,13 +100,13 @@ extension Graphics {
|
|||||||
/// Sets a mask image. The mask must match the bitmap's dimensions.
|
/// Sets a mask image. The mask must match the bitmap's dimensions.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func setMask(_ mask: Bitmap?) -> Bool {
|
public func setMask(_ mask: Bitmap?) -> Bool {
|
||||||
gfx.setBitmapMask.unsafelyUnwrapped(pointer, mask?.pointer) != 0
|
gfx.pointee.setBitmapMask.unsafelyUnwrapped(pointer, mask?.pointer) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The bitmap's mask, if any. The returned bitmap references storage
|
/// The bitmap's mask, if any. The returned bitmap references storage
|
||||||
/// owned by this bitmap.
|
/// owned by this bitmap.
|
||||||
public var mask: Bitmap? {
|
public var mask: Bitmap? {
|
||||||
guard let mask = gfx.getBitmapMask.unsafelyUnwrapped(pointer) else { return nil }
|
guard let mask = gfx.pointee.getBitmapMask.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Bitmap(pointer: mask, isOwned: false)
|
return Bitmap(pointer: mask, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ extension Graphics {
|
|||||||
other: Bitmap, otherX: Int, otherY: Int,
|
other: Bitmap, otherX: Int, otherY: Int,
|
||||||
otherFlip: BitmapFlip = .unflipped,
|
otherFlip: BitmapFlip = .unflipped,
|
||||||
in rect: Rect) -> Bool {
|
in rect: Rect) -> Bool {
|
||||||
gfx.checkMaskCollision.unsafelyUnwrapped(
|
gfx.pointee.checkMaskCollision.unsafelyUnwrapped(
|
||||||
pointer, Int32(x), Int32(y), flip.cValue,
|
pointer, Int32(x), Int32(y), flip.cValue,
|
||||||
other.pointer, Int32(otherX), Int32(otherY), otherFlip.cValue,
|
other.pointer, Int32(otherX), Int32(otherY), otherFlip.cValue,
|
||||||
rect.cValue) != 0
|
rect.cValue) != 0
|
||||||
@@ -126,13 +126,13 @@ extension Graphics {
|
|||||||
|
|
||||||
/// Draws the bitmap with its upper-left corner at (x, y).
|
/// Draws the bitmap with its upper-left corner at (x, y).
|
||||||
public func draw(x: Int, y: Int, flip: BitmapFlip = .unflipped) {
|
public func draw(x: Int, y: Int, flip: BitmapFlip = .unflipped) {
|
||||||
gfx.drawBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y), flip.cValue)
|
gfx.pointee.drawBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y), flip.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the bitmap scaled by (xScale, yScale) with its upper-left
|
/// Draws the bitmap scaled by (xScale, yScale) with its upper-left
|
||||||
/// corner at (x, y).
|
/// corner at (x, y).
|
||||||
public func drawScaled(x: Int, y: Int, xScale: Float, yScale: Float) {
|
public func drawScaled(x: Int, y: Int, xScale: Float, yScale: Float) {
|
||||||
gfx.drawScaledBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y), xScale, yScale)
|
gfx.pointee.drawScaledBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y), xScale, yScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the bitmap rotated by `degrees` around its anchor point,
|
/// Draws the bitmap rotated by `degrees` around its anchor point,
|
||||||
@@ -140,13 +140,13 @@ extension Graphics {
|
|||||||
public func drawRotated(x: Int, y: Int, degrees: Float,
|
public func drawRotated(x: Int, y: Int, degrees: Float,
|
||||||
centerX: Float = 0.5, centerY: Float = 0.5,
|
centerX: Float = 0.5, centerY: Float = 0.5,
|
||||||
xScale: Float = 1, yScale: Float = 1) {
|
xScale: Float = 1, yScale: Float = 1) {
|
||||||
gfx.drawRotatedBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y), degrees,
|
gfx.pointee.drawRotatedBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y), degrees,
|
||||||
centerX, centerY, xScale, yScale)
|
centerX, centerY, xScale, yScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tiles the bitmap over the given area.
|
/// Tiles the bitmap over the given area.
|
||||||
public func tile(x: Int, y: Int, width: Int, height: Int, flip: BitmapFlip = .unflipped) {
|
public func tile(x: Int, y: Int, width: Int, height: Int, flip: BitmapFlip = .unflipped) {
|
||||||
gfx.tileBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y),
|
gfx.pointee.tileBitmap.unsafelyUnwrapped(pointer, Int32(x), Int32(y),
|
||||||
Int32(width), Int32(height), flip.cValue)
|
Int32(width), Int32(height), flip.cValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,26 +161,26 @@ extension Graphics {
|
|||||||
|
|
||||||
/// Allocates a table with room for `count` bitmaps of the given size.
|
/// Allocates a table with room for `count` bitmaps of the given size.
|
||||||
public convenience init(count: Int, width: Int, height: Int) {
|
public convenience init(count: Int, width: Int, height: Int) {
|
||||||
let pointer = gfx.newBitmapTable.unsafelyUnwrapped(Int32(count), Int32(width), Int32(height))
|
let pointer = gfx.pointee.newBitmapTable.unsafelyUnwrapped(Int32(count), Int32(width), Int32(height))
|
||||||
self.init(pointer: pointer.unsafelyUnwrapped)
|
self.init(pointer: pointer.unsafelyUnwrapped)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads an image table from a file.
|
/// Loads an image table from a file.
|
||||||
public convenience init(path: String) throws(PlaydateError) {
|
public convenience init(path: String) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
let pointer = path.withPlaydateCString { gfx.loadBitmapTable.unsafelyUnwrapped($0, &error) }
|
let pointer = path.withPlaydateCString { gfx.pointee.loadBitmapTable.unsafelyUnwrapped($0, &error) }
|
||||||
guard let pointer else { throw PlaydateError(cString: error) }
|
guard let pointer else { throw PlaydateError(cString: error) }
|
||||||
self.init(pointer: pointer)
|
self.init(pointer: pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
gfx.freeBitmapTable.unsafelyUnwrapped(pointer)
|
gfx.pointee.freeBitmapTable.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the table's contents with the image table at `path`.
|
/// Replaces the table's contents with the image table at `path`.
|
||||||
public func load(path: String) throws(PlaydateError) {
|
public func load(path: String) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
path.withPlaydateCString { gfx.loadIntoBitmapTable.unsafelyUnwrapped($0, pointer, &error) }
|
path.withPlaydateCString { gfx.pointee.loadIntoBitmapTable.unsafelyUnwrapped($0, pointer, &error) }
|
||||||
if let error { throw PlaydateError(cString: error) }
|
if let error { throw PlaydateError(cString: error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ extension Graphics {
|
|||||||
/// references storage owned by the table; keep the table alive while
|
/// references storage owned by the table; keep the table alive while
|
||||||
/// using it.
|
/// using it.
|
||||||
public func bitmap(at index: Int) -> Bitmap? {
|
public func bitmap(at index: Int) -> Bitmap? {
|
||||||
guard let bitmap = gfx.getTableBitmap.unsafelyUnwrapped(pointer, Int32(index)) else {
|
guard let bitmap = gfx.pointee.getTableBitmap.unsafelyUnwrapped(pointer, Int32(index)) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return Bitmap(pointer: bitmap, isOwned: false)
|
return Bitmap(pointer: bitmap, isOwned: false)
|
||||||
@@ -198,7 +198,7 @@ extension Graphics {
|
|||||||
/// of the source image.
|
/// of the source image.
|
||||||
public var info: (count: Int, cellsWide: Int) {
|
public var info: (count: Int, cellsWide: Int) {
|
||||||
var count: Int32 = 0, width: Int32 = 0
|
var count: Int32 = 0, width: Int32 = 0
|
||||||
gfx.getBitmapTableInfo.unsafelyUnwrapped(pointer, &count, &width)
|
gfx.pointee.getBitmapTableInfo.unsafelyUnwrapped(pointer, &count, &width)
|
||||||
return (Int(count), Int(width))
|
return (Int(count), Int(width))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ extension Graphics {
|
|||||||
/// Loads a font from a file.
|
/// Loads a font from a file.
|
||||||
public convenience init(path: String) throws(PlaydateError) {
|
public convenience init(path: String) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
let pointer = path.withPlaydateCString { gfx.loadFont.unsafelyUnwrapped($0, &error) }
|
let pointer = path.withPlaydateCString { gfx.pointee.loadFont.unsafelyUnwrapped($0, &error) }
|
||||||
guard let pointer else { throw PlaydateError(cString: error) }
|
guard let pointer else { throw PlaydateError(cString: error) }
|
||||||
self.init(pointer: pointer)
|
self.init(pointer: pointer)
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ extension Graphics {
|
|||||||
let copy = UnsafeMutableRawPointer.allocate(byteCount: data.count, alignment: 4)
|
let copy = UnsafeMutableRawPointer.allocate(byteCount: data.count, alignment: 4)
|
||||||
copy.copyMemory(from: data.baseAddress.unsafelyUnwrapped, byteCount: data.count)
|
copy.copyMemory(from: data.baseAddress.unsafelyUnwrapped, byteCount: data.count)
|
||||||
let fontData = OpaquePointer(copy)
|
let fontData = OpaquePointer(copy)
|
||||||
guard let pointer = gfx.makeFontFromData.unsafelyUnwrapped(
|
guard let pointer = gfx.pointee.makeFontFromData.unsafelyUnwrapped(
|
||||||
fontData, wide ? 1 : 0, Int32(data.count)) else {
|
fontData, wide ? 1 : 0, Int32(data.count)) else {
|
||||||
copy.deallocate()
|
copy.deallocate()
|
||||||
return nil
|
return nil
|
||||||
@@ -48,25 +48,23 @@ extension Graphics {
|
|||||||
|
|
||||||
/// The font's glyph height in pixels.
|
/// The font's glyph height in pixels.
|
||||||
public var height: Int {
|
public var height: Int {
|
||||||
Int(gfx.getFontHeight.unsafelyUnwrapped(pointer))
|
Int(gfx.pointee.getFontHeight.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The width of `text` when drawn with this font.
|
/// The width of `text` when drawn with this font.
|
||||||
public func textWidth(_ text: String, tracking: Int = 0) -> Int {
|
public func textWidth(_ text: String, tracking: Int = 0) -> Int {
|
||||||
let utf8 = ContiguousArray(text.utf8)
|
text.withPlaydateUTF8 { bytes, count in
|
||||||
return utf8.withUnsafeBufferPointer { buffer in
|
Int(gfx.pointee.getTextWidth.unsafelyUnwrapped(pointer, bytes, count,
|
||||||
Int(gfx.getTextWidth.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count,
|
kUTF8Encoding, Int32(tracking)))
|
||||||
kUTF8Encoding, Int32(tracking)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The height of `text` when wrapped to `maxWidth` with this font.
|
/// The height of `text` when wrapped to `maxWidth` with this font.
|
||||||
public func textHeight(_ text: String, maxWidth: Int, wrap: TextWrappingMode = .word,
|
public func textHeight(_ text: String, maxWidth: Int, wrap: TextWrappingMode = .word,
|
||||||
tracking: Int = 0, extraLeading: Int = 0) -> Int {
|
tracking: Int = 0, extraLeading: Int = 0) -> Int {
|
||||||
let utf8 = ContiguousArray(text.utf8)
|
text.withPlaydateUTF8 { bytes, count in
|
||||||
return utf8.withUnsafeBufferPointer { buffer in
|
Int(gfx.pointee.getTextHeightForMaxWidth.unsafelyUnwrapped(
|
||||||
Int(gfx.getTextHeightForMaxWidth.unsafelyUnwrapped(
|
pointer, bytes, count, Int32(maxWidth), kUTF8Encoding,
|
||||||
pointer, buffer.baseAddress, buffer.count, Int32(maxWidth), kUTF8Encoding,
|
|
||||||
wrap.cValue, Int32(tracking), Int32(extraLeading)))
|
wrap.cValue, Int32(tracking), Int32(extraLeading)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +72,7 @@ extension Graphics {
|
|||||||
/// The page containing glyph data for the character `codepoint`
|
/// The page containing glyph data for the character `codepoint`
|
||||||
/// belongs to. The page references data owned by the font.
|
/// belongs to. The page references data owned by the font.
|
||||||
public func page(for codepoint: UInt32) -> FontPage? {
|
public func page(for codepoint: UInt32) -> FontPage? {
|
||||||
guard let page = gfx.getFontPage.unsafelyUnwrapped(pointer, codepoint) else { return nil }
|
guard let page = gfx.pointee.getFontPage.unsafelyUnwrapped(pointer, codepoint) else { return nil }
|
||||||
return FontPage(pointer: page, font: self)
|
return FontPage(pointer: page, font: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +81,7 @@ extension Graphics {
|
|||||||
public func glyph(for codepoint: UInt32) -> (glyph: Glyph, bitmap: Bitmap?, advance: Int)? {
|
public func glyph(for codepoint: UInt32) -> (glyph: Glyph, bitmap: Bitmap?, advance: Int)? {
|
||||||
var bitmap: OpaquePointer?
|
var bitmap: OpaquePointer?
|
||||||
var advance: Int32 = 0
|
var advance: Int32 = 0
|
||||||
guard let glyph = gfx.getFontGlyph.unsafelyUnwrapped(pointer, codepoint, &bitmap, &advance) else {
|
guard let glyph = gfx.pointee.getFontGlyph.unsafelyUnwrapped(pointer, codepoint, &bitmap, &advance) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return (Glyph(pointer: glyph, font: self),
|
return (Glyph(pointer: glyph, font: self),
|
||||||
@@ -102,7 +100,7 @@ extension Graphics {
|
|||||||
public func glyph(for codepoint: UInt32) -> (glyph: Glyph, bitmap: Bitmap?, advance: Int)? {
|
public func glyph(for codepoint: UInt32) -> (glyph: Glyph, bitmap: Bitmap?, advance: Int)? {
|
||||||
var bitmap: OpaquePointer?
|
var bitmap: OpaquePointer?
|
||||||
var advance: Int32 = 0
|
var advance: Int32 = 0
|
||||||
guard let glyph = gfx.getPageGlyph.unsafelyUnwrapped(pointer, codepoint, &bitmap, &advance) else {
|
guard let glyph = gfx.pointee.getPageGlyph.unsafelyUnwrapped(pointer, codepoint, &bitmap, &advance) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return (Glyph(pointer: glyph, font: font),
|
return (Glyph(pointer: glyph, font: font),
|
||||||
@@ -119,7 +117,7 @@ extension Graphics {
|
|||||||
|
|
||||||
/// The kerning adjustment between this glyph and the next character.
|
/// The kerning adjustment between this glyph and the next character.
|
||||||
public func kerning(glyphCode: UInt32, nextCode: UInt32) -> Int {
|
public func kerning(glyphCode: UInt32, nextCode: UInt32) -> Int {
|
||||||
Int(gfx.getGlyphKerning.unsafelyUnwrapped(pointer, glyphCode, nextCode))
|
Int(gfx.pointee.getGlyphKerning.unsafelyUnwrapped(pointer, glyphCode, nextCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var tilemapAPI: playdate_tilemap { gfx.tilemap.pointee }
|
private var tilemapAPI: UnsafePointer<playdate_tilemap> { gfx.pointee.tilemap.unsafelyUnwrapped }
|
||||||
|
|
||||||
extension Graphics {
|
extension Graphics {
|
||||||
/// A grid of tiles drawn from a bitmap table. Wraps `LCDTileMap`.
|
/// A grid of tiles drawn from a bitmap table. Wraps `LCDTileMap`.
|
||||||
@@ -15,11 +15,11 @@ extension Graphics {
|
|||||||
private var retainedImageTable: BitmapTable?
|
private var retainedImageTable: BitmapTable?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
pointer = tilemapAPI.newTilemap.unsafelyUnwrapped().unsafelyUnwrapped
|
pointer = tilemapAPI.pointee.newTilemap.unsafelyUnwrapped().unsafelyUnwrapped
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
tilemapAPI.freeTilemap.unsafelyUnwrapped(pointer)
|
tilemapAPI.pointee.freeTilemap.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The bitmap table the tile indexes refer to.
|
/// The bitmap table the tile indexes refer to.
|
||||||
@@ -27,26 +27,26 @@ extension Graphics {
|
|||||||
get { retainedImageTable }
|
get { retainedImageTable }
|
||||||
set {
|
set {
|
||||||
retainedImageTable = newValue
|
retainedImageTable = newValue
|
||||||
tilemapAPI.setImageTable.unsafelyUnwrapped(pointer, newValue?.pointer)
|
tilemapAPI.pointee.setImageTable.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the tilemap's size in tiles.
|
/// Sets the tilemap's size in tiles.
|
||||||
public func setSize(tilesWide: Int, tilesHigh: Int) {
|
public func setSize(tilesWide: Int, tilesHigh: Int) {
|
||||||
tilemapAPI.setSize.unsafelyUnwrapped(pointer, Int32(tilesWide), Int32(tilesHigh))
|
tilemapAPI.pointee.setSize.unsafelyUnwrapped(pointer, Int32(tilesWide), Int32(tilesHigh))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tilemap's size in tiles.
|
/// The tilemap's size in tiles.
|
||||||
public var size: (tilesWide: Int, tilesHigh: Int) {
|
public var size: (tilesWide: Int, tilesHigh: Int) {
|
||||||
var wide: Int32 = 0, high: Int32 = 0
|
var wide: Int32 = 0, high: Int32 = 0
|
||||||
tilemapAPI.getSize.unsafelyUnwrapped(pointer, &wide, &high)
|
tilemapAPI.pointee.getSize.unsafelyUnwrapped(pointer, &wide, &high)
|
||||||
return (Int(wide), Int(high))
|
return (Int(wide), Int(high))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tilemap's total size in pixels.
|
/// The tilemap's total size in pixels.
|
||||||
public var pixelSize: (width: Int, height: Int) {
|
public var pixelSize: (width: Int, height: Int) {
|
||||||
var width: UInt32 = 0, height: UInt32 = 0
|
var width: UInt32 = 0, height: UInt32 = 0
|
||||||
tilemapAPI.getPixelSize.unsafelyUnwrapped(pointer, &width, &height)
|
tilemapAPI.pointee.getPixelSize.unsafelyUnwrapped(pointer, &width, &height)
|
||||||
return (Int(width), Int(height))
|
return (Int(width), Int(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,25 +55,25 @@ extension Graphics {
|
|||||||
public func setTiles(_ indexes: [UInt16], rowWidth: Int) {
|
public func setTiles(_ indexes: [UInt16], rowWidth: Int) {
|
||||||
var indexes = indexes
|
var indexes = indexes
|
||||||
indexes.withUnsafeMutableBufferPointer { buffer in
|
indexes.withUnsafeMutableBufferPointer { buffer in
|
||||||
tilemapAPI.setTiles.unsafelyUnwrapped(pointer, buffer.baseAddress,
|
tilemapAPI.pointee.setTiles.unsafelyUnwrapped(pointer, buffer.baseAddress,
|
||||||
Int32(buffer.count), Int32(rowWidth))
|
Int32(buffer.count), Int32(rowWidth))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the tile index at position (x, y).
|
/// Sets the tile index at position (x, y).
|
||||||
public func setTile(x: Int, y: Int, index: UInt16) {
|
public func setTile(x: Int, y: Int, index: UInt16) {
|
||||||
tilemapAPI.setTileAtPosition.unsafelyUnwrapped(pointer, Int32(x), Int32(y), index)
|
tilemapAPI.pointee.setTileAtPosition.unsafelyUnwrapped(pointer, Int32(x), Int32(y), index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tile index at position (x, y), or `nil` if out of bounds.
|
/// The tile index at position (x, y), or `nil` if out of bounds.
|
||||||
public func tile(x: Int, y: Int) -> Int? {
|
public func tile(x: Int, y: Int) -> Int? {
|
||||||
let index = tilemapAPI.getTileAtPosition.unsafelyUnwrapped(pointer, Int32(x), Int32(y))
|
let index = tilemapAPI.pointee.getTileAtPosition.unsafelyUnwrapped(pointer, Int32(x), Int32(y))
|
||||||
return index < 0 ? nil : Int(index)
|
return index < 0 ? nil : Int(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the tilemap with its upper-left corner at (x, y).
|
/// Draws the tilemap with its upper-left corner at (x, y).
|
||||||
public func draw(x: Float, y: Float) {
|
public func draw(x: Float, y: Float) {
|
||||||
tilemapAPI.drawAtPoint.unsafelyUnwrapped(pointer, x, y)
|
tilemapAPI.pointee.drawAtPoint.unsafelyUnwrapped(pointer, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var videoAPI: playdate_video { gfx.video.pointee }
|
private var videoAPI: UnsafePointer<playdate_video> { gfx.pointee.video.unsafelyUnwrapped }
|
||||||
private var streamAPI: playdate_videostream { gfx.videostream.pointee }
|
private var streamAPI: UnsafePointer<playdate_videostream> { gfx.pointee.videostream.unsafelyUnwrapped }
|
||||||
|
|
||||||
extension Graphics {
|
extension Graphics {
|
||||||
/// Plays .pdv video files. Wraps `LCDVideoPlayer`.
|
/// Plays .pdv video files. Wraps `LCDVideoPlayer`.
|
||||||
@@ -24,7 +24,7 @@ extension Graphics {
|
|||||||
|
|
||||||
/// Opens the .pdv file at `path`.
|
/// Opens the .pdv file at `path`.
|
||||||
public convenience init(path: String) throws(PlaydateError) {
|
public convenience init(path: String) throws(PlaydateError) {
|
||||||
let pointer = path.withPlaydateCString { videoAPI.loadVideo.unsafelyUnwrapped($0) }
|
let pointer = path.withPlaydateCString { videoAPI.pointee.loadVideo.unsafelyUnwrapped($0) }
|
||||||
guard let pointer else {
|
guard let pointer else {
|
||||||
throw PlaydateError(message: "unable to load video: \(path)")
|
throw PlaydateError(message: "unable to load video: \(path)")
|
||||||
}
|
}
|
||||||
@@ -33,13 +33,13 @@ extension Graphics {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
videoAPI.freePlayer.unsafelyUnwrapped(pointer)
|
videoAPI.pointee.freePlayer.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the bitmap the video renders into.
|
/// Sets the bitmap the video renders into.
|
||||||
public func setContext(_ context: Bitmap) throws(PlaydateError) {
|
public func setContext(_ context: Bitmap) throws(PlaydateError) {
|
||||||
guard videoAPI.setContext.unsafelyUnwrapped(pointer, context.pointer) != 0 else {
|
guard videoAPI.pointee.setContext.unsafelyUnwrapped(pointer, context.pointer) != 0 else {
|
||||||
throw PlaydateError(message: error ?? "unable to set video context")
|
throw PlaydateError(message: error ?? "unable to set video context")
|
||||||
}
|
}
|
||||||
retainedContext = context
|
retainedContext = context
|
||||||
@@ -47,33 +47,33 @@ extension Graphics {
|
|||||||
|
|
||||||
/// The bitmap the video renders into.
|
/// The bitmap the video renders into.
|
||||||
public var context: Bitmap? {
|
public var context: Bitmap? {
|
||||||
guard let context = videoAPI.getContext.unsafelyUnwrapped(pointer) else { return nil }
|
guard let context = videoAPI.pointee.getContext.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Bitmap(pointer: context, isOwned: false)
|
return Bitmap(pointer: context, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders directly into the display framebuffer.
|
/// Renders directly into the display framebuffer.
|
||||||
public func useScreenContext() {
|
public func useScreenContext() {
|
||||||
retainedContext = nil
|
retainedContext = nil
|
||||||
videoAPI.useScreenContext.unsafelyUnwrapped(pointer)
|
videoAPI.pointee.useScreenContext.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders frame `frame` into the current context.
|
/// Renders frame `frame` into the current context.
|
||||||
public func renderFrame(_ frame: Int) throws(PlaydateError) {
|
public func renderFrame(_ frame: Int) throws(PlaydateError) {
|
||||||
guard videoAPI.renderFrame.unsafelyUnwrapped(pointer, Int32(frame)) != 0 else {
|
guard videoAPI.pointee.renderFrame.unsafelyUnwrapped(pointer, Int32(frame)) != 0 else {
|
||||||
throw PlaydateError(message: error ?? "unable to render frame \(frame)")
|
throw PlaydateError(message: error ?? "unable to render frame \(frame)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The most recent error message, if any.
|
/// The most recent error message, if any.
|
||||||
public var error: String? {
|
public var error: String? {
|
||||||
String(playdateCString: videoAPI.getError.unsafelyUnwrapped(pointer))
|
String(playdateCString: videoAPI.pointee.getError.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The video's dimensions, frame rate, frame count, and current frame.
|
/// The video's dimensions, frame rate, frame count, and current frame.
|
||||||
public var info: (width: Int, height: Int, frameRate: Float, frameCount: Int, currentFrame: Int) {
|
public var info: (width: Int, height: Int, frameRate: Float, frameCount: Int, currentFrame: Int) {
|
||||||
var width: Int32 = 0, height: Int32 = 0, frameCount: Int32 = 0, currentFrame: Int32 = 0
|
var width: Int32 = 0, height: Int32 = 0, frameCount: Int32 = 0, currentFrame: Int32 = 0
|
||||||
var frameRate: Float = 0
|
var frameRate: Float = 0
|
||||||
videoAPI.getInfo.unsafelyUnwrapped(pointer, &width, &height, &frameRate,
|
videoAPI.pointee.getInfo.unsafelyUnwrapped(pointer, &width, &height, &frameRate,
|
||||||
&frameCount, ¤tFrame)
|
&frameCount, ¤tFrame)
|
||||||
return (Int(width), Int(height), frameRate, Int(frameCount), Int(currentFrame))
|
return (Int(width), Int(height), frameRate, Int(frameCount), Int(currentFrame))
|
||||||
}
|
}
|
||||||
@@ -87,62 +87,62 @@ extension Graphics {
|
|||||||
private var retainedSource: AnyObject?
|
private var retainedSource: AnyObject?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
pointer = streamAPI.newPlayer.unsafelyUnwrapped().unsafelyUnwrapped
|
pointer = streamAPI.pointee.newPlayer.unsafelyUnwrapped().unsafelyUnwrapped
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
streamAPI.freePlayer.unsafelyUnwrapped(pointer)
|
streamAPI.pointee.freePlayer.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the sizes of the stream's video and audio buffers, in bytes.
|
/// Sets the sizes of the stream's video and audio buffers, in bytes.
|
||||||
public func setBufferSize(video: Int, audio: Int) {
|
public func setBufferSize(video: Int, audio: Int) {
|
||||||
streamAPI.setBufferSize.unsafelyUnwrapped(pointer, Int32(video), Int32(audio))
|
streamAPI.pointee.setBufferSize.unsafelyUnwrapped(pointer, Int32(video), Int32(audio))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Streams from an open file.
|
/// Streams from an open file.
|
||||||
public func setFile(_ file: File.Handle) {
|
public func setFile(_ file: File.Handle) {
|
||||||
retainedSource = file
|
retainedSource = file
|
||||||
streamAPI.setFile.unsafelyUnwrapped(pointer, file.pointer)
|
streamAPI.pointee.setFile.unsafelyUnwrapped(pointer, file.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Streams from an HTTP connection.
|
/// Streams from an HTTP connection.
|
||||||
public func setHTTPConnection(_ connection: Network.HTTPConnection) {
|
public func setHTTPConnection(_ connection: Network.HTTPConnection) {
|
||||||
retainedSource = connection
|
retainedSource = connection
|
||||||
streamAPI.setHTTPConnection.unsafelyUnwrapped(pointer, connection.pointer)
|
streamAPI.pointee.setHTTPConnection.unsafelyUnwrapped(pointer, connection.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Streams from a TCP connection.
|
/// Streams from a TCP connection.
|
||||||
public func setTCPConnection(_ connection: Network.TCPConnection) {
|
public func setTCPConnection(_ connection: Network.TCPConnection) {
|
||||||
retainedSource = connection
|
retainedSource = connection
|
||||||
streamAPI.setTCPConnection.unsafelyUnwrapped(pointer, connection.pointer)
|
streamAPI.pointee.setTCPConnection.unsafelyUnwrapped(pointer, connection.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The player used for the stream's audio track. Owned by the stream.
|
/// The player used for the stream's audio track. Owned by the stream.
|
||||||
public var filePlayer: Sound.FilePlayer? {
|
public var filePlayer: Sound.FilePlayer? {
|
||||||
guard let player = streamAPI.getFilePlayer.unsafelyUnwrapped(pointer) else { return nil }
|
guard let player = streamAPI.pointee.getFilePlayer.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Sound.FilePlayer(pointer: player, isOwned: false)
|
return Sound.FilePlayer(pointer: player, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The player used for the stream's video track. Owned by the stream.
|
/// The player used for the stream's video track. Owned by the stream.
|
||||||
public var videoPlayer: VideoPlayer? {
|
public var videoPlayer: VideoPlayer? {
|
||||||
guard let player = streamAPI.getVideoPlayer.unsafelyUnwrapped(pointer) else { return nil }
|
guard let player = streamAPI.pointee.getVideoPlayer.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return VideoPlayer(pointer: player, isOwned: false)
|
return VideoPlayer(pointer: player, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advances the stream. Returns `true` if a frame was drawn.
|
/// Advances the stream. Returns `true` if a frame was drawn.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func update() -> Bool {
|
public func update() -> Bool {
|
||||||
streamAPI.update.unsafelyUnwrapped(pointer)
|
streamAPI.pointee.update.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of video frames currently buffered.
|
/// The number of video frames currently buffered.
|
||||||
public var bufferedFrameCount: Int {
|
public var bufferedFrameCount: Int {
|
||||||
Int(streamAPI.getBufferedFrameCount.unsafelyUnwrapped(pointer))
|
Int(streamAPI.pointee.getBufferedFrameCount.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The total number of bytes read from the source.
|
/// The total number of bytes read from the source.
|
||||||
public var bytesRead: UInt32 {
|
public var bytesRead: UInt32 {
|
||||||
streamAPI.getBytesRead.unsafelyUnwrapped(pointer)
|
streamAPI.pointee.getBytesRead.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var jsonAPI: playdate_json { Playdate.api.json.pointee }
|
private var jsonAPI: UnsafePointer<playdate_json> { Playdate.jsonAPI }
|
||||||
|
|
||||||
/// The JSON API: decoding to and encoding from a `Value` tree.
|
/// The JSON API: decoding to and encoding from a `Value` tree.
|
||||||
public enum JSON {}
|
public enum JSON {}
|
||||||
@@ -112,7 +112,7 @@ extension JSON {
|
|||||||
var outval = json_value()
|
var outval = json_value()
|
||||||
let ok = jsonString.withPlaydateCString { cString in
|
let ok = jsonString.withPlaydateCString { cString in
|
||||||
withExtendedLifetime(context) {
|
withExtendedLifetime(context) {
|
||||||
jsonAPI.decodeString.unsafelyUnwrapped(&decoder, cString, &outval) != 0
|
jsonAPI.pointee.decodeString.unsafelyUnwrapped(&decoder, cString, &outval) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guard ok else {
|
guard ok else {
|
||||||
@@ -141,7 +141,7 @@ extension JSON {
|
|||||||
var outval = json_value()
|
var outval = json_value()
|
||||||
let ok = withExtendedLifetime(context) {
|
let ok = withExtendedLifetime(context) {
|
||||||
withExtendedLifetime(file) {
|
withExtendedLifetime(file) {
|
||||||
jsonAPI.decode.unsafelyUnwrapped(&decoder, reader, &outval) != 0
|
jsonAPI.pointee.decode.unsafelyUnwrapped(&decoder, reader, &outval) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guard ok else {
|
guard ok else {
|
||||||
@@ -172,7 +172,7 @@ extension JSON {
|
|||||||
private let output = Output()
|
private let output = Output()
|
||||||
|
|
||||||
public init(pretty: Bool = false) {
|
public init(pretty: Bool = false) {
|
||||||
jsonAPI.initEncoder.unsafelyUnwrapped(&encoder, { userdata, string, length in
|
jsonAPI.pointee.initEncoder.unsafelyUnwrapped(&encoder, { userdata, string, length in
|
||||||
guard let userdata, let string else { return }
|
guard let userdata, let string else { return }
|
||||||
let output = Unmanaged<Output>.fromOpaque(userdata).takeUnretainedValue()
|
let output = Unmanaged<Output>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
let bytes = UnsafeRawBufferPointer(start: string, count: Int(length))
|
let bytes = UnsafeRawBufferPointer(start: string, count: Int(length))
|
||||||
|
|||||||
+32
-32
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
public import CPlaydate
|
public import CPlaydate
|
||||||
|
|
||||||
private var luaAPI: playdate_lua { Playdate.api.lua.pointee }
|
private var luaAPI: UnsafePointer<playdate_lua> { Playdate.luaAPI }
|
||||||
|
|
||||||
/// The Lua bridge: registering C functions and classes, and exchanging
|
/// The Lua bridge: registering C functions and classes, and exchanging
|
||||||
/// values with Lua code.
|
/// values with Lua code.
|
||||||
@@ -59,7 +59,7 @@ extension Lua {
|
|||||||
public static func addFunction(_ function: CFunction, name: String) throws(PlaydateError) {
|
public static func addFunction(_ function: CFunction, name: String) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
let ok = name.withPlaydateCString {
|
let ok = name.withPlaydateCString {
|
||||||
luaAPI.addFunction.unsafelyUnwrapped(function, $0, &error) != 0
|
luaAPI.pointee.addFunction.unsafelyUnwrapped(function, $0, &error) != 0
|
||||||
}
|
}
|
||||||
if !ok { throw PlaydateError(cString: error) }
|
if !ok { throw PlaydateError(cString: error) }
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ extension Lua {
|
|||||||
|
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
let ok = name.withPlaydateCString {
|
let ok = name.withPlaydateCString {
|
||||||
luaAPI.registerClass.unsafelyUnwrapped($0, registrationsBuffer,
|
luaAPI.pointee.registerClass.unsafelyUnwrapped($0, registrationsBuffer,
|
||||||
values.isEmpty ? nil : constantsBuffer,
|
values.isEmpty ? nil : constantsBuffer,
|
||||||
isStatic ? 1 : 0, &error) != 0
|
isStatic ? 1 : 0, &error) != 0
|
||||||
}
|
}
|
||||||
@@ -110,64 +110,64 @@ extension Lua {
|
|||||||
|
|
||||||
/// Pushes a function onto the stack, e.g. for `setUserValue`.
|
/// Pushes a function onto the stack, e.g. for `setUserValue`.
|
||||||
public static func pushFunction(_ function: CFunction) {
|
public static func pushFunction(_ function: CFunction) {
|
||||||
luaAPI.pushFunction.unsafelyUnwrapped(function)
|
luaAPI.pointee.pushFunction.unsafelyUnwrapped(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From a class's `__index` callback: looks up the key in the instance
|
/// From a class's `__index` callback: looks up the key in the instance
|
||||||
/// metatable first. Returns 1 if a value was found.
|
/// metatable first. Returns 1 if a value was found.
|
||||||
public static func indexMetatable() -> Bool {
|
public static func indexMetatable() -> Bool {
|
||||||
luaAPI.indexMetatable.unsafelyUnwrapped() != 0
|
luaAPI.pointee.indexMetatable.unsafelyUnwrapped() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pauses the Lua runtime.
|
/// Pauses the Lua runtime.
|
||||||
public static func stop() {
|
public static func stop() {
|
||||||
luaAPI.stop.unsafelyUnwrapped()
|
luaAPI.pointee.stop.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resumes the Lua runtime.
|
/// Resumes the Lua runtime.
|
||||||
public static func start() {
|
public static func start() {
|
||||||
luaAPI.start.unsafelyUnwrapped()
|
luaAPI.pointee.start.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Arguments
|
// MARK: - Arguments
|
||||||
|
|
||||||
/// The number of arguments the Lua caller passed. Positions are 1-based.
|
/// The number of arguments the Lua caller passed. Positions are 1-based.
|
||||||
public static var argumentCount: Int {
|
public static var argumentCount: Int {
|
||||||
Int(luaAPI.getArgCount.unsafelyUnwrapped())
|
Int(luaAPI.pointee.getArgCount.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of the argument at 1-based `position`; for objects, also the
|
/// The type of the argument at 1-based `position`; for objects, also the
|
||||||
/// class name.
|
/// class name.
|
||||||
public static func argumentType(at position: Int) -> (kind: Kind, className: String?) {
|
public static func argumentType(at position: Int) -> (kind: Kind, className: String?) {
|
||||||
var className: UnsafePointer<CChar>?
|
var className: UnsafePointer<CChar>?
|
||||||
let type = luaAPI.getArgType.unsafelyUnwrapped(Int32(position), &className)
|
let type = luaAPI.pointee.getArgType.unsafelyUnwrapped(Int32(position), &className)
|
||||||
return (Kind(type), String(playdateCString: className))
|
return (Kind(type), String(playdateCString: className))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func argumentIsNil(at position: Int) -> Bool {
|
public static func argumentIsNil(at position: Int) -> Bool {
|
||||||
luaAPI.argIsNil.unsafelyUnwrapped(Int32(position)) != 0
|
luaAPI.pointee.argIsNil.unsafelyUnwrapped(Int32(position)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func boolArgument(at position: Int) -> Bool {
|
public static func boolArgument(at position: Int) -> Bool {
|
||||||
luaAPI.getArgBool.unsafelyUnwrapped(Int32(position)) != 0
|
luaAPI.pointee.getArgBool.unsafelyUnwrapped(Int32(position)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func intArgument(at position: Int) -> Int {
|
public static func intArgument(at position: Int) -> Int {
|
||||||
Int(luaAPI.getArgInt.unsafelyUnwrapped(Int32(position)))
|
Int(luaAPI.pointee.getArgInt.unsafelyUnwrapped(Int32(position)))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func floatArgument(at position: Int) -> Float {
|
public static func floatArgument(at position: Int) -> Float {
|
||||||
luaAPI.getArgFloat.unsafelyUnwrapped(Int32(position))
|
luaAPI.pointee.getArgFloat.unsafelyUnwrapped(Int32(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func stringArgument(at position: Int) -> String? {
|
public static func stringArgument(at position: Int) -> String? {
|
||||||
String(playdateCString: luaAPI.getArgString.unsafelyUnwrapped(Int32(position)))
|
String(playdateCString: luaAPI.pointee.getArgString.unsafelyUnwrapped(Int32(position)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The argument as raw bytes (which may contain embedded zeros).
|
/// The argument as raw bytes (which may contain embedded zeros).
|
||||||
public static func bytesArgument(at position: Int) -> [UInt8]? {
|
public static func bytesArgument(at position: Int) -> [UInt8]? {
|
||||||
var length = 0
|
var length = 0
|
||||||
guard let bytes = luaAPI.getArgBytes.unsafelyUnwrapped(Int32(position), &length) else {
|
guard let bytes = luaAPI.pointee.getArgBytes.unsafelyUnwrapped(Int32(position), &length) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let buffer = UnsafeRawBufferPointer(start: bytes, count: length)
|
let buffer = UnsafeRawBufferPointer(start: bytes, count: length)
|
||||||
@@ -181,58 +181,58 @@ extension Lua {
|
|||||||
let cType = type.copiedPlaydateCString()
|
let cType = type.copiedPlaydateCString()
|
||||||
defer { cType.deallocate() }
|
defer { cType.deallocate() }
|
||||||
var userdataObject: OpaquePointer?
|
var userdataObject: OpaquePointer?
|
||||||
let object = luaAPI.getArgObject.unsafelyUnwrapped(Int32(position), cType, &userdataObject)
|
let object = luaAPI.pointee.getArgObject.unsafelyUnwrapped(Int32(position), cType, &userdataObject)
|
||||||
return (object, userdataObject.map { UDObject(pointer: $0) })
|
return (object, userdataObject.map { UDObject(pointer: $0) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The argument as a bitmap. References an object owned by Lua; retain
|
/// The argument as a bitmap. References an object owned by Lua; retain
|
||||||
/// the Lua value while using it.
|
/// the Lua value while using it.
|
||||||
public static func bitmapArgument(at position: Int) -> Graphics.Bitmap? {
|
public static func bitmapArgument(at position: Int) -> Graphics.Bitmap? {
|
||||||
guard let bitmap = luaAPI.getBitmap.unsafelyUnwrapped(Int32(position)) else { return nil }
|
guard let bitmap = luaAPI.pointee.getBitmap.unsafelyUnwrapped(Int32(position)) else { return nil }
|
||||||
return Graphics.Bitmap(pointer: bitmap, isOwned: false)
|
return Graphics.Bitmap(pointer: bitmap, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The argument as a sprite.
|
/// The argument as a sprite.
|
||||||
public static func spriteArgument(at position: Int) -> Sprite? {
|
public static func spriteArgument(at position: Int) -> Sprite? {
|
||||||
guard let sprite = luaAPI.getSprite.unsafelyUnwrapped(Int32(position)) else { return nil }
|
guard let sprite = luaAPI.pointee.getSprite.unsafelyUnwrapped(Int32(position)) else { return nil }
|
||||||
return Sprite.wrapper(for: sprite)
|
return Sprite.wrapper(for: sprite)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Return values
|
// MARK: - Return values
|
||||||
|
|
||||||
public static func pushNil() {
|
public static func pushNil() {
|
||||||
luaAPI.pushNil.unsafelyUnwrapped()
|
luaAPI.pointee.pushNil.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(_ value: Bool) {
|
public static func push(_ value: Bool) {
|
||||||
luaAPI.pushBool.unsafelyUnwrapped(value ? 1 : 0)
|
luaAPI.pointee.pushBool.unsafelyUnwrapped(value ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(_ value: Int) {
|
public static func push(_ value: Int) {
|
||||||
luaAPI.pushInt.unsafelyUnwrapped(Int32(value))
|
luaAPI.pointee.pushInt.unsafelyUnwrapped(Int32(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(_ value: Float) {
|
public static func push(_ value: Float) {
|
||||||
luaAPI.pushFloat.unsafelyUnwrapped(value)
|
luaAPI.pointee.pushFloat.unsafelyUnwrapped(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(_ value: String) {
|
public static func push(_ value: String) {
|
||||||
value.withPlaydateCString { luaAPI.pushString.unsafelyUnwrapped($0) }
|
value.withPlaydateCString { luaAPI.pointee.pushString.unsafelyUnwrapped($0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(bytes: [UInt8]) {
|
public static func push(bytes: [UInt8]) {
|
||||||
bytes.withUnsafeBytes { buffer in
|
bytes.withUnsafeBytes { buffer in
|
||||||
luaAPI.pushBytes.unsafelyUnwrapped(
|
luaAPI.pointee.pushBytes.unsafelyUnwrapped(
|
||||||
buffer.baseAddress?.assumingMemoryBound(to: CChar.self), buffer.count)
|
buffer.baseAddress?.assumingMemoryBound(to: CChar.self), buffer.count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(_ bitmap: Graphics.Bitmap) {
|
public static func push(_ bitmap: Graphics.Bitmap) {
|
||||||
luaAPI.pushBitmap.unsafelyUnwrapped(bitmap.pointer)
|
luaAPI.pointee.pushBitmap.unsafelyUnwrapped(bitmap.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func push(_ sprite: Sprite) {
|
public static func push(_ sprite: Sprite) {
|
||||||
luaAPI.pushSprite.unsafelyUnwrapped(sprite.pointer)
|
luaAPI.pointee.pushSprite.unsafelyUnwrapped(sprite.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps `object` in a Lua instance of class `type` and pushes it, with
|
/// Wraps `object` in a Lua instance of class `type` and pushes it, with
|
||||||
@@ -242,7 +242,7 @@ extension Lua {
|
|||||||
valueCount: Int = 0) -> UDObject? {
|
valueCount: Int = 0) -> UDObject? {
|
||||||
let cType = type.copiedPlaydateCString()
|
let cType = type.copiedPlaydateCString()
|
||||||
defer { cType.deallocate() }
|
defer { cType.deallocate() }
|
||||||
guard let pointer = luaAPI.pushObject.unsafelyUnwrapped(object, cType, Int32(valueCount)) else {
|
guard let pointer = luaAPI.pointee.pushObject.unsafelyUnwrapped(object, cType, Int32(valueCount)) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return UDObject(pointer: pointer)
|
return UDObject(pointer: pointer)
|
||||||
@@ -255,24 +255,24 @@ extension Lua {
|
|||||||
/// Prevents the object from being garbage-collected until `release()`.
|
/// Prevents the object from being garbage-collected until `release()`.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func retain() -> UDObject {
|
public func retain() -> UDObject {
|
||||||
UDObject(pointer: luaAPI.retainObject.unsafelyUnwrapped(pointer).unsafelyUnwrapped)
|
UDObject(pointer: luaAPI.pointee.retainObject.unsafelyUnwrapped(pointer).unsafelyUnwrapped)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func release() {
|
public func release() {
|
||||||
luaAPI.releaseObject.unsafelyUnwrapped(pointer)
|
luaAPI.pointee.releaseObject.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pops the value on top of the stack and stores it in the object's
|
/// Pops the value on top of the stack and stores it in the object's
|
||||||
/// user-value `slot` (1-based).
|
/// user-value `slot` (1-based).
|
||||||
public func setUserValue(slot: UInt32) {
|
public func setUserValue(slot: UInt32) {
|
||||||
luaAPI.setUserValue.unsafelyUnwrapped(pointer, slot)
|
luaAPI.pointee.setUserValue.unsafelyUnwrapped(pointer, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes the value in user-value `slot` onto the stack and returns
|
/// Pushes the value in user-value `slot` onto the stack and returns
|
||||||
/// its stack position, or `nil` if there is none.
|
/// its stack position, or `nil` if there is none.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func getUserValue(slot: UInt32) -> Int? {
|
public func getUserValue(slot: UInt32) -> Int? {
|
||||||
let position = luaAPI.getUserValue.unsafelyUnwrapped(pointer, slot)
|
let position = luaAPI.pointee.getUserValue.unsafelyUnwrapped(pointer, slot)
|
||||||
return position == 0 ? nil : Int(position)
|
return position == 0 ? nil : Int(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ extension Lua {
|
|||||||
public static func callFunction(_ name: String, argumentCount: Int = 0) throws(PlaydateError) {
|
public static func callFunction(_ name: String, argumentCount: Int = 0) throws(PlaydateError) {
|
||||||
var error: UnsafePointer<CChar>?
|
var error: UnsafePointer<CChar>?
|
||||||
let ok = name.withPlaydateCString {
|
let ok = name.withPlaydateCString {
|
||||||
luaAPI.callFunction.unsafelyUnwrapped($0, Int32(argumentCount), &error) != 0
|
luaAPI.pointee.callFunction.unsafelyUnwrapped($0, Int32(argumentCount), &error) != 0
|
||||||
}
|
}
|
||||||
if !ok { throw PlaydateError(cString: error) }
|
if !ok { throw PlaydateError(cString: error) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var networkAPI: playdate_network { Playdate.api.network.pointee }
|
private var networkAPI: UnsafePointer<playdate_network> { Playdate.networkAPI }
|
||||||
private var httpAPI: playdate_http { networkAPI.http.pointee }
|
private var httpAPI: UnsafePointer<playdate_http> { networkAPI.pointee.http.unsafelyUnwrapped }
|
||||||
private var tcpAPI: playdate_tcp { networkAPI.tcp.pointee }
|
private var tcpAPI: UnsafePointer<playdate_tcp> { networkAPI.pointee.tcp.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// The network API: wifi status, HTTP, and TCP.
|
/// The network API: wifi status, HTTP, and TCP.
|
||||||
public enum Network {}
|
public enum Network {}
|
||||||
@@ -66,7 +66,7 @@ extension Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static var status: WifiStatus {
|
public static var status: WifiStatus {
|
||||||
WifiStatus(rawValue: networkAPI.getStatus.unsafelyUnwrapped().rawValue) ?? .notConnected
|
WifiStatus(rawValue: networkAPI.pointee.getStatus.unsafelyUnwrapped().rawValue) ?? .notConnected
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turns the wifi radio on or off. The completion receives `nil` on
|
/// Turns the wifi radio on or off. The completion receives `nil` on
|
||||||
@@ -74,13 +74,13 @@ extension Network {
|
|||||||
public static func setEnabled(_ enabled: Bool, completion: ((NetError?) -> Void)? = nil) {
|
public static func setEnabled(_ enabled: Bool, completion: ((NetError?) -> Void)? = nil) {
|
||||||
setEnabledCompletion = completion
|
setEnabledCompletion = completion
|
||||||
if completion != nil {
|
if completion != nil {
|
||||||
networkAPI.setEnabled.unsafelyUnwrapped(enabled, { error in
|
networkAPI.pointee.setEnabled.unsafelyUnwrapped(enabled, { error in
|
||||||
let completion = Network.setEnabledCompletion
|
let completion = Network.setEnabledCompletion
|
||||||
Network.setEnabledCompletion = nil
|
Network.setEnabledCompletion = nil
|
||||||
completion?(Network.optionalError(error))
|
completion?(Network.optionalError(error))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
networkAPI.setEnabled.unsafelyUnwrapped(enabled, nil)
|
networkAPI.pointee.setEnabled.unsafelyUnwrapped(enabled, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ extension Network {
|
|||||||
purpose: String? = nil,
|
purpose: String? = nil,
|
||||||
completion: @escaping (Bool) -> Void) -> AccessReply {
|
completion: @escaping (Bool) -> Void) -> AccessReply {
|
||||||
Network.requestAccess(
|
Network.requestAccess(
|
||||||
rawRequest: { httpAPI.requestAccess.unsafelyUnwrapped($0, $1, $2, $3, $4, $5) },
|
rawRequest: { httpAPI.pointee.requestAccess.unsafelyUnwrapped($0, $1, $2, $3, $4, $5) },
|
||||||
server: server, port: port, useSSL: useSSL, purpose: purpose,
|
server: server, port: port, useSSL: useSSL, purpose: purpose,
|
||||||
completion: completion)
|
completion: completion)
|
||||||
}
|
}
|
||||||
@@ -146,21 +146,21 @@ extension Network {
|
|||||||
/// granted.
|
/// granted.
|
||||||
public init?(server: String, port: Int = 443, useSSL: Bool = true) {
|
public init?(server: String, port: Int = 443, useSSL: Bool = true) {
|
||||||
let pointer = server.withPlaydateCString {
|
let pointer = server.withPlaydateCString {
|
||||||
httpAPI.newConnection.unsafelyUnwrapped($0, Int32(port), useSSL)
|
httpAPI.pointee.newConnection.unsafelyUnwrapped($0, Int32(port), useSSL)
|
||||||
}
|
}
|
||||||
guard let pointer else { return nil }
|
guard let pointer else { return nil }
|
||||||
self.pointer = pointer
|
self.pointer = pointer
|
||||||
httpAPI.setUserdata.unsafelyUnwrapped(pointer, Unmanaged.passUnretained(self).toOpaque())
|
httpAPI.pointee.setUserdata.unsafelyUnwrapped(pointer, Unmanaged.passUnretained(self).toOpaque())
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
httpAPI.setUserdata.unsafelyUnwrapped(pointer, nil)
|
httpAPI.pointee.setUserdata.unsafelyUnwrapped(pointer, nil)
|
||||||
httpAPI.release.unsafelyUnwrapped(pointer)
|
httpAPI.pointee.release.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func wrapper(for pointer: OpaquePointer?) -> HTTPConnection? {
|
private static func wrapper(for pointer: OpaquePointer?) -> HTTPConnection? {
|
||||||
guard let pointer,
|
guard let pointer,
|
||||||
let userdata = httpAPI.getUserdata.unsafelyUnwrapped(pointer) else { return nil }
|
let userdata = httpAPI.pointee.getUserdata.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Unmanaged<HTTPConnection>.fromOpaque(userdata).takeUnretainedValue()
|
return Unmanaged<HTTPConnection>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,27 +168,27 @@ extension Network {
|
|||||||
|
|
||||||
/// The time to wait for the connection to open, in milliseconds.
|
/// The time to wait for the connection to open, in milliseconds.
|
||||||
public func setConnectTimeout(milliseconds: Int) {
|
public func setConnectTimeout(milliseconds: Int) {
|
||||||
httpAPI.setConnectTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
httpAPI.pointee.setConnectTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to keep the connection open after a request completes.
|
/// Whether to keep the connection open after a request completes.
|
||||||
public func setKeepAlive(_ keepAlive: Bool) {
|
public func setKeepAlive(_ keepAlive: Bool) {
|
||||||
httpAPI.setKeepAlive.unsafelyUnwrapped(pointer, keepAlive)
|
httpAPI.pointee.setKeepAlive.unsafelyUnwrapped(pointer, keepAlive)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a `Range: bytes=start-end` header to future requests.
|
/// Adds a `Range: bytes=start-end` header to future requests.
|
||||||
public func setByteRange(start: Int, end: Int) {
|
public func setByteRange(start: Int, end: Int) {
|
||||||
httpAPI.setByteRange.unsafelyUnwrapped(pointer, Int32(start), Int32(end))
|
httpAPI.pointee.setByteRange.unsafelyUnwrapped(pointer, Int32(start), Int32(end))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The time to wait for incoming data, in milliseconds.
|
/// The time to wait for incoming data, in milliseconds.
|
||||||
public func setReadTimeout(milliseconds: Int) {
|
public func setReadTimeout(milliseconds: Int) {
|
||||||
httpAPI.setReadTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
httpAPI.pointee.setReadTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The size of the connection's read buffer, in bytes.
|
/// The size of the connection's read buffer, in bytes.
|
||||||
public func setReadBufferSize(bytes: Int) {
|
public func setReadBufferSize(bytes: Int) {
|
||||||
httpAPI.setReadBufferSize.unsafelyUnwrapped(pointer, Int32(bytes))
|
httpAPI.pointee.setReadBufferSize.unsafelyUnwrapped(pointer, Int32(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Requests
|
// MARK: Requests
|
||||||
@@ -198,7 +198,7 @@ extension Network {
|
|||||||
public func get(path: String, headers: String = "") throws(NetError) {
|
public func get(path: String, headers: String = "") throws(NetError) {
|
||||||
let error = path.withPlaydateCString { cPath in
|
let error = path.withPlaydateCString { cPath in
|
||||||
headers.withPlaydateCString { cHeaders in
|
headers.withPlaydateCString { cHeaders in
|
||||||
httpAPI.get.unsafelyUnwrapped(pointer, cPath, cHeaders, headers.utf8.count)
|
httpAPI.pointee.get.unsafelyUnwrapped(pointer, cPath, cHeaders, headers.utf8.count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try Network.check(error)
|
try Network.check(error)
|
||||||
@@ -209,7 +209,7 @@ extension Network {
|
|||||||
let error = path.withPlaydateCString { cPath in
|
let error = path.withPlaydateCString { cPath in
|
||||||
headers.withPlaydateCString { cHeaders in
|
headers.withPlaydateCString { cHeaders in
|
||||||
body.withUnsafeBytes { bodyBuffer in
|
body.withUnsafeBytes { bodyBuffer in
|
||||||
httpAPI.post.unsafelyUnwrapped(
|
httpAPI.pointee.post.unsafelyUnwrapped(
|
||||||
pointer, cPath, cHeaders, headers.utf8.count,
|
pointer, cPath, cHeaders, headers.utf8.count,
|
||||||
bodyBuffer.baseAddress?.assumingMemoryBound(to: CChar.self),
|
bodyBuffer.baseAddress?.assumingMemoryBound(to: CChar.self),
|
||||||
bodyBuffer.count)
|
bodyBuffer.count)
|
||||||
@@ -226,7 +226,7 @@ extension Network {
|
|||||||
path.withPlaydateCString { cPath in
|
path.withPlaydateCString { cPath in
|
||||||
headers.withPlaydateCString { cHeaders in
|
headers.withPlaydateCString { cHeaders in
|
||||||
body.withUnsafeBytes { bodyBuffer in
|
body.withUnsafeBytes { bodyBuffer in
|
||||||
httpAPI.query.unsafelyUnwrapped(
|
httpAPI.pointee.query.unsafelyUnwrapped(
|
||||||
pointer, cMethod, cPath, cHeaders, headers.utf8.count,
|
pointer, cMethod, cPath, cHeaders, headers.utf8.count,
|
||||||
bodyBuffer.baseAddress?.assumingMemoryBound(to: CChar.self),
|
bodyBuffer.baseAddress?.assumingMemoryBound(to: CChar.self),
|
||||||
bodyBuffer.count)
|
bodyBuffer.count)
|
||||||
@@ -241,31 +241,31 @@ extension Network {
|
|||||||
|
|
||||||
/// The last error on the connection, if any.
|
/// The last error on the connection, if any.
|
||||||
public var error: NetError? {
|
public var error: NetError? {
|
||||||
Network.optionalError(httpAPI.getError.unsafelyUnwrapped(pointer))
|
Network.optionalError(httpAPI.pointee.getError.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of bytes read of the current response, and the total
|
/// The number of bytes read of the current response, and the total
|
||||||
/// expected (0 if the response has no Content-Length).
|
/// expected (0 if the response has no Content-Length).
|
||||||
public var progress: (read: Int, total: Int) {
|
public var progress: (read: Int, total: Int) {
|
||||||
var read: Int32 = 0, total: Int32 = 0
|
var read: Int32 = 0, total: Int32 = 0
|
||||||
httpAPI.getProgress.unsafelyUnwrapped(pointer, &read, &total)
|
httpAPI.pointee.getProgress.unsafelyUnwrapped(pointer, &read, &total)
|
||||||
return (Int(read), Int(total))
|
return (Int(read), Int(total))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The HTTP status code of the response.
|
/// The HTTP status code of the response.
|
||||||
public var responseStatus: Int {
|
public var responseStatus: Int {
|
||||||
Int(httpAPI.getResponseStatus.unsafelyUnwrapped(pointer))
|
Int(httpAPI.pointee.getResponseStatus.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of response bytes available to read.
|
/// The number of response bytes available to read.
|
||||||
public var bytesAvailable: Int {
|
public var bytesAvailable: Int {
|
||||||
Int(httpAPI.getBytesAvailable.unsafelyUnwrapped(pointer))
|
Int(httpAPI.pointee.getBytesAvailable.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads up to `buffer.count` response bytes. Returns the number of
|
/// Reads up to `buffer.count` response bytes. Returns the number of
|
||||||
/// bytes read.
|
/// bytes read.
|
||||||
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(NetError) -> Int {
|
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(NetError) -> Int {
|
||||||
let result = httpAPI.read.unsafelyUnwrapped(pointer, buffer.baseAddress,
|
let result = httpAPI.pointee.read.unsafelyUnwrapped(pointer, buffer.baseAddress,
|
||||||
UInt32(buffer.count))
|
UInt32(buffer.count))
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
throw NetError(rawValue: result) ?? .unknown
|
throw NetError(rawValue: result) ?? .unknown
|
||||||
@@ -277,7 +277,7 @@ extension Network {
|
|||||||
public func read(length: Int) throws(NetError) -> [UInt8] {
|
public func read(length: Int) throws(NetError) -> [UInt8] {
|
||||||
var bytes = [UInt8](repeating: 0, count: length)
|
var bytes = [UInt8](repeating: 0, count: length)
|
||||||
let result = bytes.withUnsafeMutableBytes { buffer in
|
let result = bytes.withUnsafeMutableBytes { buffer in
|
||||||
httpAPI.read.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
httpAPI.pointee.read.unsafelyUnwrapped(pointer, buffer.baseAddress, UInt32(buffer.count))
|
||||||
}
|
}
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
throw NetError(rawValue: result) ?? .unknown
|
throw NetError(rawValue: result) ?? .unknown
|
||||||
@@ -288,7 +288,7 @@ extension Network {
|
|||||||
|
|
||||||
/// Closes the connection.
|
/// Closes the connection.
|
||||||
public func close() {
|
public func close() {
|
||||||
httpAPI.close.unsafelyUnwrapped(pointer)
|
httpAPI.pointee.close.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Callbacks
|
// MARK: Callbacks
|
||||||
@@ -297,14 +297,14 @@ extension Network {
|
|||||||
public func setHeaderReceivedCallback(_ callback: ((HTTPConnection, _ key: String, _ value: String) -> Void)?) {
|
public func setHeaderReceivedCallback(_ callback: ((HTTPConnection, _ key: String, _ value: String) -> Void)?) {
|
||||||
headerReceivedCallback = callback
|
headerReceivedCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
httpAPI.setHeaderReceivedCallback.unsafelyUnwrapped(pointer, { connection, key, value in
|
httpAPI.pointee.setHeaderReceivedCallback.unsafelyUnwrapped(pointer, { connection, key, value in
|
||||||
guard let wrapper = HTTPConnection.wrapper(for: connection),
|
guard let wrapper = HTTPConnection.wrapper(for: connection),
|
||||||
let key = String(playdateCString: key),
|
let key = String(playdateCString: key),
|
||||||
let value = String(playdateCString: value) else { return }
|
let value = String(playdateCString: value) else { return }
|
||||||
wrapper.headerReceivedCallback?(wrapper, key, value)
|
wrapper.headerReceivedCallback?(wrapper, key, value)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
httpAPI.setHeaderReceivedCallback.unsafelyUnwrapped(pointer, nil)
|
httpAPI.pointee.setHeaderReceivedCallback.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,12 +312,12 @@ extension Network {
|
|||||||
public func setHeadersReadCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
public func setHeadersReadCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
||||||
headersReadCallback = callback
|
headersReadCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
httpAPI.setHeadersReadCallback.unsafelyUnwrapped(pointer, { connection in
|
httpAPI.pointee.setHeadersReadCallback.unsafelyUnwrapped(pointer, { connection in
|
||||||
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
||||||
wrapper.headersReadCallback?(wrapper)
|
wrapper.headersReadCallback?(wrapper)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
httpAPI.setHeadersReadCallback.unsafelyUnwrapped(pointer, nil)
|
httpAPI.pointee.setHeadersReadCallback.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,12 +325,12 @@ extension Network {
|
|||||||
public func setResponseCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
public func setResponseCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
||||||
responseCallback = callback
|
responseCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
httpAPI.setResponseCallback.unsafelyUnwrapped(pointer, { connection in
|
httpAPI.pointee.setResponseCallback.unsafelyUnwrapped(pointer, { connection in
|
||||||
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
||||||
wrapper.responseCallback?(wrapper)
|
wrapper.responseCallback?(wrapper)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
httpAPI.setResponseCallback.unsafelyUnwrapped(pointer, nil)
|
httpAPI.pointee.setResponseCallback.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,12 +338,12 @@ extension Network {
|
|||||||
public func setRequestCompleteCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
public func setRequestCompleteCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
||||||
requestCompleteCallback = callback
|
requestCompleteCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
httpAPI.setRequestCompleteCallback.unsafelyUnwrapped(pointer, { connection in
|
httpAPI.pointee.setRequestCompleteCallback.unsafelyUnwrapped(pointer, { connection in
|
||||||
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
||||||
wrapper.requestCompleteCallback?(wrapper)
|
wrapper.requestCompleteCallback?(wrapper)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
httpAPI.setRequestCompleteCallback.unsafelyUnwrapped(pointer, nil)
|
httpAPI.pointee.setRequestCompleteCallback.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,12 +351,12 @@ extension Network {
|
|||||||
public func setConnectionClosedCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
public func setConnectionClosedCallback(_ callback: ((HTTPConnection) -> Void)?) {
|
||||||
connectionClosedCallback = callback
|
connectionClosedCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
httpAPI.setConnectionClosedCallback.unsafelyUnwrapped(pointer, { connection in
|
httpAPI.pointee.setConnectionClosedCallback.unsafelyUnwrapped(pointer, { connection in
|
||||||
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
guard let wrapper = HTTPConnection.wrapper(for: connection) else { return }
|
||||||
wrapper.connectionClosedCallback?(wrapper)
|
wrapper.connectionClosedCallback?(wrapper)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
httpAPI.setConnectionClosedCallback.unsafelyUnwrapped(pointer, nil)
|
httpAPI.pointee.setConnectionClosedCallback.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,7 +377,7 @@ extension Network {
|
|||||||
purpose: String? = nil,
|
purpose: String? = nil,
|
||||||
completion: @escaping (Bool) -> Void) -> AccessReply {
|
completion: @escaping (Bool) -> Void) -> AccessReply {
|
||||||
Network.requestAccess(
|
Network.requestAccess(
|
||||||
rawRequest: { tcpAPI.requestAccess.unsafelyUnwrapped($0, $1, $2, $3, $4, $5) },
|
rawRequest: { tcpAPI.pointee.requestAccess.unsafelyUnwrapped($0, $1, $2, $3, $4, $5) },
|
||||||
server: server, port: port, useSSL: useSSL, purpose: purpose,
|
server: server, port: port, useSSL: useSSL, purpose: purpose,
|
||||||
completion: completion)
|
completion: completion)
|
||||||
}
|
}
|
||||||
@@ -386,38 +386,38 @@ extension Network {
|
|||||||
/// granted. Call `open(_:)` to connect.
|
/// granted. Call `open(_:)` to connect.
|
||||||
public init?(server: String, port: Int, useSSL: Bool = true) {
|
public init?(server: String, port: Int, useSSL: Bool = true) {
|
||||||
let pointer = server.withPlaydateCString {
|
let pointer = server.withPlaydateCString {
|
||||||
tcpAPI.newConnection.unsafelyUnwrapped($0, Int32(port), useSSL)
|
tcpAPI.pointee.newConnection.unsafelyUnwrapped($0, Int32(port), useSSL)
|
||||||
}
|
}
|
||||||
guard let pointer else { return nil }
|
guard let pointer else { return nil }
|
||||||
self.pointer = pointer
|
self.pointer = pointer
|
||||||
tcpAPI.setUserdata.unsafelyUnwrapped(pointer, Unmanaged.passUnretained(self).toOpaque())
|
tcpAPI.pointee.setUserdata.unsafelyUnwrapped(pointer, Unmanaged.passUnretained(self).toOpaque())
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
tcpAPI.setUserdata.unsafelyUnwrapped(pointer, nil)
|
tcpAPI.pointee.setUserdata.unsafelyUnwrapped(pointer, nil)
|
||||||
tcpAPI.release.unsafelyUnwrapped(pointer)
|
tcpAPI.pointee.release.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func wrapper(for pointer: OpaquePointer?) -> TCPConnection? {
|
private static func wrapper(for pointer: OpaquePointer?) -> TCPConnection? {
|
||||||
guard let pointer,
|
guard let pointer,
|
||||||
let userdata = tcpAPI.getUserdata.unsafelyUnwrapped(pointer) else { return nil }
|
let userdata = tcpAPI.pointee.getUserdata.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Unmanaged<TCPConnection>.fromOpaque(userdata).takeUnretainedValue()
|
return Unmanaged<TCPConnection>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The last error on the connection, if any.
|
/// The last error on the connection, if any.
|
||||||
public var error: NetError? {
|
public var error: NetError? {
|
||||||
Network.optionalError(tcpAPI.getError.unsafelyUnwrapped(pointer))
|
Network.optionalError(tcpAPI.pointee.getError.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The time to wait for the connection to open, in milliseconds.
|
/// The time to wait for the connection to open, in milliseconds.
|
||||||
public func setConnectTimeout(milliseconds: Int) {
|
public func setConnectTimeout(milliseconds: Int) {
|
||||||
tcpAPI.setConnectTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
tcpAPI.pointee.setConnectTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens the connection. The completion receives `nil` on success.
|
/// Opens the connection. The completion receives `nil` on success.
|
||||||
public func open(_ completion: @escaping (TCPConnection, NetError?) -> Void) throws(NetError) {
|
public func open(_ completion: @escaping (TCPConnection, NetError?) -> Void) throws(NetError) {
|
||||||
openCompletion = completion
|
openCompletion = completion
|
||||||
let error = tcpAPI.open.unsafelyUnwrapped(pointer, { connection, error, _ in
|
let error = tcpAPI.pointee.open.unsafelyUnwrapped(pointer, { connection, error, _ in
|
||||||
guard let wrapper = TCPConnection.wrapper(for: connection) else { return }
|
guard let wrapper = TCPConnection.wrapper(for: connection) else { return }
|
||||||
let completion = wrapper.openCompletion
|
let completion = wrapper.openCompletion
|
||||||
wrapper.openCompletion = nil
|
wrapper.openCompletion = nil
|
||||||
@@ -428,7 +428,7 @@ extension Network {
|
|||||||
|
|
||||||
/// Closes the connection.
|
/// Closes the connection.
|
||||||
public func close() throws(NetError) {
|
public func close() throws(NetError) {
|
||||||
try Network.check(tcpAPI.close.unsafelyUnwrapped(pointer))
|
try Network.check(tcpAPI.pointee.close.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the connection closes, with the reason if it closed
|
/// Called when the connection closes, with the reason if it closed
|
||||||
@@ -436,39 +436,39 @@ extension Network {
|
|||||||
public func setConnectionClosedCallback(_ callback: ((TCPConnection, NetError?) -> Void)?) {
|
public func setConnectionClosedCallback(_ callback: ((TCPConnection, NetError?) -> Void)?) {
|
||||||
connectionClosedCallback = callback
|
connectionClosedCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
tcpAPI.setConnectionClosedCallback.unsafelyUnwrapped(pointer, { connection, error in
|
tcpAPI.pointee.setConnectionClosedCallback.unsafelyUnwrapped(pointer, { connection, error in
|
||||||
guard let wrapper = TCPConnection.wrapper(for: connection) else { return }
|
guard let wrapper = TCPConnection.wrapper(for: connection) else { return }
|
||||||
wrapper.connectionClosedCallback?(wrapper, Network.optionalError(error))
|
wrapper.connectionClosedCallback?(wrapper, Network.optionalError(error))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
tcpAPI.setConnectionClosedCallback.unsafelyUnwrapped(pointer, nil)
|
tcpAPI.pointee.setConnectionClosedCallback.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The time to wait for incoming data, in milliseconds.
|
/// The time to wait for incoming data, in milliseconds.
|
||||||
public func setReadTimeout(milliseconds: Int) {
|
public func setReadTimeout(milliseconds: Int) {
|
||||||
tcpAPI.setReadTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
tcpAPI.pointee.setReadTimeout.unsafelyUnwrapped(pointer, Int32(milliseconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The size of the connection's read buffer, in bytes.
|
/// The size of the connection's read buffer, in bytes.
|
||||||
public func setReadBufferSize(bytes: Int) {
|
public func setReadBufferSize(bytes: Int) {
|
||||||
tcpAPI.setReadBufferSize.unsafelyUnwrapped(pointer, Int32(bytes))
|
tcpAPI.pointee.setReadBufferSize.unsafelyUnwrapped(pointer, Int32(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of bytes available to read.
|
/// The number of bytes available to read.
|
||||||
public var bytesAvailable: Int {
|
public var bytesAvailable: Int {
|
||||||
Int(tcpAPI.getBytesAvailable.unsafelyUnwrapped(pointer))
|
Int(tcpAPI.pointee.getBytesAvailable.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of written bytes not yet sent on the wire.
|
/// The number of written bytes not yet sent on the wire.
|
||||||
public var sentBytesPending: Int {
|
public var sentBytesPending: Int {
|
||||||
Int(tcpAPI.getSentBytesPending.unsafelyUnwrapped(pointer))
|
Int(tcpAPI.pointee.getSentBytesPending.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads up to `buffer.count` bytes, waiting up to the read timeout.
|
/// Reads up to `buffer.count` bytes, waiting up to the read timeout.
|
||||||
/// Returns the number of bytes read.
|
/// Returns the number of bytes read.
|
||||||
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(NetError) -> Int {
|
public func read(into buffer: UnsafeMutableRawBufferPointer) throws(NetError) -> Int {
|
||||||
let result = tcpAPI.read.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
let result = tcpAPI.pointee.read.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
throw NetError(rawValue: result) ?? .unknown
|
throw NetError(rawValue: result) ?? .unknown
|
||||||
}
|
}
|
||||||
@@ -479,7 +479,7 @@ extension Network {
|
|||||||
public func read(length: Int) throws(NetError) -> [UInt8] {
|
public func read(length: Int) throws(NetError) -> [UInt8] {
|
||||||
var bytes = [UInt8](repeating: 0, count: length)
|
var bytes = [UInt8](repeating: 0, count: length)
|
||||||
let result = bytes.withUnsafeMutableBytes { buffer in
|
let result = bytes.withUnsafeMutableBytes { buffer in
|
||||||
tcpAPI.read.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
tcpAPI.pointee.read.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
||||||
}
|
}
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
throw NetError(rawValue: result) ?? .unknown
|
throw NetError(rawValue: result) ?? .unknown
|
||||||
@@ -492,7 +492,7 @@ extension Network {
|
|||||||
/// accepted.
|
/// accepted.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func write(_ buffer: UnsafeRawBufferPointer) throws(NetError) -> Int {
|
public func write(_ buffer: UnsafeRawBufferPointer) throws(NetError) -> Int {
|
||||||
let result = tcpAPI.write.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
let result = tcpAPI.pointee.write.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
throw NetError(rawValue: result) ?? .unknown
|
throw NetError(rawValue: result) ?? .unknown
|
||||||
}
|
}
|
||||||
@@ -504,7 +504,7 @@ extension Network {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public func write(_ bytes: [UInt8]) throws(NetError) -> Int {
|
public func write(_ bytes: [UInt8]) throws(NetError) -> Int {
|
||||||
let result = bytes.withUnsafeBytes { buffer in
|
let result = bytes.withUnsafeBytes { buffer in
|
||||||
tcpAPI.write.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
tcpAPI.pointee.write.unsafelyUnwrapped(pointer, buffer.baseAddress, buffer.count)
|
||||||
}
|
}
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
throw NetError(rawValue: result) ?? .unknown
|
throw NetError(rawValue: result) ?? .unknown
|
||||||
|
|||||||
@@ -24,6 +24,19 @@ public enum Playdate {
|
|||||||
/// need to pass the `PlaydateAPI*` back to C.
|
/// need to pass the `PlaydateAPI*` back to C.
|
||||||
public internal(set) nonisolated(unsafe) static var apiPointer: UnsafeMutablePointer<PlaydateAPI>!
|
public internal(set) nonisolated(unsafe) static var apiPointer: UnsafeMutablePointer<PlaydateAPI>!
|
||||||
|
|
||||||
|
// Sub-API pointers cached once at initialization, so wrapper calls are a
|
||||||
|
// single field load off a pointer instead of re-walking `api` per call.
|
||||||
|
nonisolated(unsafe) static var systemAPI: UnsafePointer<playdate_sys>!
|
||||||
|
nonisolated(unsafe) static var displayAPI: UnsafePointer<playdate_display>!
|
||||||
|
nonisolated(unsafe) static var graphicsAPI: UnsafePointer<playdate_graphics>!
|
||||||
|
nonisolated(unsafe) static var spriteAPI: UnsafePointer<playdate_sprite>!
|
||||||
|
nonisolated(unsafe) static var soundAPI: UnsafePointer<playdate_sound>!
|
||||||
|
nonisolated(unsafe) static var fileAPI: UnsafePointer<playdate_file>!
|
||||||
|
nonisolated(unsafe) static var jsonAPI: UnsafePointer<playdate_json>!
|
||||||
|
nonisolated(unsafe) static var luaAPI: UnsafePointer<playdate_lua>!
|
||||||
|
nonisolated(unsafe) static var scoreboardsAPI: UnsafePointer<playdate_scoreboards>!
|
||||||
|
nonisolated(unsafe) static var networkAPI: UnsafePointer<playdate_network>!
|
||||||
|
|
||||||
/// Stores the API pointer handed to the game's `eventHandler`.
|
/// Stores the API pointer handed to the game's `eventHandler`.
|
||||||
///
|
///
|
||||||
/// Call this first, on the `.initialize` event, before using any other
|
/// Call this first, on the `.initialize` event, before using any other
|
||||||
@@ -31,6 +44,16 @@ public enum Playdate {
|
|||||||
public static func initialize(with pointer: UnsafeMutableRawPointer) {
|
public static func initialize(with pointer: UnsafeMutableRawPointer) {
|
||||||
apiPointer = pointer.assumingMemoryBound(to: PlaydateAPI.self)
|
apiPointer = pointer.assumingMemoryBound(to: PlaydateAPI.self)
|
||||||
api = apiPointer.pointee
|
api = apiPointer.pointee
|
||||||
|
systemAPI = api.system
|
||||||
|
displayAPI = api.display
|
||||||
|
graphicsAPI = api.graphics
|
||||||
|
spriteAPI = api.sprite
|
||||||
|
soundAPI = api.sound
|
||||||
|
fileAPI = api.file
|
||||||
|
jsonAPI = api.json
|
||||||
|
luaAPI = api.lua
|
||||||
|
scoreboardsAPI = api.scoreboards
|
||||||
|
networkAPI = api.network
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var scoreboardsAPI: playdate_scoreboards { Playdate.api.scoreboards.pointee }
|
private var scoreboardsAPI: UnsafePointer<playdate_scoreboards> { Playdate.scoreboardsAPI }
|
||||||
|
|
||||||
/// The scoreboards API for games with online leaderboards.
|
/// The scoreboards API for games with online leaderboards.
|
||||||
public enum Scoreboards {}
|
public enum Scoreboards {}
|
||||||
@@ -102,7 +102,7 @@ extension Scoreboards {
|
|||||||
completion: @escaping (Result<Score, PlaydateError>) -> Void) -> Bool {
|
completion: @escaping (Result<Score, PlaydateError>) -> Void) -> Bool {
|
||||||
addScoreCompletion = completion
|
addScoreCompletion = completion
|
||||||
return boardID.withPlaydateCString { cBoardID in
|
return boardID.withPlaydateCString { cBoardID in
|
||||||
scoreboardsAPI.addScore.unsafelyUnwrapped(cBoardID, value, { score, errorMessage in
|
scoreboardsAPI.pointee.addScore.unsafelyUnwrapped(cBoardID, value, { score, errorMessage in
|
||||||
let completion = Scoreboards.addScoreCompletion
|
let completion = Scoreboards.addScoreCompletion
|
||||||
Scoreboards.addScoreCompletion = nil
|
Scoreboards.addScoreCompletion = nil
|
||||||
completion?(Scoreboards.result(score, errorMessage))
|
completion?(Scoreboards.result(score, errorMessage))
|
||||||
@@ -116,7 +116,7 @@ extension Scoreboards {
|
|||||||
completion: @escaping (Result<Score, PlaydateError>) -> Void) -> Bool {
|
completion: @escaping (Result<Score, PlaydateError>) -> Void) -> Bool {
|
||||||
personalBestCompletion = completion
|
personalBestCompletion = completion
|
||||||
return boardID.withPlaydateCString { cBoardID in
|
return boardID.withPlaydateCString { cBoardID in
|
||||||
scoreboardsAPI.getPersonalBest.unsafelyUnwrapped(cBoardID, { score, errorMessage in
|
scoreboardsAPI.pointee.getPersonalBest.unsafelyUnwrapped(cBoardID, { score, errorMessage in
|
||||||
let completion = Scoreboards.personalBestCompletion
|
let completion = Scoreboards.personalBestCompletion
|
||||||
Scoreboards.personalBestCompletion = nil
|
Scoreboards.personalBestCompletion = nil
|
||||||
completion?(Scoreboards.result(score, errorMessage))
|
completion?(Scoreboards.result(score, errorMessage))
|
||||||
@@ -128,7 +128,7 @@ extension Scoreboards {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public static func getScoreboards(completion: @escaping (Result<BoardsList, PlaydateError>) -> Void) -> Bool {
|
public static func getScoreboards(completion: @escaping (Result<BoardsList, PlaydateError>) -> Void) -> Bool {
|
||||||
boardsCompletion = completion
|
boardsCompletion = completion
|
||||||
return scoreboardsAPI.getScoreboards.unsafelyUnwrapped({ boards, errorMessage in
|
return scoreboardsAPI.pointee.getScoreboards.unsafelyUnwrapped({ boards, errorMessage in
|
||||||
let completion = Scoreboards.boardsCompletion
|
let completion = Scoreboards.boardsCompletion
|
||||||
Scoreboards.boardsCompletion = nil
|
Scoreboards.boardsCompletion = nil
|
||||||
guard let boards else {
|
guard let boards else {
|
||||||
@@ -136,7 +136,7 @@ extension Scoreboards {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let list = BoardsList(boards.pointee)
|
let list = BoardsList(boards.pointee)
|
||||||
scoreboardsAPI.freeBoardsList.unsafelyUnwrapped(boards)
|
scoreboardsAPI.pointee.freeBoardsList.unsafelyUnwrapped(boards)
|
||||||
completion?(.success(list))
|
completion?(.success(list))
|
||||||
}) != 0
|
}) != 0
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ extension Scoreboards {
|
|||||||
completion: @escaping (Result<ScoresList, PlaydateError>) -> Void) -> Bool {
|
completion: @escaping (Result<ScoresList, PlaydateError>) -> Void) -> Bool {
|
||||||
scoresCompletion = completion
|
scoresCompletion = completion
|
||||||
return boardID.withPlaydateCString { cBoardID in
|
return boardID.withPlaydateCString { cBoardID in
|
||||||
scoreboardsAPI.getScores.unsafelyUnwrapped(cBoardID, { scores, errorMessage in
|
scoreboardsAPI.pointee.getScores.unsafelyUnwrapped(cBoardID, { scores, errorMessage in
|
||||||
let completion = Scoreboards.scoresCompletion
|
let completion = Scoreboards.scoresCompletion
|
||||||
Scoreboards.scoresCompletion = nil
|
Scoreboards.scoresCompletion = nil
|
||||||
guard let scores else {
|
guard let scores else {
|
||||||
@@ -155,7 +155,7 @@ extension Scoreboards {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let list = ScoresList(scores.pointee)
|
let list = ScoresList(scores.pointee)
|
||||||
scoreboardsAPI.freeScoresList.unsafelyUnwrapped(scores)
|
scoreboardsAPI.pointee.freeScoresList.unsafelyUnwrapped(scores)
|
||||||
completion?(.success(list))
|
completion?(.success(list))
|
||||||
}) != 0
|
}) != 0
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ extension Scoreboards {
|
|||||||
return .failure(PlaydateError(cString: errorMessage))
|
return .failure(PlaydateError(cString: errorMessage))
|
||||||
}
|
}
|
||||||
let value = Score(score.pointee)
|
let value = Score(score.pointee)
|
||||||
scoreboardsAPI.freeScore.unsafelyUnwrapped(score)
|
scoreboardsAPI.pointee.freeScore.unsafelyUnwrapped(score)
|
||||||
return .success(value)
|
return .success(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
var snd: playdate_sound { Playdate.api.sound.pointee }
|
var snd: UnsafePointer<playdate_sound> { Playdate.soundAPI }
|
||||||
|
|
||||||
/// The sound API: channels, players, synths, sequences, and effects.
|
/// The sound API: channels, players, synths, sequences, and effects.
|
||||||
public enum Sound {}
|
public enum Sound {}
|
||||||
@@ -60,25 +60,25 @@ extension Sound {
|
|||||||
|
|
||||||
/// The most recent sound error as a thrown error.
|
/// The most recent sound error as a thrown error.
|
||||||
static func lastError() -> PlaydateError {
|
static func lastError() -> PlaydateError {
|
||||||
PlaydateError(cString: snd.getError.unsafelyUnwrapped())
|
PlaydateError(cString: snd.pointee.getError.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Top-level functions
|
// MARK: - Top-level functions
|
||||||
|
|
||||||
/// The audio engine's current time, in frames (44,100 per second).
|
/// The audio engine's current time, in frames (44,100 per second).
|
||||||
public static var currentTime: UInt32 {
|
public static var currentTime: UInt32 {
|
||||||
snd.getCurrentTime.unsafelyUnwrapped()
|
snd.pointee.getCurrentTime.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The most recent audio error message, if any.
|
/// The most recent audio error message, if any.
|
||||||
public static var error: String? {
|
public static var error: String? {
|
||||||
String(playdateCString: snd.getError.unsafelyUnwrapped())
|
String(playdateCString: snd.pointee.getError.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a source from its channel.
|
/// Removes a source from its channel.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func removeSource(_ source: Source) -> Bool {
|
public static func removeSource(_ source: Source) -> Bool {
|
||||||
let removed = snd.removeSource.unsafelyUnwrapped(source.pointer) != 0
|
let removed = snd.pointee.removeSource.unsafelyUnwrapped(source.pointer) != 0
|
||||||
CallbackSource.release(source)
|
CallbackSource.release(source)
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
@@ -91,12 +91,12 @@ extension Sound {
|
|||||||
_ callback: ((UnsafeMutableBufferPointer<Int16>) -> Bool)?) -> Bool {
|
_ callback: ((UnsafeMutableBufferPointer<Int16>) -> Bool)?) -> Bool {
|
||||||
micCallback = callback
|
micCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
return snd.setMicCallback.unsafelyUnwrapped({ _, buffer, length in
|
return snd.pointee.setMicCallback.unsafelyUnwrapped({ _, buffer, length in
|
||||||
let samples = UnsafeMutableBufferPointer(start: buffer, count: Int(length))
|
let samples = UnsafeMutableBufferPointer(start: buffer, count: Int(length))
|
||||||
return Sound.micCallback?(samples) == true ? 1 : 0
|
return Sound.micCallback?(samples) == true ? 1 : 0
|
||||||
}, nil, CPlaydate.MicSource(source.rawValue)) != 0
|
}, nil, CPlaydate.MicSource(source.rawValue)) != 0
|
||||||
} else {
|
} else {
|
||||||
return snd.setMicCallback.unsafelyUnwrapped(nil, nil, CPlaydate.MicSource(source.rawValue)) != 0
|
return snd.pointee.setMicCallback.unsafelyUnwrapped(nil, nil, CPlaydate.MicSource(source.rawValue)) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,10 +119,10 @@ extension Sound {
|
|||||||
let reply: accessReply
|
let reply: accessReply
|
||||||
if let purpose {
|
if let purpose {
|
||||||
reply = purpose.withPlaydateCString {
|
reply = purpose.withPlaydateCString {
|
||||||
snd.requestMicAccess.unsafelyUnwrapped($0, trampoline, box.toOpaque())
|
snd.pointee.requestMicAccess.unsafelyUnwrapped($0, trampoline, box.toOpaque())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reply = snd.requestMicAccess.unsafelyUnwrapped(nil, trampoline, box.toOpaque())
|
reply = snd.pointee.requestMicAccess.unsafelyUnwrapped(nil, trampoline, box.toOpaque())
|
||||||
}
|
}
|
||||||
if reply != kAccessAsk {
|
if reply != kAccessAsk {
|
||||||
// The callback will not be invoked; balance the retain.
|
// The callback will not be invoked; balance the retain.
|
||||||
@@ -134,7 +134,7 @@ extension Sound {
|
|||||||
/// The current headphone and headset-microphone state.
|
/// The current headphone and headset-microphone state.
|
||||||
public static var headphoneState: (headphone: Bool, headsetMic: Bool) {
|
public static var headphoneState: (headphone: Bool, headsetMic: Bool) {
|
||||||
var headphone: Int32 = 0, headsetMic: Int32 = 0
|
var headphone: Int32 = 0, headsetMic: Int32 = 0
|
||||||
snd.getHeadphoneState.unsafelyUnwrapped(&headphone, &headsetMic, nil)
|
snd.pointee.getHeadphoneState.unsafelyUnwrapped(&headphone, &headsetMic, nil)
|
||||||
return (headphone != 0, headsetMic != 0)
|
return (headphone != 0, headsetMic != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,11 +143,11 @@ extension Sound {
|
|||||||
public static func setHeadphoneChangeCallback(_ callback: ((_ headphone: Bool, _ headsetMic: Bool) -> Void)?) {
|
public static func setHeadphoneChangeCallback(_ callback: ((_ headphone: Bool, _ headsetMic: Bool) -> Void)?) {
|
||||||
headphoneChangeCallback = callback
|
headphoneChangeCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
snd.getHeadphoneState.unsafelyUnwrapped(nil, nil, { headphone, mic in
|
snd.pointee.getHeadphoneState.unsafelyUnwrapped(nil, nil, { headphone, mic in
|
||||||
Sound.headphoneChangeCallback?(headphone != 0, mic != 0)
|
Sound.headphoneChangeCallback?(headphone != 0, mic != 0)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
snd.getHeadphoneState.unsafelyUnwrapped(nil, nil, nil)
|
snd.pointee.getHeadphoneState.unsafelyUnwrapped(nil, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ extension Sound {
|
|||||||
/// headphone jack drives output and `speaker` is also set, the speaker
|
/// headphone jack drives output and `speaker` is also set, the speaker
|
||||||
/// plays too.
|
/// plays too.
|
||||||
public static func setOutputsActive(headphone: Bool, speaker: Bool) {
|
public static func setOutputsActive(headphone: Bool, speaker: Bool) {
|
||||||
snd.setOutputsActive.unsafelyUnwrapped(headphone ? 1 : 0, speaker ? 1 : 0)
|
snd.pointee.setOutputsActive.unsafelyUnwrapped(headphone ? 1 : 0, speaker ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a callback-based source to the default channel. The callback
|
/// Adds a callback-based source to the default channel. The callback
|
||||||
@@ -166,7 +166,7 @@ extension Sound {
|
|||||||
public static func addSource(stereo: Bool,
|
public static func addSource(stereo: Bool,
|
||||||
_ callback: @escaping CallbackSource.Callback) -> CallbackSource {
|
_ callback: @escaping CallbackSource.Callback) -> CallbackSource {
|
||||||
let source = CallbackSource(callback: callback)
|
let source = CallbackSource(callback: callback)
|
||||||
let pointer = snd.addSource.unsafelyUnwrapped(
|
let pointer = snd.pointee.addSource.unsafelyUnwrapped(
|
||||||
CallbackSource.trampoline, source.contextPointer, stereo ? 1 : 0)
|
CallbackSource.trampoline, source.contextPointer, stereo ? 1 : 0)
|
||||||
source.adopt(pointer: pointer.unsafelyUnwrapped)
|
source.adopt(pointer: pointer.unsafelyUnwrapped)
|
||||||
return source
|
return source
|
||||||
@@ -176,7 +176,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// A mixer channel holding sources and effects. Wraps `SoundChannel`.
|
/// A mixer channel holding sources and effects. Wraps `SoundChannel`.
|
||||||
public final class Channel {
|
public final class Channel {
|
||||||
private static var api: playdate_sound_channel { snd.channel.pointee }
|
private static var api: UnsafePointer<playdate_sound_channel> { snd.pointee.channel.unsafelyUnwrapped }
|
||||||
|
|
||||||
let pointer: OpaquePointer
|
let pointer: OpaquePointer
|
||||||
let isOwned: Bool
|
let isOwned: Bool
|
||||||
@@ -191,13 +191,13 @@ extension Sound {
|
|||||||
|
|
||||||
/// Creates a new channel. Add it to the sound engine with `add()`.
|
/// Creates a new channel. Add it to the sound engine with `add()`.
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: Channel.api.newChannel.unsafelyUnwrapped().unsafelyUnwrapped,
|
self.init(pointer: Channel.api.pointee.newChannel.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
Channel.api.freeChannel.unsafelyUnwrapped(pointer)
|
Channel.api.pointee.freeChannel.unsafelyUnwrapped(pointer)
|
||||||
// The freed channel no longer pulls its callback sources, so
|
// The freed channel no longer pulls its callback sources, so
|
||||||
// their trampoline registrations can be released too.
|
// their trampoline registrations can be released too.
|
||||||
for source in retainedSources where source is CallbackSource {
|
for source in retainedSources where source is CallbackSource {
|
||||||
@@ -209,7 +209,7 @@ extension Sound {
|
|||||||
/// The default channel, which sources are added to unless otherwise
|
/// The default channel, which sources are added to unless otherwise
|
||||||
/// specified.
|
/// specified.
|
||||||
public static var `default`: Channel {
|
public static var `default`: Channel {
|
||||||
Channel(pointer: snd.getDefaultChannel.unsafelyUnwrapped().unsafelyUnwrapped,
|
Channel(pointer: snd.pointee.getDefaultChannel.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: false)
|
isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ extension Sound {
|
|||||||
/// Adds the channel to the sound engine.
|
/// Adds the channel to the sound engine.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func add() -> Bool {
|
public func add() -> Bool {
|
||||||
let added = snd.addChannel.unsafelyUnwrapped(pointer) != 0
|
let added = snd.pointee.addChannel.unsafelyUnwrapped(pointer) != 0
|
||||||
if added, !Channel.addedChannels.contains(where: { $0 === self }) {
|
if added, !Channel.addedChannels.contains(where: { $0 === self }) {
|
||||||
Channel.addedChannels.append(self)
|
Channel.addedChannels.append(self)
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ extension Sound {
|
|||||||
/// Removes the channel from the sound engine.
|
/// Removes the channel from the sound engine.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func remove() -> Bool {
|
public func remove() -> Bool {
|
||||||
let removed = snd.removeChannel.unsafelyUnwrapped(pointer) != 0
|
let removed = snd.pointee.removeChannel.unsafelyUnwrapped(pointer) != 0
|
||||||
Channel.addedChannels.removeAll { $0 === self }
|
Channel.addedChannels.removeAll { $0 === self }
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
@@ -236,7 +236,7 @@ extension Sound {
|
|||||||
/// Adds a source to the channel. A source can only be on one channel.
|
/// Adds a source to the channel. A source can only be on one channel.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func addSource(_ source: Source) -> Bool {
|
public func addSource(_ source: Source) -> Bool {
|
||||||
let added = Channel.api.addSource.unsafelyUnwrapped(pointer, source.pointer) != 0
|
let added = Channel.api.pointee.addSource.unsafelyUnwrapped(pointer, source.pointer) != 0
|
||||||
if added, !retainedSources.contains(where: { $0 === source }) {
|
if added, !retainedSources.contains(where: { $0 === source }) {
|
||||||
retainedSources.append(source)
|
retainedSources.append(source)
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ extension Sound {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func removeSource(_ source: Source) -> Bool {
|
public func removeSource(_ source: Source) -> Bool {
|
||||||
let removed = Channel.api.removeSource.unsafelyUnwrapped(pointer, source.pointer) != 0
|
let removed = Channel.api.pointee.removeSource.unsafelyUnwrapped(pointer, source.pointer) != 0
|
||||||
retainedSources.removeAll { $0 === source }
|
retainedSources.removeAll { $0 === source }
|
||||||
CallbackSource.release(source)
|
CallbackSource.release(source)
|
||||||
return removed
|
return removed
|
||||||
@@ -256,7 +256,7 @@ extension Sound {
|
|||||||
public func addCallbackSource(stereo: Bool,
|
public func addCallbackSource(stereo: Bool,
|
||||||
_ callback: @escaping CallbackSource.Callback) -> CallbackSource {
|
_ callback: @escaping CallbackSource.Callback) -> CallbackSource {
|
||||||
let source = CallbackSource(callback: callback)
|
let source = CallbackSource(callback: callback)
|
||||||
let pointer = Channel.api.addCallbackSource.unsafelyUnwrapped(
|
let pointer = Channel.api.pointee.addCallbackSource.unsafelyUnwrapped(
|
||||||
self.pointer, CallbackSource.trampoline, source.contextPointer, stereo ? 1 : 0)
|
self.pointer, CallbackSource.trampoline, source.contextPointer, stereo ? 1 : 0)
|
||||||
source.adopt(pointer: pointer.unsafelyUnwrapped)
|
source.adopt(pointer: pointer.unsafelyUnwrapped)
|
||||||
retainedSources.append(source)
|
retainedSources.append(source)
|
||||||
@@ -265,7 +265,7 @@ extension Sound {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func addEffect(_ effect: Effect) -> Bool {
|
public func addEffect(_ effect: Effect) -> Bool {
|
||||||
let added = Channel.api.addEffect.unsafelyUnwrapped(pointer, effect.pointer) != 0
|
let added = Channel.api.pointee.addEffect.unsafelyUnwrapped(pointer, effect.pointer) != 0
|
||||||
if added, !retainedEffects.contains(where: { $0 === effect }) {
|
if added, !retainedEffects.contains(where: { $0 === effect }) {
|
||||||
retainedEffects.append(effect)
|
retainedEffects.append(effect)
|
||||||
}
|
}
|
||||||
@@ -274,56 +274,56 @@ extension Sound {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func removeEffect(_ effect: Effect) -> Bool {
|
public func removeEffect(_ effect: Effect) -> Bool {
|
||||||
let removed = Channel.api.removeEffect.unsafelyUnwrapped(pointer, effect.pointer) != 0
|
let removed = Channel.api.pointee.removeEffect.unsafelyUnwrapped(pointer, effect.pointer) != 0
|
||||||
retainedEffects.removeAll { $0 === effect }
|
retainedEffects.removeAll { $0 === effect }
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The channel's volume, 0...1.
|
/// The channel's volume, 0...1.
|
||||||
public var volume: Float {
|
public var volume: Float {
|
||||||
get { Channel.api.getVolume.unsafelyUnwrapped(pointer) }
|
get { Channel.api.pointee.getVolume.unsafelyUnwrapped(pointer) }
|
||||||
set { Channel.api.setVolume.unsafelyUnwrapped(pointer, newValue) }
|
set { Channel.api.pointee.setVolume.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modulates the channel's volume.
|
/// Modulates the channel's volume.
|
||||||
public func setVolumeModulator(_ modulator: SignalValue?) {
|
public func setVolumeModulator(_ modulator: SignalValue?) {
|
||||||
retain(modulator)
|
retain(modulator)
|
||||||
Channel.api.setVolumeModulator.unsafelyUnwrapped(pointer, modulator?.pointer)
|
Channel.api.pointee.setVolumeModulator.unsafelyUnwrapped(pointer, modulator?.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var volumeModulator: SignalValue? {
|
public var volumeModulator: SignalValue? {
|
||||||
SignalValue.wrap(Channel.api.getVolumeModulator.unsafelyUnwrapped(pointer))
|
SignalValue.wrap(Channel.api.pointee.getVolumeModulator.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The channel's stereo pan: -1 (left) to 1 (right).
|
/// The channel's stereo pan: -1 (left) to 1 (right).
|
||||||
public func setPan(_ pan: Float) {
|
public func setPan(_ pan: Float) {
|
||||||
Channel.api.setPan.unsafelyUnwrapped(pointer, pan)
|
Channel.api.pointee.setPan.unsafelyUnwrapped(pointer, pan)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modulates the channel's pan. The signal's range 0...1 maps to
|
/// Modulates the channel's pan. The signal's range 0...1 maps to
|
||||||
/// left...right.
|
/// left...right.
|
||||||
public func setPanModulator(_ modulator: SignalValue?) {
|
public func setPanModulator(_ modulator: SignalValue?) {
|
||||||
retain(modulator)
|
retain(modulator)
|
||||||
Channel.api.setPanModulator.unsafelyUnwrapped(pointer, modulator?.pointer)
|
Channel.api.pointee.setPanModulator.unsafelyUnwrapped(pointer, modulator?.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var panModulator: SignalValue? {
|
public var panModulator: SignalValue? {
|
||||||
SignalValue.wrap(Channel.api.getPanModulator.unsafelyUnwrapped(pointer))
|
SignalValue.wrap(Channel.api.pointee.getPanModulator.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A signal following the channel's dry (unprocessed) level.
|
/// A signal following the channel's dry (unprocessed) level.
|
||||||
public var dryLevelSignal: SignalValue? {
|
public var dryLevelSignal: SignalValue? {
|
||||||
SignalValue.wrap(Channel.api.getDryLevelSignal.unsafelyUnwrapped(pointer))
|
SignalValue.wrap(Channel.api.pointee.getDryLevelSignal.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A signal following the channel's wet (processed) level.
|
/// A signal following the channel's wet (processed) level.
|
||||||
public var wetLevelSignal: SignalValue? {
|
public var wetLevelSignal: SignalValue? {
|
||||||
SignalValue.wrap(Channel.api.getWetLevelSignal.unsafelyUnwrapped(pointer))
|
SignalValue.wrap(Channel.api.pointee.getWetLevelSignal.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The channel's output as a source, for feeding into another channel.
|
/// The channel's output as a source, for feeding into another channel.
|
||||||
public var outputAsSource: Source? {
|
public var outputAsSource: Source? {
|
||||||
guard let source = Channel.api.getOutputAsSource.unsafelyUnwrapped(pointer) else {
|
guard let source = Channel.api.pointee.getOutputAsSource.unsafelyUnwrapped(pointer) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return Source(pointer: source, isOwned: false)
|
return Source(pointer: source, isOwned: false)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var effectAPI: playdate_sound_effect { snd.effect.pointee }
|
private var effectAPI: UnsafePointer<playdate_sound_effect> { snd.pointee.effect.unsafelyUnwrapped }
|
||||||
|
|
||||||
extension Sound {
|
extension Sound {
|
||||||
/// An effect that processes a channel's audio: the base class of the
|
/// An effect that processes a channel's audio: the base class of the
|
||||||
@@ -38,9 +38,9 @@ extension Sound {
|
|||||||
public init(processor: @escaping Processor) {
|
public init(processor: @escaping Processor) {
|
||||||
let box = Unmanaged.passRetained(ProcessorBox(processor))
|
let box = Unmanaged.passRetained(ProcessorBox(processor))
|
||||||
processorBox = box
|
processorBox = box
|
||||||
pointer = effectAPI.newEffect.unsafelyUnwrapped({ effect, left, right, nsamples, bufactive in
|
pointer = effectAPI.pointee.newEffect.unsafelyUnwrapped({ effect, left, right, nsamples, bufactive in
|
||||||
guard let effect, let left,
|
guard let effect, let left,
|
||||||
let userdata = effectAPI.getUserdata.unsafelyUnwrapped(effect) else { return 0 }
|
let userdata = effectAPI.pointee.getUserdata.unsafelyUnwrapped(effect) else { return 0 }
|
||||||
let box = Unmanaged<ProcessorBox>.fromOpaque(userdata).takeUnretainedValue()
|
let box = Unmanaged<ProcessorBox>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
let leftBuffer = UnsafeMutableBufferPointer(start: left, count: Int(nsamples))
|
let leftBuffer = UnsafeMutableBufferPointer(start: left, count: Int(nsamples))
|
||||||
let rightBuffer = right.map { UnsafeMutableBufferPointer(start: $0, count: Int(nsamples)) }
|
let rightBuffer = right.map { UnsafeMutableBufferPointer(start: $0, count: Int(nsamples)) }
|
||||||
@@ -51,21 +51,21 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
effectAPI.freeEffect.unsafelyUnwrapped(pointer)
|
effectAPI.pointee.freeEffect.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
processorBox?.release()
|
processorBox?.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The wet/dry mix: 1 is fully processed, 0 fully dry.
|
/// The wet/dry mix: 1 is fully processed, 0 fully dry.
|
||||||
public func setMix(_ level: Float) {
|
public func setMix(_ level: Float) {
|
||||||
effectAPI.setMix.unsafelyUnwrapped(pointer, level)
|
effectAPI.pointee.setMix.unsafelyUnwrapped(pointer, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var mixModulator: SignalValue? {
|
public var mixModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(effectAPI.getMixModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(effectAPI.pointee.getMixModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedMixModulator = newValue
|
retainedMixModulator = newValue
|
||||||
effectAPI.setMixModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
effectAPI.pointee.setMixModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// A two-pole IIR filter. Wraps `TwoPoleFilter`.
|
/// A two-pole IIR filter. Wraps `TwoPoleFilter`.
|
||||||
public final class TwoPoleFilter: Effect {
|
public final class TwoPoleFilter: Effect {
|
||||||
private static var api: playdate_sound_effect_twopolefilter { effectAPI.twopolefilter.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_twopolefilter> { effectAPI.pointee.twopolefilter.unsafelyUnwrapped }
|
||||||
|
|
||||||
public enum Kind: UInt32, Sendable {
|
public enum Kind: UInt32, Sendable {
|
||||||
case lowPass = 0
|
case lowPass = 0
|
||||||
@@ -92,48 +92,48 @@ extension Sound {
|
|||||||
private var retainedResonanceModulator: SignalValue?
|
private var retainedResonanceModulator: SignalValue?
|
||||||
|
|
||||||
public init(kind: Kind = .lowPass) {
|
public init(kind: Kind = .lowPass) {
|
||||||
super.init(pointer: TwoPoleFilter.api.newFilter.unsafelyUnwrapped().unsafelyUnwrapped,
|
super.init(pointer: TwoPoleFilter.api.pointee.newFilter.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
setKind(kind)
|
setKind(kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
TwoPoleFilter.api.freeFilter.unsafelyUnwrapped(pointer)
|
TwoPoleFilter.api.pointee.freeFilter.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setKind(_ kind: Kind) {
|
public func setKind(_ kind: Kind) {
|
||||||
TwoPoleFilter.api.setType.unsafelyUnwrapped(pointer, kind.cValue)
|
TwoPoleFilter.api.pointee.setType.unsafelyUnwrapped(pointer, kind.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The center/corner frequency, in Hz.
|
/// The center/corner frequency, in Hz.
|
||||||
public func setFrequency(_ frequency: Float) {
|
public func setFrequency(_ frequency: Float) {
|
||||||
TwoPoleFilter.api.setFrequency.unsafelyUnwrapped(pointer, frequency)
|
TwoPoleFilter.api.pointee.setFrequency.unsafelyUnwrapped(pointer, frequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var frequencyModulator: SignalValue? {
|
public var frequencyModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(TwoPoleFilter.api.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(TwoPoleFilter.api.pointee.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedFrequencyModulator = newValue
|
retainedFrequencyModulator = newValue
|
||||||
TwoPoleFilter.api.setFrequencyModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
TwoPoleFilter.api.pointee.setFrequencyModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The gain, used by PEQ and shelf filters.
|
/// The gain, used by PEQ and shelf filters.
|
||||||
public func setGain(_ gain: Float) {
|
public func setGain(_ gain: Float) {
|
||||||
TwoPoleFilter.api.setGain.unsafelyUnwrapped(pointer, gain)
|
TwoPoleFilter.api.pointee.setGain.unsafelyUnwrapped(pointer, gain)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setResonance(_ resonance: Float) {
|
public func setResonance(_ resonance: Float) {
|
||||||
TwoPoleFilter.api.setResonance.unsafelyUnwrapped(pointer, resonance)
|
TwoPoleFilter.api.pointee.setResonance.unsafelyUnwrapped(pointer, resonance)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var resonanceModulator: SignalValue? {
|
public var resonanceModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(TwoPoleFilter.api.getResonanceModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(TwoPoleFilter.api.pointee.getResonanceModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedResonanceModulator = newValue
|
retainedResonanceModulator = newValue
|
||||||
TwoPoleFilter.api.setResonanceModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
TwoPoleFilter.api.pointee.setResonanceModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,32 +142,32 @@ extension Sound {
|
|||||||
|
|
||||||
/// A one-pole low/high-pass filter. Wraps `OnePoleFilter`.
|
/// A one-pole low/high-pass filter. Wraps `OnePoleFilter`.
|
||||||
public final class OnePoleFilter: Effect {
|
public final class OnePoleFilter: Effect {
|
||||||
private static var api: playdate_sound_effect_onepolefilter { effectAPI.onepolefilter.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_onepolefilter> { effectAPI.pointee.onepolefilter.unsafelyUnwrapped }
|
||||||
|
|
||||||
private var retainedParameterModulator: SignalValue?
|
private var retainedParameterModulator: SignalValue?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
super.init(pointer: OnePoleFilter.api.newFilter.unsafelyUnwrapped().unsafelyUnwrapped,
|
super.init(pointer: OnePoleFilter.api.pointee.newFilter.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
OnePoleFilter.api.freeFilter.unsafelyUnwrapped(pointer)
|
OnePoleFilter.api.pointee.freeFilter.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The filter's cutoff: -1 to 1, where values above 0 are low-pass
|
/// The filter's cutoff: -1 to 1, where values above 0 are low-pass
|
||||||
/// and values below 0 high-pass.
|
/// and values below 0 high-pass.
|
||||||
public func setParameter(_ parameter: Float) {
|
public func setParameter(_ parameter: Float) {
|
||||||
OnePoleFilter.api.setParameter.unsafelyUnwrapped(pointer, parameter)
|
OnePoleFilter.api.pointee.setParameter.unsafelyUnwrapped(pointer, parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var parameterModulator: SignalValue? {
|
public var parameterModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(OnePoleFilter.api.getParameterModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(OnePoleFilter.api.pointee.getParameterModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedParameterModulator = newValue
|
retainedParameterModulator = newValue
|
||||||
OnePoleFilter.api.setParameterModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
OnePoleFilter.api.pointee.setParameterModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,49 +176,49 @@ extension Sound {
|
|||||||
|
|
||||||
/// A bit-crushing and downsampling effect. Wraps `BitCrusher`.
|
/// A bit-crushing and downsampling effect. Wraps `BitCrusher`.
|
||||||
public final class BitCrusher: Effect {
|
public final class BitCrusher: Effect {
|
||||||
private static var api: playdate_sound_effect_bitcrusher { effectAPI.bitcrusher.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_bitcrusher> { effectAPI.pointee.bitcrusher.unsafelyUnwrapped }
|
||||||
|
|
||||||
private var retainedModulators: [SignalValue] = []
|
private var retainedModulators: [SignalValue] = []
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
super.init(pointer: BitCrusher.api.newBitCrusher.unsafelyUnwrapped().unsafelyUnwrapped,
|
super.init(pointer: BitCrusher.api.pointee.newBitCrusher.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
BitCrusher.api.freeBitCrusher.unsafelyUnwrapped(pointer)
|
BitCrusher.api.pointee.freeBitCrusher.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true`, `setDepth` values map exponentially to bit depth.
|
/// When `true`, `setDepth` values map exponentially to bit depth.
|
||||||
public func setExponential(_ flag: Bool) {
|
public func setExponential(_ flag: Bool) {
|
||||||
BitCrusher.api.setExponential.unsafelyUnwrapped(pointer, flag)
|
BitCrusher.api.pointee.setExponential.unsafelyUnwrapped(pointer, flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The amount of crushing, 0 (none) to 1 (quantized to 1 bit).
|
/// The amount of crushing, 0 (none) to 1 (quantized to 1 bit).
|
||||||
public func setDepth(_ depth: Float) {
|
public func setDepth(_ depth: Float) {
|
||||||
BitCrusher.api.setDepth.unsafelyUnwrapped(pointer, depth)
|
BitCrusher.api.pointee.setDepth.unsafelyUnwrapped(pointer, depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var depthModulator: SignalValue? {
|
public var depthModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(BitCrusher.api.getDepthModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(BitCrusher.api.pointee.getDepthModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retain(newValue)
|
retain(newValue)
|
||||||
BitCrusher.api.setDepthModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
BitCrusher.api.pointee.setDepthModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The amount of downsampling, 0 (none) to 1 (every sample repeated).
|
/// The amount of downsampling, 0 (none) to 1 (every sample repeated).
|
||||||
public func setDownsampling(_ downsampling: Float) {
|
public func setDownsampling(_ downsampling: Float) {
|
||||||
BitCrusher.api.setDownsampling.unsafelyUnwrapped(pointer, downsampling)
|
BitCrusher.api.pointee.setDownsampling.unsafelyUnwrapped(pointer, downsampling)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var downsamplingModulator: SignalValue? {
|
public var downsamplingModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(BitCrusher.api.getDownsamplingModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(BitCrusher.api.pointee.getDownsamplingModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retain(newValue)
|
retain(newValue)
|
||||||
BitCrusher.api.setDownsamplingModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
BitCrusher.api.pointee.setDownsamplingModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,31 +231,31 @@ extension Sound {
|
|||||||
|
|
||||||
/// A ring modulator effect. Wraps `RingModulator`.
|
/// A ring modulator effect. Wraps `RingModulator`.
|
||||||
public final class RingModulator: Effect {
|
public final class RingModulator: Effect {
|
||||||
private static var api: playdate_sound_effect_ringmodulator { effectAPI.ringmodulator.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_ringmodulator> { effectAPI.pointee.ringmodulator.unsafelyUnwrapped }
|
||||||
|
|
||||||
private var retainedFrequencyModulator: SignalValue?
|
private var retainedFrequencyModulator: SignalValue?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
super.init(pointer: RingModulator.api.newRingmod.unsafelyUnwrapped().unsafelyUnwrapped,
|
super.init(pointer: RingModulator.api.pointee.newRingmod.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
RingModulator.api.freeRingmod.unsafelyUnwrapped(pointer)
|
RingModulator.api.pointee.freeRingmod.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The modulation frequency, in Hz.
|
/// The modulation frequency, in Hz.
|
||||||
public func setFrequency(_ frequency: Float) {
|
public func setFrequency(_ frequency: Float) {
|
||||||
RingModulator.api.setFrequency.unsafelyUnwrapped(pointer, frequency)
|
RingModulator.api.pointee.setFrequency.unsafelyUnwrapped(pointer, frequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var frequencyModulator: SignalValue? {
|
public var frequencyModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(RingModulator.api.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(RingModulator.api.pointee.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedFrequencyModulator = newValue
|
retainedFrequencyModulator = newValue
|
||||||
RingModulator.api.setFrequencyModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
RingModulator.api.pointee.setFrequencyModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +265,7 @@ extension Sound {
|
|||||||
/// A tap into a delay line; produces audio and can be added to a channel
|
/// A tap into a delay line; produces audio and can be added to a channel
|
||||||
/// as a source. Wraps `DelayLineTap`.
|
/// as a source. Wraps `DelayLineTap`.
|
||||||
public final class DelayLineTap: Source {
|
public final class DelayLineTap: Source {
|
||||||
private static var api: playdate_sound_effect_delayline { effectAPI.delayline.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_delayline> { effectAPI.pointee.delayline.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// The delay line is retained so the tap stays valid.
|
/// The delay line is retained so the tap stays valid.
|
||||||
private let delayLine: DelayLine
|
private let delayLine: DelayLine
|
||||||
@@ -277,59 +277,59 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
DelayLineTap.api.freeTap.unsafelyUnwrapped(pointer)
|
DelayLineTap.api.pointee.freeTap.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tap's position in the delay line, in frames.
|
/// The tap's position in the delay line, in frames.
|
||||||
public func setDelay(frames: Int) {
|
public func setDelay(frames: Int) {
|
||||||
DelayLineTap.api.setTapDelay.unsafelyUnwrapped(pointer, Int32(frames))
|
DelayLineTap.api.pointee.setTapDelay.unsafelyUnwrapped(pointer, Int32(frames))
|
||||||
}
|
}
|
||||||
|
|
||||||
public var delayModulator: SignalValue? {
|
public var delayModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(DelayLineTap.api.getTapDelayModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(DelayLineTap.api.pointee.getTapDelayModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedDelayModulator = newValue
|
retainedDelayModulator = newValue
|
||||||
DelayLineTap.api.setTapDelayModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
DelayLineTap.api.pointee.setTapDelayModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For stereo delay lines: swaps the left and right channels.
|
/// For stereo delay lines: swaps the left and right channels.
|
||||||
public func setChannelsFlipped(_ flipped: Bool) {
|
public func setChannelsFlipped(_ flipped: Bool) {
|
||||||
DelayLineTap.api.setTapChannelsFlipped.unsafelyUnwrapped(pointer, flipped ? 1 : 0)
|
DelayLineTap.api.pointee.setTapChannelsFlipped.unsafelyUnwrapped(pointer, flipped ? 1 : 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A delay line effect. Wraps `DelayLine`.
|
/// A delay line effect. Wraps `DelayLine`.
|
||||||
public final class DelayLine: Effect {
|
public final class DelayLine: Effect {
|
||||||
private static var api: playdate_sound_effect_delayline { effectAPI.delayline.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_delayline> { effectAPI.pointee.delayline.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// Creates a delay line holding `length` frames.
|
/// Creates a delay line holding `length` frames.
|
||||||
public init(length: Int, stereo: Bool = false) {
|
public init(length: Int, stereo: Bool = false) {
|
||||||
super.init(pointer: DelayLine.api.newDelayLine.unsafelyUnwrapped(
|
super.init(pointer: DelayLine.api.pointee.newDelayLine.unsafelyUnwrapped(
|
||||||
Int32(length), stereo ? 1 : 0).unsafelyUnwrapped, isOwned: true)
|
Int32(length), stereo ? 1 : 0).unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
DelayLine.api.freeDelayLine.unsafelyUnwrapped(pointer)
|
DelayLine.api.pointee.freeDelayLine.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the delay length. Cannot be larger than the line's
|
/// Changes the delay length. Cannot be larger than the line's
|
||||||
/// original length.
|
/// original length.
|
||||||
public func setLength(frames: Int) {
|
public func setLength(frames: Int) {
|
||||||
DelayLine.api.setLength.unsafelyUnwrapped(pointer, Int32(frames))
|
DelayLine.api.pointee.setLength.unsafelyUnwrapped(pointer, Int32(frames))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The feedback level, 0...1.
|
/// The feedback level, 0...1.
|
||||||
public func setFeedback(_ feedback: Float) {
|
public func setFeedback(_ feedback: Float) {
|
||||||
DelayLine.api.setFeedback.unsafelyUnwrapped(pointer, feedback)
|
DelayLine.api.pointee.setFeedback.unsafelyUnwrapped(pointer, feedback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a tap `delay` frames behind the write head. The tap can be
|
/// Adds a tap `delay` frames behind the write head. The tap can be
|
||||||
/// added to a channel as a sound source.
|
/// added to a channel as a sound source.
|
||||||
public func addTap(delay: Int) -> DelayLineTap? {
|
public func addTap(delay: Int) -> DelayLineTap? {
|
||||||
guard let tap = DelayLine.api.addTap.unsafelyUnwrapped(pointer, Int32(delay)) else {
|
guard let tap = DelayLine.api.pointee.addTap.unsafelyUnwrapped(pointer, Int32(delay)) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return DelayLineTap(pointer: tap, delayLine: self)
|
return DelayLineTap(pointer: tap, delayLine: self)
|
||||||
@@ -340,49 +340,49 @@ extension Sound {
|
|||||||
|
|
||||||
/// An overdrive/distortion effect. Wraps `Overdrive`.
|
/// An overdrive/distortion effect. Wraps `Overdrive`.
|
||||||
public final class Overdrive: Effect {
|
public final class Overdrive: Effect {
|
||||||
private static var api: playdate_sound_effect_overdrive { effectAPI.overdrive.pointee }
|
private static var api: UnsafePointer<playdate_sound_effect_overdrive> { effectAPI.pointee.overdrive.unsafelyUnwrapped }
|
||||||
|
|
||||||
private var retainedModulators: [SignalValue] = []
|
private var retainedModulators: [SignalValue] = []
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
super.init(pointer: Overdrive.api.newOverdrive.unsafelyUnwrapped().unsafelyUnwrapped,
|
super.init(pointer: Overdrive.api.pointee.newOverdrive.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
Overdrive.api.freeOverdrive.unsafelyUnwrapped(pointer)
|
Overdrive.api.pointee.freeOverdrive.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input gain applied before clipping.
|
/// The input gain applied before clipping.
|
||||||
public func setGain(_ gain: Float) {
|
public func setGain(_ gain: Float) {
|
||||||
Overdrive.api.setGain.unsafelyUnwrapped(pointer, gain)
|
Overdrive.api.pointee.setGain.unsafelyUnwrapped(pointer, gain)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The level where the amplified input clips.
|
/// The level where the amplified input clips.
|
||||||
public func setLimit(_ limit: Float) {
|
public func setLimit(_ limit: Float) {
|
||||||
Overdrive.api.setLimit.unsafelyUnwrapped(pointer, limit)
|
Overdrive.api.pointee.setLimit.unsafelyUnwrapped(pointer, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var limitModulator: SignalValue? {
|
public var limitModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(Overdrive.api.getLimitModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(Overdrive.api.pointee.getLimitModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retain(newValue)
|
retain(newValue)
|
||||||
Overdrive.api.setLimitModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
Overdrive.api.pointee.setLimitModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A DC offset applied to the input, making the clipping asymmetric.
|
/// A DC offset applied to the input, making the clipping asymmetric.
|
||||||
public func setOffset(_ offset: Float) {
|
public func setOffset(_ offset: Float) {
|
||||||
Overdrive.api.setOffset.unsafelyUnwrapped(pointer, offset)
|
Overdrive.api.pointee.setOffset.unsafelyUnwrapped(pointer, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var offsetModulator: SignalValue? {
|
public var offsetModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(Overdrive.api.getOffsetModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(Overdrive.api.pointee.getOffsetModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retain(newValue)
|
retain(newValue)
|
||||||
Overdrive.api.setOffsetModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
Overdrive.api.pointee.setOffsetModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ extension Sound {
|
|||||||
/// A signal object; also provides custom signals driven by Swift
|
/// A signal object; also provides custom signals driven by Swift
|
||||||
/// callbacks. Wraps `PDSynthSignal`.
|
/// callbacks. Wraps `PDSynthSignal`.
|
||||||
public final class Signal: SignalValue {
|
public final class Signal: SignalValue {
|
||||||
private static var api: playdate_sound_signal { snd.signal.pointee }
|
private static var api: UnsafePointer<playdate_sound_signal> { snd.pointee.signal.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// Custom signal callbacks.
|
/// Custom signal callbacks.
|
||||||
public struct Callbacks {
|
public struct Callbacks {
|
||||||
@@ -62,7 +62,7 @@ extension Sound {
|
|||||||
/// Creates a signal driven by the given callbacks.
|
/// Creates a signal driven by the given callbacks.
|
||||||
public init(callbacks: Callbacks) {
|
public init(callbacks: Callbacks) {
|
||||||
let box = Unmanaged.passRetained(Box(callbacks))
|
let box = Unmanaged.passRetained(Box(callbacks))
|
||||||
let pointer = Signal.api.newSignal.unsafelyUnwrapped(
|
let pointer = Signal.api.pointee.newSignal.unsafelyUnwrapped(
|
||||||
{ userdata, ioFrames, interpolationValue in
|
{ userdata, ioFrames, interpolationValue in
|
||||||
guard let userdata else { return 0 }
|
guard let userdata else { return 0 }
|
||||||
let box = Unmanaged<Box>.fromOpaque(userdata).takeUnretainedValue()
|
let box = Unmanaged<Box>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
@@ -89,7 +89,7 @@ extension Sound {
|
|||||||
/// Creates a plain signal object wrapping an existing signal value,
|
/// Creates a plain signal object wrapping an existing signal value,
|
||||||
/// so it can be scaled and offset.
|
/// so it can be scaled and offset.
|
||||||
public init(value: SignalValue) {
|
public init(value: SignalValue) {
|
||||||
let pointer = Signal.api.newSignalForValue.unsafelyUnwrapped(value.pointer)
|
let pointer = Signal.api.pointee.newSignalForValue.unsafelyUnwrapped(value.pointer)
|
||||||
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,23 +99,23 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
Signal.api.freeSignal.unsafelyUnwrapped(pointer)
|
Signal.api.pointee.freeSignal.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The signal's current value.
|
/// The signal's current value.
|
||||||
public var value: Float {
|
public var value: Float {
|
||||||
Signal.api.getValue.unsafelyUnwrapped(pointer)
|
Signal.api.pointee.getValue.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scales the signal's output.
|
/// Scales the signal's output.
|
||||||
public func setValueScale(_ scale: Float) {
|
public func setValueScale(_ scale: Float) {
|
||||||
Signal.api.setValueScale.unsafelyUnwrapped(pointer, scale)
|
Signal.api.pointee.setValueScale.unsafelyUnwrapped(pointer, scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Offsets the signal's output.
|
/// Offsets the signal's output.
|
||||||
public func setValueOffset(_ offset: Float) {
|
public func setValueOffset(_ offset: Float) {
|
||||||
Signal.api.setValueOffset.unsafelyUnwrapped(pointer, offset)
|
Signal.api.pointee.setValueOffset.unsafelyUnwrapped(pointer, offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// A low-frequency oscillator signal. Wraps `PDSynthLFO`.
|
/// A low-frequency oscillator signal. Wraps `PDSynthLFO`.
|
||||||
public final class LFO: SignalValue {
|
public final class LFO: SignalValue {
|
||||||
private static var api: playdate_sound_lfo { snd.lfo.pointee }
|
private static var api: UnsafePointer<playdate_sound_lfo> { snd.pointee.lfo.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// The oscillator's waveform.
|
/// The oscillator's waveform.
|
||||||
public enum Shape: UInt32, Sendable {
|
public enum Shape: UInt32, Sendable {
|
||||||
@@ -142,43 +142,43 @@ extension Sound {
|
|||||||
var function: ((LFO) -> Float)?
|
var function: ((LFO) -> Float)?
|
||||||
|
|
||||||
public init(shape: Shape = .sine) {
|
public init(shape: Shape = .sine) {
|
||||||
let pointer = LFO.api.newLFO.unsafelyUnwrapped(shape.cValue)
|
let pointer = LFO.api.pointee.newLFO.unsafelyUnwrapped(shape.cValue)
|
||||||
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
LFO.api.freeLFO.unsafelyUnwrapped(pointer)
|
LFO.api.pointee.freeLFO.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setShape(_ shape: Shape) {
|
public func setShape(_ shape: Shape) {
|
||||||
LFO.api.setType.unsafelyUnwrapped(pointer, shape.cValue)
|
LFO.api.pointee.setType.unsafelyUnwrapped(pointer, shape.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The LFO rate, in cycles per second.
|
/// The LFO rate, in cycles per second.
|
||||||
public func setRate(_ rate: Float) {
|
public func setRate(_ rate: Float) {
|
||||||
LFO.api.setRate.unsafelyUnwrapped(pointer, rate)
|
LFO.api.pointee.setRate.unsafelyUnwrapped(pointer, rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current phase, 0...1.
|
/// The current phase, 0...1.
|
||||||
public func setPhase(_ phase: Float) {
|
public func setPhase(_ phase: Float) {
|
||||||
LFO.api.setPhase.unsafelyUnwrapped(pointer, phase)
|
LFO.api.pointee.setPhase.unsafelyUnwrapped(pointer, phase)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The phase the LFO starts at when a note starts, 0...1.
|
/// The phase the LFO starts at when a note starts, 0...1.
|
||||||
public func setStartPhase(_ phase: Float) {
|
public func setStartPhase(_ phase: Float) {
|
||||||
LFO.api.setStartPhase.unsafelyUnwrapped(pointer, phase)
|
LFO.api.pointee.setStartPhase.unsafelyUnwrapped(pointer, phase)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The center value of the LFO output.
|
/// The center value of the LFO output.
|
||||||
public func setCenter(_ center: Float) {
|
public func setCenter(_ center: Float) {
|
||||||
LFO.api.setCenter.unsafelyUnwrapped(pointer, center)
|
LFO.api.pointee.setCenter.unsafelyUnwrapped(pointer, center)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The amplitude of the LFO around its center.
|
/// The amplitude of the LFO around its center.
|
||||||
public func setDepth(_ depth: Float) {
|
public func setDepth(_ depth: Float) {
|
||||||
LFO.api.setDepth.unsafelyUnwrapped(pointer, depth)
|
LFO.api.pointee.setDepth.unsafelyUnwrapped(pointer, depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For `.arpeggiator` LFOs: the sequence of values (in half-steps)
|
/// For `.arpeggiator` LFOs: the sequence of values (in half-steps)
|
||||||
@@ -186,7 +186,7 @@ extension Sound {
|
|||||||
public func setArpeggiation(_ steps: [Float]) {
|
public func setArpeggiation(_ steps: [Float]) {
|
||||||
var steps = steps
|
var steps = steps
|
||||||
steps.withUnsafeMutableBufferPointer { buffer in
|
steps.withUnsafeMutableBufferPointer { buffer in
|
||||||
LFO.api.setArpeggiation.unsafelyUnwrapped(pointer, Int32(buffer.count),
|
LFO.api.pointee.setArpeggiation.unsafelyUnwrapped(pointer, Int32(buffer.count),
|
||||||
buffer.baseAddress)
|
buffer.baseAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ extension Sound {
|
|||||||
/// `interpolate` is `true`, values are interpolated between calls.
|
/// `interpolate` is `true`, values are interpolated between calls.
|
||||||
public func setFunction(interpolate: Bool = false, _ function: @escaping (LFO) -> Float) {
|
public func setFunction(interpolate: Bool = false, _ function: @escaping (LFO) -> Float) {
|
||||||
self.function = function
|
self.function = function
|
||||||
LFO.api.setFunction.unsafelyUnwrapped(pointer, { _, userdata in
|
LFO.api.pointee.setFunction.unsafelyUnwrapped(pointer, { _, userdata in
|
||||||
guard let userdata else { return 0 }
|
guard let userdata else { return 0 }
|
||||||
let lfo = Unmanaged<LFO>.fromOpaque(userdata).takeUnretainedValue()
|
let lfo = Unmanaged<LFO>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
return lfo.function?(lfo) ?? 0
|
return lfo.function?(lfo) ?? 0
|
||||||
@@ -205,26 +205,26 @@ extension Sound {
|
|||||||
/// Waits `holdoff` seconds after a note starts, then ramps the LFO
|
/// Waits `holdoff` seconds after a note starts, then ramps the LFO
|
||||||
/// depth up over `rampTime` seconds.
|
/// depth up over `rampTime` seconds.
|
||||||
public func setDelay(holdoff: Float, rampTime: Float) {
|
public func setDelay(holdoff: Float, rampTime: Float) {
|
||||||
LFO.api.setDelay.unsafelyUnwrapped(pointer, holdoff, rampTime)
|
LFO.api.pointee.setDelay.unsafelyUnwrapped(pointer, holdoff, rampTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the LFO phase restarts on every new note.
|
/// Whether the LFO phase restarts on every new note.
|
||||||
public func setRetrigger(_ flag: Bool) {
|
public func setRetrigger(_ flag: Bool) {
|
||||||
LFO.api.setRetrigger.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
LFO.api.pointee.setRetrigger.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true`, the LFO runs globally instead of per-note.
|
/// When `true`, the LFO runs globally instead of per-note.
|
||||||
public func setGlobal(_ global: Bool) {
|
public func setGlobal(_ global: Bool) {
|
||||||
LFO.api.setGlobal.unsafelyUnwrapped(pointer, global ? 1 : 0)
|
LFO.api.pointee.setGlobal.unsafelyUnwrapped(pointer, global ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Seeds the random number generator used by `.sampleAndHold` LFOs.
|
/// Seeds the random number generator used by `.sampleAndHold` LFOs.
|
||||||
public func setRandomSeed(_ seed: UInt16) {
|
public func setRandomSeed(_ seed: UInt16) {
|
||||||
LFO.api.setRandomSeed.unsafelyUnwrapped(pointer, seed)
|
LFO.api.pointee.setRandomSeed.unsafelyUnwrapped(pointer, seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var value: Float {
|
public var value: Float {
|
||||||
LFO.api.getValue.unsafelyUnwrapped(pointer)
|
LFO.api.pointee.getValue.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,12 +232,12 @@ extension Sound {
|
|||||||
|
|
||||||
/// An ADSR envelope signal. Wraps `PDSynthEnvelope`.
|
/// An ADSR envelope signal. Wraps `PDSynthEnvelope`.
|
||||||
public final class Envelope: SignalValue {
|
public final class Envelope: SignalValue {
|
||||||
private static var api: playdate_sound_envelope { snd.envelope.pointee }
|
private static var api: UnsafePointer<playdate_sound_envelope> { snd.pointee.envelope.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// Creates an envelope with the given attack and decay times
|
/// Creates an envelope with the given attack and decay times
|
||||||
/// (seconds), sustain level (0...1), and release time (seconds).
|
/// (seconds), sustain level (0...1), and release time (seconds).
|
||||||
public init(attack: Float = 0, decay: Float = 0, sustain: Float = 1, release: Float = 0) {
|
public init(attack: Float = 0, decay: Float = 0, sustain: Float = 1, release: Float = 0) {
|
||||||
let pointer = Envelope.api.newEnvelope.unsafelyUnwrapped(attack, decay, sustain, release)
|
let pointer = Envelope.api.pointee.newEnvelope.unsafelyUnwrapped(attack, decay, sustain, release)
|
||||||
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,56 +247,56 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
Envelope.api.freeEnvelope.unsafelyUnwrapped(pointer)
|
Envelope.api.pointee.freeEnvelope.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setAttack(_ attack: Float) {
|
public func setAttack(_ attack: Float) {
|
||||||
Envelope.api.setAttack.unsafelyUnwrapped(pointer, attack)
|
Envelope.api.pointee.setAttack.unsafelyUnwrapped(pointer, attack)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setDecay(_ decay: Float) {
|
public func setDecay(_ decay: Float) {
|
||||||
Envelope.api.setDecay.unsafelyUnwrapped(pointer, decay)
|
Envelope.api.pointee.setDecay.unsafelyUnwrapped(pointer, decay)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setSustain(_ sustain: Float) {
|
public func setSustain(_ sustain: Float) {
|
||||||
Envelope.api.setSustain.unsafelyUnwrapped(pointer, sustain)
|
Envelope.api.pointee.setSustain.unsafelyUnwrapped(pointer, sustain)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setRelease(_ release: Float) {
|
public func setRelease(_ release: Float) {
|
||||||
Envelope.api.setRelease.unsafelyUnwrapped(pointer, release)
|
Envelope.api.pointee.setRelease.unsafelyUnwrapped(pointer, release)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true`, a new note while a note is playing does not restart
|
/// When `true`, a new note while a note is playing does not restart
|
||||||
/// the envelope.
|
/// the envelope.
|
||||||
public func setLegato(_ flag: Bool) {
|
public func setLegato(_ flag: Bool) {
|
||||||
Envelope.api.setLegato.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
Envelope.api.pointee.setLegato.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true`, a new note restarts the envelope from zero instead of
|
/// When `true`, a new note restarts the envelope from zero instead of
|
||||||
/// its current value.
|
/// its current value.
|
||||||
public func setRetrigger(_ flag: Bool) {
|
public func setRetrigger(_ flag: Bool) {
|
||||||
Envelope.api.setRetrigger.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
Envelope.api.pointee.setRetrigger.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bends the envelope's segments: 0 is linear, 1 is maximum curvature.
|
/// Bends the envelope's segments: 0 is linear, 1 is maximum curvature.
|
||||||
public func setCurvature(_ amount: Float) {
|
public func setCurvature(_ amount: Float) {
|
||||||
Envelope.api.setCurvature.unsafelyUnwrapped(pointer, amount)
|
Envelope.api.pointee.setCurvature.unsafelyUnwrapped(pointer, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How much note velocity scales the envelope's output.
|
/// How much note velocity scales the envelope's output.
|
||||||
public func setVelocitySensitivity(_ sensitivity: Float) {
|
public func setVelocitySensitivity(_ sensitivity: Float) {
|
||||||
Envelope.api.setVelocitySensitivity.unsafelyUnwrapped(pointer, sensitivity)
|
Envelope.api.pointee.setVelocitySensitivity.unsafelyUnwrapped(pointer, sensitivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scales the envelope's rate by note: notes above `start` play the
|
/// Scales the envelope's rate by note: notes above `start` play the
|
||||||
/// envelope faster (up to `scaling` at `end` and beyond).
|
/// envelope faster (up to `scaling` at `end` and beyond).
|
||||||
public func setRateScaling(_ scaling: Float, start: MIDINote, end: MIDINote) {
|
public func setRateScaling(_ scaling: Float, start: MIDINote, end: MIDINote) {
|
||||||
Envelope.api.setRateScaling.unsafelyUnwrapped(pointer, scaling, start, end)
|
Envelope.api.pointee.setRateScaling.unsafelyUnwrapped(pointer, scaling, start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var value: Float {
|
public var value: Float {
|
||||||
Envelope.api.getValue.unsafelyUnwrapped(pointer)
|
Envelope.api.pointee.getValue.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,10 +305,10 @@ extension Sound {
|
|||||||
/// A signal whose values are set on a sequence timeline. Wraps
|
/// A signal whose values are set on a sequence timeline. Wraps
|
||||||
/// `ControlSignal`.
|
/// `ControlSignal`.
|
||||||
public final class ControlSignal: SignalValue {
|
public final class ControlSignal: SignalValue {
|
||||||
private static var api: playdate_control_signal { snd.controlsignal.pointee }
|
private static var api: UnsafePointer<playdate_control_signal> { snd.pointee.controlsignal.unsafelyUnwrapped }
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
let pointer = ControlSignal.api.newSignal.unsafelyUnwrapped()
|
let pointer = ControlSignal.api.pointee.newSignal.unsafelyUnwrapped()
|
||||||
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
super.init(pointer: pointer.unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,28 +318,28 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
ControlSignal.api.freeSignal.unsafelyUnwrapped(pointer)
|
ControlSignal.api.pointee.freeSignal.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearEvents() {
|
public func clearEvents() {
|
||||||
ControlSignal.api.clearEvents.unsafelyUnwrapped(pointer)
|
ControlSignal.api.pointee.clearEvents.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a value at `step` in the signal's timeline. If `interpolate`
|
/// Adds a value at `step` in the signal's timeline. If `interpolate`
|
||||||
/// is `true`, the value ramps from the previous event.
|
/// is `true`, the value ramps from the previous event.
|
||||||
public func addEvent(step: Int, value: Float, interpolate: Bool = false) {
|
public func addEvent(step: Int, value: Float, interpolate: Bool = false) {
|
||||||
ControlSignal.api.addEvent.unsafelyUnwrapped(pointer, Int32(step), value,
|
ControlSignal.api.pointee.addEvent.unsafelyUnwrapped(pointer, Int32(step), value,
|
||||||
interpolate ? 1 : 0)
|
interpolate ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeEvent(step: Int) {
|
public func removeEvent(step: Int) {
|
||||||
ControlSignal.api.removeEvent.unsafelyUnwrapped(pointer, Int32(step))
|
ControlSignal.api.pointee.removeEvent.unsafelyUnwrapped(pointer, Int32(step))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The MIDI controller number for signals loaded from a MIDI file.
|
/// The MIDI controller number for signals loaded from a MIDI file.
|
||||||
public var midiControllerNumber: Int {
|
public var midiControllerNumber: Int {
|
||||||
Int(ControlSignal.api.getMIDIControllerNumber.unsafelyUnwrapped(pointer))
|
Int(ControlSignal.api.pointee.getMIDIControllerNumber.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ extension Sound {
|
|||||||
/// A source of audio: the base class of `FilePlayer`, `SamplePlayer`,
|
/// A source of audio: the base class of `FilePlayer`, `SamplePlayer`,
|
||||||
/// `Synth`, `DelayLineTap`, and `CallbackSource`. Wraps `SoundSource`.
|
/// `Synth`, `DelayLineTap`, and `CallbackSource`. Wraps `SoundSource`.
|
||||||
public class Source {
|
public class Source {
|
||||||
private static var api: playdate_sound_source { snd.source.pointee }
|
private static var api: UnsafePointer<playdate_sound_source> { snd.pointee.source.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// The underlying C object. Set once, immediately after creation.
|
/// The underlying C object. Set once, immediately after creation.
|
||||||
var pointer: OpaquePointer!
|
var pointer: OpaquePointer!
|
||||||
@@ -23,7 +23,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// Sets the playback volume for the left and right channels, 0...1.
|
/// Sets the playback volume for the left and right channels, 0...1.
|
||||||
public func setVolume(left: Float, right: Float) {
|
public func setVolume(left: Float, right: Float) {
|
||||||
Source.api.setVolume.unsafelyUnwrapped(pointer, left, right)
|
Source.api.pointee.setVolume.unsafelyUnwrapped(pointer, left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the playback volume of both channels.
|
/// Sets the playback volume of both channels.
|
||||||
@@ -34,25 +34,25 @@ extension Sound {
|
|||||||
/// The playback volume of the left and right channels.
|
/// The playback volume of the left and right channels.
|
||||||
public var volume: (left: Float, right: Float) {
|
public var volume: (left: Float, right: Float) {
|
||||||
var left: Float = 0, right: Float = 0
|
var left: Float = 0, right: Float = 0
|
||||||
Source.api.getVolume.unsafelyUnwrapped(pointer, &left, &right)
|
Source.api.pointee.getVolume.unsafelyUnwrapped(pointer, &left, &right)
|
||||||
return (left, right)
|
return (left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var isPlaying: Bool {
|
public var isPlaying: Bool {
|
||||||
Source.api.isPlaying.unsafelyUnwrapped(pointer) != 0
|
Source.api.pointee.isPlaying.unsafelyUnwrapped(pointer) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a function called when the source finishes playing.
|
/// Sets a function called when the source finishes playing.
|
||||||
public func setFinishCallback(_ callback: ((Source) -> Void)?) {
|
public func setFinishCallback(_ callback: ((Source) -> Void)?) {
|
||||||
finishCallback = callback
|
finishCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
Source.api.setFinishCallback.unsafelyUnwrapped(pointer, { _, userdata in
|
Source.api.pointee.setFinishCallback.unsafelyUnwrapped(pointer, { _, userdata in
|
||||||
guard let userdata else { return }
|
guard let userdata else { return }
|
||||||
let source = Unmanaged<Source>.fromOpaque(userdata).takeUnretainedValue()
|
let source = Unmanaged<Source>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
source.finishCallback?(source)
|
source.finishCallback?(source)
|
||||||
}, Unmanaged.passUnretained(self).toOpaque())
|
}, Unmanaged.passUnretained(self).toOpaque())
|
||||||
} else {
|
} else {
|
||||||
Source.api.setFinishCallback.unsafelyUnwrapped(pointer, nil, nil)
|
Source.api.pointee.setFinishCallback.unsafelyUnwrapped(pointer, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// Streams audio from a file. Wraps `FilePlayer`.
|
/// Streams audio from a file. Wraps `FilePlayer`.
|
||||||
public final class FilePlayer: Source {
|
public final class FilePlayer: Source {
|
||||||
private static var api: playdate_sound_fileplayer { snd.fileplayer.pointee }
|
private static var api: UnsafePointer<playdate_sound_fileplayer> { snd.pointee.fileplayer.unsafelyUnwrapped }
|
||||||
|
|
||||||
var loopCallback: ((FilePlayer) -> Void)?
|
var loopCallback: ((FilePlayer) -> Void)?
|
||||||
var fadeCallback: ((FilePlayer) -> Void)?
|
var fadeCallback: ((FilePlayer) -> Void)?
|
||||||
@@ -118,7 +118,7 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: FilePlayer.api.newPlayer.unsafelyUnwrapped().unsafelyUnwrapped,
|
self.init(pointer: FilePlayer.api.pointee.newPlayer.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,14 +130,14 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
FilePlayer.api.freePlayer.unsafelyUnwrapped(pointer)
|
FilePlayer.api.pointee.freePlayer.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepares the player to stream the file at `path`.
|
/// Prepares the player to stream the file at `path`.
|
||||||
public func load(path: String) throws(PlaydateError) {
|
public func load(path: String) throws(PlaydateError) {
|
||||||
let loaded = path.withPlaydateCString {
|
let loaded = path.withPlaydateCString {
|
||||||
FilePlayer.api.loadIntoPlayer.unsafelyUnwrapped(pointer, $0) != 0
|
FilePlayer.api.pointee.loadIntoPlayer.unsafelyUnwrapped(pointer, $0) != 0
|
||||||
}
|
}
|
||||||
if !loaded {
|
if !loaded {
|
||||||
throw PlaydateError(message: "unable to load audio file: \(path)")
|
throw PlaydateError(message: "unable to load audio file: \(path)")
|
||||||
@@ -146,69 +146,69 @@ extension Sound {
|
|||||||
|
|
||||||
/// Sets the length of the stream buffer, in seconds. Default 0.25.
|
/// Sets the length of the stream buffer, in seconds. Default 0.25.
|
||||||
public func setBufferLength(_ seconds: Float) {
|
public func setBufferLength(_ seconds: Float) {
|
||||||
FilePlayer.api.setBufferLength.unsafelyUnwrapped(pointer, seconds)
|
FilePlayer.api.pointee.setBufferLength.unsafelyUnwrapped(pointer, seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts playback, looping `repeat` times; 0 loops endlessly.
|
/// Starts playback, looping `repeat` times; 0 loops endlessly.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func play(repeat repeatCount: Int = 1) -> Bool {
|
public func play(repeat repeatCount: Int = 1) -> Bool {
|
||||||
FilePlayer.api.play.unsafelyUnwrapped(pointer, Int32(repeatCount)) != 0
|
FilePlayer.api.pointee.play.unsafelyUnwrapped(pointer, Int32(repeatCount)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pause() {
|
public func pause() {
|
||||||
FilePlayer.api.pause.unsafelyUnwrapped(pointer)
|
FilePlayer.api.pointee.pause.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stop() {
|
public func stop() {
|
||||||
FilePlayer.api.stop.unsafelyUnwrapped(pointer)
|
FilePlayer.api.pointee.stop.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The file's length in seconds.
|
/// The file's length in seconds.
|
||||||
public var length: Float {
|
public var length: Float {
|
||||||
FilePlayer.api.getLength.unsafelyUnwrapped(pointer)
|
FilePlayer.api.pointee.getLength.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The playback position in seconds.
|
/// The playback position in seconds.
|
||||||
public var offset: Float {
|
public var offset: Float {
|
||||||
get { FilePlayer.api.getOffset.unsafelyUnwrapped(pointer) }
|
get { FilePlayer.api.pointee.getOffset.unsafelyUnwrapped(pointer) }
|
||||||
set { FilePlayer.api.setOffset.unsafelyUnwrapped(pointer, newValue) }
|
set { FilePlayer.api.pointee.setOffset.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The playback rate; 1 is normal speed, negative values are not
|
/// The playback rate; 1 is normal speed, negative values are not
|
||||||
/// supported.
|
/// supported.
|
||||||
public var rate: Float {
|
public var rate: Float {
|
||||||
get { FilePlayer.api.getRate.unsafelyUnwrapped(pointer) }
|
get { FilePlayer.api.pointee.getRate.unsafelyUnwrapped(pointer) }
|
||||||
set { FilePlayer.api.setRate.unsafelyUnwrapped(pointer, newValue) }
|
set { FilePlayer.api.pointee.setRate.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loops playback between `start` and `end` (seconds) while playing
|
/// Loops playback between `start` and `end` (seconds) while playing
|
||||||
/// with `repeat` 0. An `end` of 0 means the end of the file.
|
/// with `repeat` 0. An `end` of 0 means the end of the file.
|
||||||
public func setLoopRange(start: Float, end: Float) {
|
public func setLoopRange(start: Float, end: Float) {
|
||||||
FilePlayer.api.setLoopRange.unsafelyUnwrapped(pointer, start, end)
|
FilePlayer.api.pointee.setLoopRange.unsafelyUnwrapped(pointer, start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether playback underran because the file could not be read fast
|
/// Whether playback underran because the file could not be read fast
|
||||||
/// enough.
|
/// enough.
|
||||||
public var didUnderrun: Bool {
|
public var didUnderrun: Bool {
|
||||||
FilePlayer.api.didUnderrun.unsafelyUnwrapped(pointer) != 0
|
FilePlayer.api.pointee.didUnderrun.unsafelyUnwrapped(pointer) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stops playback (instead of looping the buffer) on underrun.
|
/// Stops playback (instead of looping the buffer) on underrun.
|
||||||
public func setStopOnUnderrun(_ flag: Bool) {
|
public func setStopOnUnderrun(_ flag: Bool) {
|
||||||
FilePlayer.api.setStopOnUnderrun.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
FilePlayer.api.pointee.setStopOnUnderrun.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a function called every time playback loops.
|
/// Sets a function called every time playback loops.
|
||||||
public func setLoopCallback(_ callback: ((FilePlayer) -> Void)?) {
|
public func setLoopCallback(_ callback: ((FilePlayer) -> Void)?) {
|
||||||
loopCallback = callback
|
loopCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
FilePlayer.api.setLoopCallback.unsafelyUnwrapped(pointer, { _, userdata in
|
FilePlayer.api.pointee.setLoopCallback.unsafelyUnwrapped(pointer, { _, userdata in
|
||||||
guard let userdata else { return }
|
guard let userdata else { return }
|
||||||
let player = Unmanaged<FilePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
let player = Unmanaged<FilePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
player.loopCallback?(player)
|
player.loopCallback?(player)
|
||||||
}, Unmanaged.passUnretained(self).toOpaque())
|
}, Unmanaged.passUnretained(self).toOpaque())
|
||||||
} else {
|
} else {
|
||||||
FilePlayer.api.setLoopCallback.unsafelyUnwrapped(pointer, nil, nil)
|
FilePlayer.api.pointee.setLoopCallback.unsafelyUnwrapped(pointer, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,13 +218,13 @@ extension Sound {
|
|||||||
completion: ((FilePlayer) -> Void)? = nil) {
|
completion: ((FilePlayer) -> Void)? = nil) {
|
||||||
fadeCallback = completion
|
fadeCallback = completion
|
||||||
if completion != nil {
|
if completion != nil {
|
||||||
FilePlayer.api.fadeVolume.unsafelyUnwrapped(pointer, left, right, length, { _, userdata in
|
FilePlayer.api.pointee.fadeVolume.unsafelyUnwrapped(pointer, left, right, length, { _, userdata in
|
||||||
guard let userdata else { return }
|
guard let userdata else { return }
|
||||||
let player = Unmanaged<FilePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
let player = Unmanaged<FilePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
player.fadeCallback?(player)
|
player.fadeCallback?(player)
|
||||||
}, Unmanaged.passUnretained(self).toOpaque())
|
}, Unmanaged.passUnretained(self).toOpaque())
|
||||||
} else {
|
} else {
|
||||||
FilePlayer.api.fadeVolume.unsafelyUnwrapped(pointer, left, right, length, nil, nil)
|
FilePlayer.api.pointee.fadeVolume.unsafelyUnwrapped(pointer, left, right, length, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ extension Sound {
|
|||||||
public func setMP3StreamSource(bufferLength: Float,
|
public func setMP3StreamSource(bufferLength: Float,
|
||||||
_ dataSource: @escaping (UnsafeMutableBufferPointer<UInt8>) -> Int) {
|
_ dataSource: @escaping (UnsafeMutableBufferPointer<UInt8>) -> Int) {
|
||||||
mp3DataSource = dataSource
|
mp3DataSource = dataSource
|
||||||
FilePlayer.api.setMP3StreamSource.unsafelyUnwrapped(pointer, { data, bytes, userdata in
|
FilePlayer.api.pointee.setMP3StreamSource.unsafelyUnwrapped(pointer, { data, bytes, userdata in
|
||||||
guard let userdata, let data else { return 0 }
|
guard let userdata, let data else { return 0 }
|
||||||
let player = Unmanaged<FilePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
let player = Unmanaged<FilePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
let buffer = UnsafeMutableBufferPointer(start: data, count: Int(bytes))
|
let buffer = UnsafeMutableBufferPointer(start: data, count: Int(bytes))
|
||||||
@@ -244,10 +244,10 @@ extension Sound {
|
|||||||
|
|
||||||
/// Modulates the playback rate.
|
/// Modulates the playback rate.
|
||||||
public var rateModulator: SignalValue? {
|
public var rateModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(FilePlayer.api.getRateModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(FilePlayer.api.pointee.getRateModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedRateModulator = newValue
|
retainedRateModulator = newValue
|
||||||
FilePlayer.api.setRateModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
FilePlayer.api.pointee.setRateModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// Audio data loaded into memory. Wraps `AudioSample`.
|
/// Audio data loaded into memory. Wraps `AudioSample`.
|
||||||
public final class AudioSample {
|
public final class AudioSample {
|
||||||
private static var api: playdate_sound_sample { snd.sample.pointee }
|
private static var api: UnsafePointer<playdate_sound_sample> { snd.pointee.sample.unsafelyUnwrapped }
|
||||||
|
|
||||||
let pointer: OpaquePointer
|
let pointer: OpaquePointer
|
||||||
let isOwned: Bool
|
let isOwned: Bool
|
||||||
@@ -268,13 +268,13 @@ extension Sound {
|
|||||||
|
|
||||||
/// Allocates a sample buffer with room for `byteCount` bytes.
|
/// Allocates a sample buffer with room for `byteCount` bytes.
|
||||||
public convenience init(byteCount: Int) {
|
public convenience init(byteCount: Int) {
|
||||||
self.init(pointer: AudioSample.api.newSampleBuffer.unsafelyUnwrapped(
|
self.init(pointer: AudioSample.api.pointee.newSampleBuffer.unsafelyUnwrapped(
|
||||||
Int32(byteCount)).unsafelyUnwrapped, isOwned: true)
|
Int32(byteCount)).unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the wav or aiff file at `path`.
|
/// Loads the wav or aiff file at `path`.
|
||||||
public convenience init(path: String) throws(PlaydateError) {
|
public convenience init(path: String) throws(PlaydateError) {
|
||||||
let pointer = path.withPlaydateCString { AudioSample.api.load.unsafelyUnwrapped($0) }
|
let pointer = path.withPlaydateCString { AudioSample.api.pointee.load.unsafelyUnwrapped($0) }
|
||||||
guard let pointer else {
|
guard let pointer else {
|
||||||
throw PlaydateError(message: "unable to load sample: \(path)")
|
throw PlaydateError(message: "unable to load sample: \(path)")
|
||||||
}
|
}
|
||||||
@@ -287,7 +287,7 @@ extension Sound {
|
|||||||
/// sample's lifetime.
|
/// sample's lifetime.
|
||||||
public convenience init?(data: UnsafeMutablePointer<UInt8>, format: Format,
|
public convenience init?(data: UnsafeMutablePointer<UInt8>, format: Format,
|
||||||
sampleRate: UInt32, byteCount: Int, freeWhenDone: Bool) {
|
sampleRate: UInt32, byteCount: Int, freeWhenDone: Bool) {
|
||||||
guard let pointer = AudioSample.api.newSampleFromData.unsafelyUnwrapped(
|
guard let pointer = AudioSample.api.pointee.newSampleFromData.unsafelyUnwrapped(
|
||||||
data, format.cValue, sampleRate, Int32(byteCount), freeWhenDone ? 1 : 0) else {
|
data, format.cValue, sampleRate, Int32(byteCount), freeWhenDone ? 1 : 0) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -296,14 +296,14 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
AudioSample.api.freeSample.unsafelyUnwrapped(pointer)
|
AudioSample.api.pointee.freeSample.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the file at `path` into this sample's buffer.
|
/// Loads the file at `path` into this sample's buffer.
|
||||||
public func load(path: String) throws(PlaydateError) {
|
public func load(path: String) throws(PlaydateError) {
|
||||||
let loaded = path.withPlaydateCString {
|
let loaded = path.withPlaydateCString {
|
||||||
AudioSample.api.loadIntoSample.unsafelyUnwrapped(pointer, $0) != 0
|
AudioSample.api.pointee.loadIntoSample.unsafelyUnwrapped(pointer, $0) != 0
|
||||||
}
|
}
|
||||||
if !loaded {
|
if !loaded {
|
||||||
throw PlaydateError(message: "unable to load sample: \(path)")
|
throw PlaydateError(message: "unable to load sample: \(path)")
|
||||||
@@ -316,20 +316,20 @@ extension Sound {
|
|||||||
var data: UnsafeMutablePointer<UInt8>?
|
var data: UnsafeMutablePointer<UInt8>?
|
||||||
var format = kSound16bitMono
|
var format = kSound16bitMono
|
||||||
var sampleRate: UInt32 = 0, byteLength: UInt32 = 0
|
var sampleRate: UInt32 = 0, byteLength: UInt32 = 0
|
||||||
AudioSample.api.getData.unsafelyUnwrapped(pointer, &data, &format, &sampleRate, &byteLength)
|
AudioSample.api.pointee.getData.unsafelyUnwrapped(pointer, &data, &format, &sampleRate, &byteLength)
|
||||||
return (data, Format(format), sampleRate, byteLength)
|
return (data, Format(format), sampleRate, byteLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sample's length in seconds.
|
/// The sample's length in seconds.
|
||||||
public var length: Float {
|
public var length: Float {
|
||||||
AudioSample.api.getLength.unsafelyUnwrapped(pointer)
|
AudioSample.api.pointee.getLength.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decompresses an ADPCM sample to 16-bit PCM so it can be used in a
|
/// Decompresses an ADPCM sample to 16-bit PCM so it can be used in a
|
||||||
/// synth. Returns `false` if there is not enough memory.
|
/// synth. Returns `false` if there is not enough memory.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func decompress() -> Bool {
|
public func decompress() -> Bool {
|
||||||
AudioSample.api.decompress.unsafelyUnwrapped(pointer) != 0
|
AudioSample.api.pointee.decompress.unsafelyUnwrapped(pointer) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// Plays an `AudioSample` from memory. Wraps `SamplePlayer`.
|
/// Plays an `AudioSample` from memory. Wraps `SamplePlayer`.
|
||||||
public final class SamplePlayer: Source {
|
public final class SamplePlayer: Source {
|
||||||
private static var api: playdate_sound_sampleplayer { snd.sampleplayer.pointee }
|
private static var api: UnsafePointer<playdate_sound_sampleplayer> { snd.pointee.sampleplayer.unsafelyUnwrapped }
|
||||||
|
|
||||||
var loopCallback: ((SamplePlayer) -> Void)?
|
var loopCallback: ((SamplePlayer) -> Void)?
|
||||||
private var retainedSample: AudioSample?
|
private var retainedSample: AudioSample?
|
||||||
@@ -348,7 +348,7 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: SamplePlayer.api.newPlayer.unsafelyUnwrapped().unsafelyUnwrapped,
|
self.init(pointer: SamplePlayer.api.pointee.newPlayer.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +360,7 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
SamplePlayer.api.freePlayer.unsafelyUnwrapped(pointer)
|
SamplePlayer.api.pointee.freePlayer.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ extension Sound {
|
|||||||
get { retainedSample }
|
get { retainedSample }
|
||||||
set {
|
set {
|
||||||
retainedSample = newValue
|
retainedSample = newValue
|
||||||
SamplePlayer.api.setSample.unsafelyUnwrapped(pointer, newValue?.pointer)
|
SamplePlayer.api.pointee.setSample.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,59 +377,59 @@ extension Sound {
|
|||||||
/// endlessly, -1 loops ping-pong.
|
/// endlessly, -1 loops ping-pong.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func play(repeat repeatCount: Int = 1, rate: Float = 1) -> Bool {
|
public func play(repeat repeatCount: Int = 1, rate: Float = 1) -> Bool {
|
||||||
SamplePlayer.api.play.unsafelyUnwrapped(pointer, Int32(repeatCount), rate) != 0
|
SamplePlayer.api.pointee.play.unsafelyUnwrapped(pointer, Int32(repeatCount), rate) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stop() {
|
public func stop() {
|
||||||
SamplePlayer.api.stop.unsafelyUnwrapped(pointer)
|
SamplePlayer.api.pointee.stop.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setPaused(_ paused: Bool) {
|
public func setPaused(_ paused: Bool) {
|
||||||
SamplePlayer.api.setPaused.unsafelyUnwrapped(pointer, paused ? 1 : 0)
|
SamplePlayer.api.pointee.setPaused.unsafelyUnwrapped(pointer, paused ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sample's length in seconds.
|
/// The sample's length in seconds.
|
||||||
public var length: Float {
|
public var length: Float {
|
||||||
SamplePlayer.api.getLength.unsafelyUnwrapped(pointer)
|
SamplePlayer.api.pointee.getLength.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The playback position in seconds.
|
/// The playback position in seconds.
|
||||||
public var offset: Float {
|
public var offset: Float {
|
||||||
get { SamplePlayer.api.getOffset.unsafelyUnwrapped(pointer) }
|
get { SamplePlayer.api.pointee.getOffset.unsafelyUnwrapped(pointer) }
|
||||||
set { SamplePlayer.api.setOffset.unsafelyUnwrapped(pointer, newValue) }
|
set { SamplePlayer.api.pointee.setOffset.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The playback rate; 1 is normal speed, negative plays backward.
|
/// The playback rate; 1 is normal speed, negative plays backward.
|
||||||
public var rate: Float {
|
public var rate: Float {
|
||||||
get { SamplePlayer.api.getRate.unsafelyUnwrapped(pointer) }
|
get { SamplePlayer.api.pointee.getRate.unsafelyUnwrapped(pointer) }
|
||||||
set { SamplePlayer.api.setRate.unsafelyUnwrapped(pointer, newValue) }
|
set { SamplePlayer.api.pointee.setRate.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restricts playback to the given range of sample frames.
|
/// Restricts playback to the given range of sample frames.
|
||||||
public func setPlayRange(start: Int, end: Int) {
|
public func setPlayRange(start: Int, end: Int) {
|
||||||
SamplePlayer.api.setPlayRange.unsafelyUnwrapped(pointer, Int32(start), Int32(end))
|
SamplePlayer.api.pointee.setPlayRange.unsafelyUnwrapped(pointer, Int32(start), Int32(end))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a function called every time playback loops.
|
/// Sets a function called every time playback loops.
|
||||||
public func setLoopCallback(_ callback: ((SamplePlayer) -> Void)?) {
|
public func setLoopCallback(_ callback: ((SamplePlayer) -> Void)?) {
|
||||||
loopCallback = callback
|
loopCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
SamplePlayer.api.setLoopCallback.unsafelyUnwrapped(pointer, { _, userdata in
|
SamplePlayer.api.pointee.setLoopCallback.unsafelyUnwrapped(pointer, { _, userdata in
|
||||||
guard let userdata else { return }
|
guard let userdata else { return }
|
||||||
let player = Unmanaged<SamplePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
let player = Unmanaged<SamplePlayer>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
player.loopCallback?(player)
|
player.loopCallback?(player)
|
||||||
}, Unmanaged.passUnretained(self).toOpaque())
|
}, Unmanaged.passUnretained(self).toOpaque())
|
||||||
} else {
|
} else {
|
||||||
SamplePlayer.api.setLoopCallback.unsafelyUnwrapped(pointer, nil, nil)
|
SamplePlayer.api.pointee.setLoopCallback.unsafelyUnwrapped(pointer, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modulates the playback rate.
|
/// Modulates the playback rate.
|
||||||
public var rateModulator: SignalValue? {
|
public var rateModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(SamplePlayer.api.getRateModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(SamplePlayer.api.pointee.getRateModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retainedRateModulator = newValue
|
retainedRateModulator = newValue
|
||||||
SamplePlayer.api.setRateModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
SamplePlayer.api.pointee.setRateModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ internal import CPlaydate
|
|||||||
extension Sound {
|
extension Sound {
|
||||||
/// A synthesizer voice. Wraps `PDSynth`.
|
/// A synthesizer voice. Wraps `PDSynth`.
|
||||||
public final class Synth: Source {
|
public final class Synth: Source {
|
||||||
private static var api: playdate_sound_synth { snd.synth.pointee }
|
private static var api: UnsafePointer<playdate_sound_synth> { snd.pointee.synth.unsafelyUnwrapped }
|
||||||
|
|
||||||
/// The synth's waveform.
|
/// The synth's waveform.
|
||||||
public enum Waveform: UInt32, Sendable {
|
public enum Waveform: UInt32, Sendable {
|
||||||
@@ -72,7 +72,7 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: Synth.api.newSynth.unsafelyUnwrapped().unsafelyUnwrapped,
|
self.init(pointer: Synth.api.pointee.newSynth.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,27 +83,27 @@ extension Sound {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
Synth.api.freeSynth.unsafelyUnwrapped(pointer)
|
Synth.api.pointee.freeSynth.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copies the synth (and its generator, if any).
|
/// Copies the synth (and its generator, if any).
|
||||||
public func copy() -> Synth {
|
public func copy() -> Synth {
|
||||||
Synth(pointer: Synth.api.copy.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
Synth(pointer: Synth.api.pointee.copy.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Sound generation
|
// MARK: Sound generation
|
||||||
|
|
||||||
public func setWaveform(_ waveform: Waveform) {
|
public func setWaveform(_ waveform: Waveform) {
|
||||||
Synth.api.setWaveform.unsafelyUnwrapped(pointer, waveform.cValue)
|
Synth.api.pointee.setWaveform.unsafelyUnwrapped(pointer, waveform.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Plays a sample instead of a waveform. A nonzero sustain range
|
/// Plays a sample instead of a waveform. A nonzero sustain range
|
||||||
/// loops that part of the sample while the note is held.
|
/// loops that part of the sample while the note is held.
|
||||||
public func setSample(_ sample: AudioSample, sustainStart: UInt32 = 0, sustainEnd: UInt32 = 0) {
|
public func setSample(_ sample: AudioSample, sustainStart: UInt32 = 0, sustainEnd: UInt32 = 0) {
|
||||||
retainedSample = sample
|
retainedSample = sample
|
||||||
Synth.api.setSample.unsafelyUnwrapped(pointer, sample.pointer, sustainStart, sustainEnd)
|
Synth.api.pointee.setSample.unsafelyUnwrapped(pointer, sample.pointer, sustainStart, sustainEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses a wavetable for the synth. `log2size` is the base-2 log of
|
/// Uses a wavetable for the synth. `log2size` is the base-2 log of
|
||||||
@@ -111,7 +111,7 @@ extension Sound {
|
|||||||
public func setWavetable(_ sample: AudioSample, log2size: Int,
|
public func setWavetable(_ sample: AudioSample, log2size: Int,
|
||||||
columns: Int, rows: Int) throws(PlaydateError) {
|
columns: Int, rows: Int) throws(PlaydateError) {
|
||||||
retainedSample = sample
|
retainedSample = sample
|
||||||
guard Synth.api.setWavetable.unsafelyUnwrapped(
|
guard Synth.api.pointee.setWavetable.unsafelyUnwrapped(
|
||||||
pointer, sample.pointer, Int32(log2size), Int32(columns), Int32(rows)) != 0 else {
|
pointer, sample.pointer, Int32(log2size), Int32(columns), Int32(rows)) != 0 else {
|
||||||
throw PlaydateError(message: "invalid wavetable dimensions")
|
throw PlaydateError(message: "invalid wavetable dimensions")
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ extension Sound {
|
|||||||
/// Provides audio via custom Swift callbacks.
|
/// Provides audio via custom Swift callbacks.
|
||||||
public func setGenerator(stereo: Bool, _ generator: Generator) {
|
public func setGenerator(stereo: Bool, _ generator: Generator) {
|
||||||
let box = Unmanaged.passRetained(GeneratorBox(generator, stereo: stereo))
|
let box = Unmanaged.passRetained(GeneratorBox(generator, stereo: stereo))
|
||||||
Synth.api.setGenerator.unsafelyUnwrapped(
|
Synth.api.pointee.setGenerator.unsafelyUnwrapped(
|
||||||
pointer, stereo ? 1 : 0,
|
pointer, stereo ? 1 : 0,
|
||||||
{ userdata, left, right, nsamples, rate, drate in
|
{ userdata, left, right, nsamples, rate, drate in
|
||||||
guard let userdata, let left else { return 0 }
|
guard let userdata, let left else { return 0 }
|
||||||
@@ -159,75 +159,75 @@ extension Sound {
|
|||||||
// MARK: Envelope
|
// MARK: Envelope
|
||||||
|
|
||||||
public func setAttackTime(_ attack: Float) {
|
public func setAttackTime(_ attack: Float) {
|
||||||
Synth.api.setAttackTime.unsafelyUnwrapped(pointer, attack)
|
Synth.api.pointee.setAttackTime.unsafelyUnwrapped(pointer, attack)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setDecayTime(_ decay: Float) {
|
public func setDecayTime(_ decay: Float) {
|
||||||
Synth.api.setDecayTime.unsafelyUnwrapped(pointer, decay)
|
Synth.api.pointee.setDecayTime.unsafelyUnwrapped(pointer, decay)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setSustainLevel(_ sustain: Float) {
|
public func setSustainLevel(_ sustain: Float) {
|
||||||
Synth.api.setSustainLevel.unsafelyUnwrapped(pointer, sustain)
|
Synth.api.pointee.setSustainLevel.unsafelyUnwrapped(pointer, sustain)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setReleaseTime(_ release: Float) {
|
public func setReleaseTime(_ release: Float) {
|
||||||
Synth.api.setReleaseTime.unsafelyUnwrapped(pointer, release)
|
Synth.api.pointee.setReleaseTime.unsafelyUnwrapped(pointer, release)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The synth's amplitude envelope. Owned by the synth.
|
/// The synth's amplitude envelope. Owned by the synth.
|
||||||
public var envelope: Envelope? {
|
public var envelope: Envelope? {
|
||||||
guard let envelope = Synth.api.getEnvelope.unsafelyUnwrapped(pointer) else { return nil }
|
guard let envelope = Synth.api.pointee.getEnvelope.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Envelope(pointer: envelope, isOwned: false)
|
return Envelope(pointer: envelope, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears the synth's envelope so it plays at constant volume.
|
/// Clears the synth's envelope so it plays at constant volume.
|
||||||
public func clearEnvelope() {
|
public func clearEnvelope() {
|
||||||
Synth.api.clearEnvelope.unsafelyUnwrapped(pointer)
|
Synth.api.pointee.clearEnvelope.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Modulation
|
// MARK: Modulation
|
||||||
|
|
||||||
/// Transposes played notes by `halfSteps` (fractional values allowed).
|
/// Transposes played notes by `halfSteps` (fractional values allowed).
|
||||||
public func setTranspose(_ halfSteps: Float) {
|
public func setTranspose(_ halfSteps: Float) {
|
||||||
Synth.api.setTranspose.unsafelyUnwrapped(pointer, halfSteps)
|
Synth.api.pointee.setTranspose.unsafelyUnwrapped(pointer, halfSteps)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var frequencyModulator: SignalValue? {
|
public var frequencyModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(Synth.api.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(Synth.api.pointee.getFrequencyModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retain(newValue)
|
retain(newValue)
|
||||||
Synth.api.setFrequencyModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
Synth.api.pointee.setFrequencyModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var amplitudeModulator: SignalValue? {
|
public var amplitudeModulator: SignalValue? {
|
||||||
get { SignalValue.wrap(Synth.api.getAmplitudeModulator.unsafelyUnwrapped(pointer)) }
|
get { SignalValue.wrap(Synth.api.pointee.getAmplitudeModulator.unsafelyUnwrapped(pointer)) }
|
||||||
set {
|
set {
|
||||||
retain(newValue)
|
retain(newValue)
|
||||||
Synth.api.setAmplitudeModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
Synth.api.pointee.setAmplitudeModulator.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of parameters the synth's generator supports.
|
/// The number of parameters the synth's generator supports.
|
||||||
public var parameterCount: Int {
|
public var parameterCount: Int {
|
||||||
Int(Synth.api.getParameterCount.unsafelyUnwrapped(pointer))
|
Int(Synth.api.pointee.getParameterCount.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a generator parameter. Returns `false` if the parameter is
|
/// Sets a generator parameter. Returns `false` if the parameter is
|
||||||
/// invalid.
|
/// invalid.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func setParameter(_ parameter: Int, value: Float) -> Bool {
|
public func setParameter(_ parameter: Int, value: Float) -> Bool {
|
||||||
Synth.api.setParameter.unsafelyUnwrapped(pointer, Int32(parameter), value) != 0
|
Synth.api.pointee.setParameter.unsafelyUnwrapped(pointer, Int32(parameter), value) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setParameterModulator(_ parameter: Int, _ modulator: SignalValue?) {
|
public func setParameterModulator(_ parameter: Int, _ modulator: SignalValue?) {
|
||||||
retain(modulator)
|
retain(modulator)
|
||||||
Synth.api.setParameterModulator.unsafelyUnwrapped(pointer, Int32(parameter),
|
Synth.api.pointee.setParameterModulator.unsafelyUnwrapped(pointer, Int32(parameter),
|
||||||
modulator?.pointer)
|
modulator?.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parameterModulator(_ parameter: Int) -> SignalValue? {
|
public func parameterModulator(_ parameter: Int) -> SignalValue? {
|
||||||
SignalValue.wrap(Synth.api.getParameterModulator.unsafelyUnwrapped(pointer, Int32(parameter)))
|
SignalValue.wrap(Synth.api.pointee.getParameterModulator.unsafelyUnwrapped(pointer, Int32(parameter)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func retain(_ modulator: SignalValue?) {
|
private func retain(_ modulator: SignalValue?) {
|
||||||
@@ -243,23 +243,23 @@ extension Sound {
|
|||||||
/// or 0 for immediately.
|
/// or 0 for immediately.
|
||||||
public func playNote(frequency: Float, velocity: Float = 1,
|
public func playNote(frequency: Float, velocity: Float = 1,
|
||||||
length: Float? = nil, when: UInt32 = 0) {
|
length: Float? = nil, when: UInt32 = 0) {
|
||||||
Synth.api.playNote.unsafelyUnwrapped(pointer, frequency, velocity, length ?? -1, when)
|
Synth.api.pointee.playNote.unsafelyUnwrapped(pointer, frequency, velocity, length ?? -1, when)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Plays a MIDI note, where 60 is middle C.
|
/// Plays a MIDI note, where 60 is middle C.
|
||||||
public func playMIDINote(_ note: MIDINote, velocity: Float = 1,
|
public func playMIDINote(_ note: MIDINote, velocity: Float = 1,
|
||||||
length: Float? = nil, when: UInt32 = 0) {
|
length: Float? = nil, when: UInt32 = 0) {
|
||||||
Synth.api.playMIDINote.unsafelyUnwrapped(pointer, note, velocity, length ?? -1, when)
|
Synth.api.pointee.playMIDINote.unsafelyUnwrapped(pointer, note, velocity, length ?? -1, when)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases the playing note at time `when`, or immediately if 0.
|
/// Releases the playing note at time `when`, or immediately if 0.
|
||||||
public func noteOff(when: UInt32 = 0) {
|
public func noteOff(when: UInt32 = 0) {
|
||||||
Synth.api.noteOff.unsafelyUnwrapped(pointer, when)
|
Synth.api.pointee.noteOff.unsafelyUnwrapped(pointer, when)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stops the synth immediately, without playing the release phase.
|
/// Stops the synth immediately, without playing the release phase.
|
||||||
public func stop() {
|
public func stop() {
|
||||||
Synth.api.stop.unsafelyUnwrapped(pointer)
|
Synth.api.pointee.stop.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +268,7 @@ extension Sound {
|
|||||||
/// A bank of synth voices for playing a sequence track. Wraps
|
/// A bank of synth voices for playing a sequence track. Wraps
|
||||||
/// `PDSynthInstrument`.
|
/// `PDSynthInstrument`.
|
||||||
public final class Instrument {
|
public final class Instrument {
|
||||||
private static var api: playdate_sound_instrument { snd.instrument.pointee }
|
private static var api: UnsafePointer<playdate_sound_instrument> { snd.pointee.instrument.unsafelyUnwrapped }
|
||||||
|
|
||||||
let pointer: OpaquePointer
|
let pointer: OpaquePointer
|
||||||
let isOwned: Bool
|
let isOwned: Bool
|
||||||
@@ -280,13 +280,13 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: Instrument.api.newInstrument.unsafelyUnwrapped().unsafelyUnwrapped,
|
self.init(pointer: Instrument.api.pointee.newInstrument.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
Instrument.api.freeInstrument.unsafelyUnwrapped(pointer)
|
Instrument.api.pointee.freeInstrument.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +296,7 @@ extension Sound {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public func addVoice(_ synth: Synth, rangeStart: MIDINote = 0, rangeEnd: MIDINote = 127,
|
public func addVoice(_ synth: Synth, rangeStart: MIDINote = 0, rangeEnd: MIDINote = 127,
|
||||||
transpose: Float = 0) -> Bool {
|
transpose: Float = 0) -> Bool {
|
||||||
let added = Instrument.api.addVoice.unsafelyUnwrapped(
|
let added = Instrument.api.pointee.addVoice.unsafelyUnwrapped(
|
||||||
pointer, synth.pointer, rangeStart, rangeEnd, transpose) != 0
|
pointer, synth.pointer, rangeStart, rangeEnd, transpose) != 0
|
||||||
if added, !retainedVoices.contains(where: { $0 === synth }) {
|
if added, !retainedVoices.contains(where: { $0 === synth }) {
|
||||||
retainedVoices.append(synth)
|
retainedVoices.append(synth)
|
||||||
@@ -309,7 +309,7 @@ extension Sound {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public func playNote(frequency: Float, velocity: Float = 1,
|
public func playNote(frequency: Float, velocity: Float = 1,
|
||||||
length: Float? = nil, when: UInt32 = 0) -> Synth? {
|
length: Float? = nil, when: UInt32 = 0) -> Synth? {
|
||||||
let synth = Instrument.api.playNote.unsafelyUnwrapped(
|
let synth = Instrument.api.pointee.playNote.unsafelyUnwrapped(
|
||||||
pointer, frequency, velocity, length ?? -1, when)
|
pointer, frequency, velocity, length ?? -1, when)
|
||||||
return voice(for: synth)
|
return voice(for: synth)
|
||||||
}
|
}
|
||||||
@@ -318,7 +318,7 @@ extension Sound {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public func playMIDINote(_ note: MIDINote, velocity: Float = 1,
|
public func playMIDINote(_ note: MIDINote, velocity: Float = 1,
|
||||||
length: Float? = nil, when: UInt32 = 0) -> Synth? {
|
length: Float? = nil, when: UInt32 = 0) -> Synth? {
|
||||||
let synth = Instrument.api.playMIDINote.unsafelyUnwrapped(
|
let synth = Instrument.api.pointee.playMIDINote.unsafelyUnwrapped(
|
||||||
pointer, note, velocity, length ?? -1, when)
|
pointer, note, velocity, length ?? -1, when)
|
||||||
return voice(for: synth)
|
return voice(for: synth)
|
||||||
}
|
}
|
||||||
@@ -333,38 +333,38 @@ extension Sound {
|
|||||||
|
|
||||||
/// Bends played notes by `bend` × the pitch bend range.
|
/// Bends played notes by `bend` × the pitch bend range.
|
||||||
public func setPitchBend(_ bend: Float) {
|
public func setPitchBend(_ bend: Float) {
|
||||||
Instrument.api.setPitchBend.unsafelyUnwrapped(pointer, bend)
|
Instrument.api.pointee.setPitchBend.unsafelyUnwrapped(pointer, bend)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setPitchBendRange(halfSteps: Float) {
|
public func setPitchBendRange(halfSteps: Float) {
|
||||||
Instrument.api.setPitchBendRange.unsafelyUnwrapped(pointer, halfSteps)
|
Instrument.api.pointee.setPitchBendRange.unsafelyUnwrapped(pointer, halfSteps)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setTranspose(halfSteps: Float) {
|
public func setTranspose(halfSteps: Float) {
|
||||||
Instrument.api.setTranspose.unsafelyUnwrapped(pointer, halfSteps)
|
Instrument.api.pointee.setTranspose.unsafelyUnwrapped(pointer, halfSteps)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases the voice playing `note` at time `when` (0 = now).
|
/// Releases the voice playing `note` at time `when` (0 = now).
|
||||||
public func noteOff(_ note: MIDINote, when: UInt32 = 0) {
|
public func noteOff(_ note: MIDINote, when: UInt32 = 0) {
|
||||||
Instrument.api.noteOff.unsafelyUnwrapped(pointer, note, when)
|
Instrument.api.pointee.noteOff.unsafelyUnwrapped(pointer, note, when)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func allNotesOff(when: UInt32 = 0) {
|
public func allNotesOff(when: UInt32 = 0) {
|
||||||
Instrument.api.allNotesOff.unsafelyUnwrapped(pointer, when)
|
Instrument.api.pointee.allNotesOff.unsafelyUnwrapped(pointer, when)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setVolume(left: Float, right: Float) {
|
public func setVolume(left: Float, right: Float) {
|
||||||
Instrument.api.setVolume.unsafelyUnwrapped(pointer, left, right)
|
Instrument.api.pointee.setVolume.unsafelyUnwrapped(pointer, left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var volume: (left: Float, right: Float) {
|
public var volume: (left: Float, right: Float) {
|
||||||
var left: Float = 0, right: Float = 0
|
var left: Float = 0, right: Float = 0
|
||||||
Instrument.api.getVolume.unsafelyUnwrapped(pointer, &left, &right)
|
Instrument.api.pointee.getVolume.unsafelyUnwrapped(pointer, &left, &right)
|
||||||
return (left, right)
|
return (left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var activeVoiceCount: Int {
|
public var activeVoiceCount: Int {
|
||||||
Int(Instrument.api.activeVoiceCount.unsafelyUnwrapped(pointer))
|
Int(Instrument.api.pointee.activeVoiceCount.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +372,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// A track of notes played by an instrument. Wraps `SequenceTrack`.
|
/// A track of notes played by an instrument. Wraps `SequenceTrack`.
|
||||||
public final class SequenceTrack {
|
public final class SequenceTrack {
|
||||||
private static var api: playdate_sound_track { snd.track.pointee }
|
private static var api: UnsafePointer<playdate_sound_track> { snd.pointee.track.unsafelyUnwrapped }
|
||||||
|
|
||||||
let pointer: OpaquePointer
|
let pointer: OpaquePointer
|
||||||
let isOwned: Bool
|
let isOwned: Bool
|
||||||
@@ -384,13 +384,13 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: SequenceTrack.api.newTrack.unsafelyUnwrapped().unsafelyUnwrapped,
|
self.init(pointer: SequenceTrack.api.pointee.newTrack.unsafelyUnwrapped().unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
SequenceTrack.api.freeTrack.unsafelyUnwrapped(pointer)
|
SequenceTrack.api.pointee.freeTrack.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,38 +398,38 @@ extension Sound {
|
|||||||
public var instrument: Instrument? {
|
public var instrument: Instrument? {
|
||||||
get {
|
get {
|
||||||
if let retainedInstrument { return retainedInstrument }
|
if let retainedInstrument { return retainedInstrument }
|
||||||
guard let instrument = SequenceTrack.api.getInstrument.unsafelyUnwrapped(pointer) else {
|
guard let instrument = SequenceTrack.api.pointee.getInstrument.unsafelyUnwrapped(pointer) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return Instrument(pointer: instrument, isOwned: false)
|
return Instrument(pointer: instrument, isOwned: false)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
retainedInstrument = newValue
|
retainedInstrument = newValue
|
||||||
SequenceTrack.api.setInstrument.unsafelyUnwrapped(pointer, newValue?.pointer)
|
SequenceTrack.api.pointee.setInstrument.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a note starting at `step`, lasting `length` steps.
|
/// Adds a note starting at `step`, lasting `length` steps.
|
||||||
public func addNote(step: UInt32, length: UInt32, note: MIDINote, velocity: Float = 1) {
|
public func addNote(step: UInt32, length: UInt32, note: MIDINote, velocity: Float = 1) {
|
||||||
SequenceTrack.api.addNoteEvent.unsafelyUnwrapped(pointer, step, length, note, velocity)
|
SequenceTrack.api.pointee.addNoteEvent.unsafelyUnwrapped(pointer, step, length, note, velocity)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeNote(step: UInt32, note: MIDINote) {
|
public func removeNote(step: UInt32, note: MIDINote) {
|
||||||
SequenceTrack.api.removeNoteEvent.unsafelyUnwrapped(pointer, step, note)
|
SequenceTrack.api.pointee.removeNoteEvent.unsafelyUnwrapped(pointer, step, note)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearNotes() {
|
public func clearNotes() {
|
||||||
SequenceTrack.api.clearNotes.unsafelyUnwrapped(pointer)
|
SequenceTrack.api.pointee.clearNotes.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The track's length in steps, including the tail of the last note.
|
/// The track's length in steps, including the tail of the last note.
|
||||||
public var length: UInt32 {
|
public var length: UInt32 {
|
||||||
SequenceTrack.api.getLength.unsafelyUnwrapped(pointer)
|
SequenceTrack.api.pointee.getLength.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The index of the first note at or after `step`.
|
/// The index of the first note at or after `step`.
|
||||||
public func indexForStep(_ step: UInt32) -> Int {
|
public func indexForStep(_ step: UInt32) -> Int {
|
||||||
Int(SequenceTrack.api.getIndexForStep.unsafelyUnwrapped(pointer, step))
|
Int(SequenceTrack.api.pointee.getIndexForStep.unsafelyUnwrapped(pointer, step))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The note at `index`, or `nil` if the index is out of range.
|
/// The note at `index`, or `nil` if the index is out of range.
|
||||||
@@ -438,19 +438,19 @@ extension Sound {
|
|||||||
var step: UInt32 = 0, length: UInt32 = 0
|
var step: UInt32 = 0, length: UInt32 = 0
|
||||||
var note: MIDINote = 0
|
var note: MIDINote = 0
|
||||||
var velocity: Float = 0
|
var velocity: Float = 0
|
||||||
guard SequenceTrack.api.getNoteAtIndex.unsafelyUnwrapped(
|
guard SequenceTrack.api.pointee.getNoteAtIndex.unsafelyUnwrapped(
|
||||||
pointer, Int32(index), &step, &length, ¬e, &velocity) != 0 else { return nil }
|
pointer, Int32(index), &step, &length, ¬e, &velocity) != 0 else { return nil }
|
||||||
return (step, length, note, velocity)
|
return (step, length, note, velocity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of control signals on the track.
|
/// The number of control signals on the track.
|
||||||
public var controlSignalCount: Int {
|
public var controlSignalCount: Int {
|
||||||
Int(SequenceTrack.api.getControlSignalCount.unsafelyUnwrapped(pointer))
|
Int(SequenceTrack.api.pointee.getControlSignalCount.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The control signal at `index`. Owned by the track.
|
/// The control signal at `index`. Owned by the track.
|
||||||
public func controlSignal(at index: Int) -> ControlSignal? {
|
public func controlSignal(at index: Int) -> ControlSignal? {
|
||||||
guard let signal = SequenceTrack.api.getControlSignal.unsafelyUnwrapped(
|
guard let signal = SequenceTrack.api.pointee.getControlSignal.unsafelyUnwrapped(
|
||||||
pointer, Int32(index)) else { return nil }
|
pointer, Int32(index)) else { return nil }
|
||||||
return ControlSignal(pointer: signal, isOwned: false)
|
return ControlSignal(pointer: signal, isOwned: false)
|
||||||
}
|
}
|
||||||
@@ -458,26 +458,26 @@ extension Sound {
|
|||||||
/// The control signal for MIDI controller `controller`, optionally
|
/// The control signal for MIDI controller `controller`, optionally
|
||||||
/// creating it. Owned by the track.
|
/// creating it. Owned by the track.
|
||||||
public func signalForController(_ controller: Int, create: Bool = false) -> ControlSignal? {
|
public func signalForController(_ controller: Int, create: Bool = false) -> ControlSignal? {
|
||||||
guard let signal = SequenceTrack.api.getSignalForController.unsafelyUnwrapped(
|
guard let signal = SequenceTrack.api.pointee.getSignalForController.unsafelyUnwrapped(
|
||||||
pointer, Int32(controller), create ? 1 : 0) else { return nil }
|
pointer, Int32(controller), create ? 1 : 0) else { return nil }
|
||||||
return ControlSignal(pointer: signal, isOwned: false)
|
return ControlSignal(pointer: signal, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearControlEvents() {
|
public func clearControlEvents() {
|
||||||
SequenceTrack.api.clearControlEvents.unsafelyUnwrapped(pointer)
|
SequenceTrack.api.pointee.clearControlEvents.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum number of simultaneous notes in the track.
|
/// The maximum number of simultaneous notes in the track.
|
||||||
public var polyphony: Int {
|
public var polyphony: Int {
|
||||||
Int(SequenceTrack.api.getPolyphony.unsafelyUnwrapped(pointer))
|
Int(SequenceTrack.api.pointee.getPolyphony.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
public var activeVoiceCount: Int {
|
public var activeVoiceCount: Int {
|
||||||
Int(SequenceTrack.api.activeVoiceCount.unsafelyUnwrapped(pointer))
|
Int(SequenceTrack.api.pointee.activeVoiceCount.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setMuted(_ muted: Bool) {
|
public func setMuted(_ muted: Bool) {
|
||||||
SequenceTrack.api.setMuted.unsafelyUnwrapped(pointer, muted ? 1 : 0)
|
SequenceTrack.api.pointee.setMuted.unsafelyUnwrapped(pointer, muted ? 1 : 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,14 +486,14 @@ extension Sound {
|
|||||||
/// A collection of tracks with tempo and loop control, playable from a
|
/// A collection of tracks with tempo and loop control, playable from a
|
||||||
/// MIDI file. Wraps `SoundSequence`.
|
/// MIDI file. Wraps `SoundSequence`.
|
||||||
public final class Sequence {
|
public final class Sequence {
|
||||||
private static var api: playdate_sound_sequence { snd.sequence.pointee }
|
private static var api: UnsafePointer<playdate_sound_sequence> { snd.pointee.sequence.unsafelyUnwrapped }
|
||||||
|
|
||||||
let pointer: OpaquePointer
|
let pointer: OpaquePointer
|
||||||
private var retainedTracks: [SequenceTrack] = []
|
private var retainedTracks: [SequenceTrack] = []
|
||||||
var finishCallback: ((Sequence) -> Void)?
|
var finishCallback: ((Sequence) -> Void)?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
pointer = Sequence.api.newSequence.unsafelyUnwrapped().unsafelyUnwrapped
|
pointer = Sequence.api.pointee.newSequence.unsafelyUnwrapped().unsafelyUnwrapped
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a sequence and loads the MIDI file at `path`.
|
/// Creates a sequence and loads the MIDI file at `path`.
|
||||||
@@ -503,12 +503,12 @@ extension Sound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
Sequence.api.freeSequence.unsafelyUnwrapped(pointer)
|
Sequence.api.pointee.freeSequence.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadMIDIFile(path: String) throws(PlaydateError) {
|
public func loadMIDIFile(path: String) throws(PlaydateError) {
|
||||||
let loaded = path.withPlaydateCString {
|
let loaded = path.withPlaydateCString {
|
||||||
Sequence.api.loadMIDIFile.unsafelyUnwrapped(pointer, $0) != 0
|
Sequence.api.pointee.loadMIDIFile.unsafelyUnwrapped(pointer, $0) != 0
|
||||||
}
|
}
|
||||||
if !loaded {
|
if !loaded {
|
||||||
throw PlaydateError(message: "unable to load MIDI file: \(path)")
|
throw PlaydateError(message: "unable to load MIDI file: \(path)")
|
||||||
@@ -519,65 +519,65 @@ extension Sound {
|
|||||||
public func play(completion: ((Sequence) -> Void)? = nil) {
|
public func play(completion: ((Sequence) -> Void)? = nil) {
|
||||||
finishCallback = completion
|
finishCallback = completion
|
||||||
if completion != nil {
|
if completion != nil {
|
||||||
Sequence.api.play.unsafelyUnwrapped(pointer, { _, userdata in
|
Sequence.api.pointee.play.unsafelyUnwrapped(pointer, { _, userdata in
|
||||||
guard let userdata else { return }
|
guard let userdata else { return }
|
||||||
let sequence = Unmanaged<Sequence>.fromOpaque(userdata).takeUnretainedValue()
|
let sequence = Unmanaged<Sequence>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
sequence.finishCallback?(sequence)
|
sequence.finishCallback?(sequence)
|
||||||
}, Unmanaged.passUnretained(self).toOpaque())
|
}, Unmanaged.passUnretained(self).toOpaque())
|
||||||
} else {
|
} else {
|
||||||
Sequence.api.play.unsafelyUnwrapped(pointer, nil, nil)
|
Sequence.api.pointee.play.unsafelyUnwrapped(pointer, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stop() {
|
public func stop() {
|
||||||
Sequence.api.stop.unsafelyUnwrapped(pointer)
|
Sequence.api.pointee.stop.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var isPlaying: Bool {
|
public var isPlaying: Bool {
|
||||||
Sequence.api.isPlaying.unsafelyUnwrapped(pointer) != 0
|
Sequence.api.pointee.isPlaying.unsafelyUnwrapped(pointer) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The playback position, in samples.
|
/// The playback position, in samples.
|
||||||
public var time: UInt32 {
|
public var time: UInt32 {
|
||||||
get { Sequence.api.getTime.unsafelyUnwrapped(pointer) }
|
get { Sequence.api.pointee.getTime.unsafelyUnwrapped(pointer) }
|
||||||
set { Sequence.api.setTime.unsafelyUnwrapped(pointer, newValue) }
|
set { Sequence.api.pointee.setTime.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tempo, in steps per second.
|
/// The tempo, in steps per second.
|
||||||
public var tempo: Float {
|
public var tempo: Float {
|
||||||
get { Sequence.api.getTempo.unsafelyUnwrapped(pointer) }
|
get { Sequence.api.pointee.getTempo.unsafelyUnwrapped(pointer) }
|
||||||
set { Sequence.api.setTempo.unsafelyUnwrapped(pointer, newValue) }
|
set { Sequence.api.pointee.setTempo.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sequence's length in steps, including the tail of the last note.
|
/// The sequence's length in steps, including the tail of the last note.
|
||||||
public var length: UInt32 {
|
public var length: UInt32 {
|
||||||
Sequence.api.getLength.unsafelyUnwrapped(pointer)
|
Sequence.api.pointee.getLength.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loops the range `loopStart..<loopEnd` (steps) `loops` times while
|
/// Loops the range `loopStart..<loopEnd` (steps) `loops` times while
|
||||||
/// playing; 0 loops endlessly.
|
/// playing; 0 loops endlessly.
|
||||||
public func setLoops(start: Int, end: Int, count: Int = 0) {
|
public func setLoops(start: Int, end: Int, count: Int = 0) {
|
||||||
Sequence.api.setLoops.unsafelyUnwrapped(pointer, Int32(start), Int32(end), Int32(count))
|
Sequence.api.pointee.setLoops.unsafelyUnwrapped(pointer, Int32(start), Int32(end), Int32(count))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current step, and the time offset (in samples) into that step.
|
/// The current step, and the time offset (in samples) into that step.
|
||||||
public var currentStep: (step: Int, timeOffset: Int) {
|
public var currentStep: (step: Int, timeOffset: Int) {
|
||||||
var timeOffset: Int32 = 0
|
var timeOffset: Int32 = 0
|
||||||
let step = Sequence.api.getCurrentStep.unsafelyUnwrapped(pointer, &timeOffset)
|
let step = Sequence.api.pointee.getCurrentStep.unsafelyUnwrapped(pointer, &timeOffset)
|
||||||
return (Int(step), Int(timeOffset))
|
return (Int(step), Int(timeOffset))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves playback to the given step. If `playNotes` is `true`, notes
|
/// Moves playback to the given step. If `playNotes` is `true`, notes
|
||||||
/// at the position (that started before it) are played.
|
/// at the position (that started before it) are played.
|
||||||
public func setCurrentStep(_ step: Int, timeOffset: Int = 0, playNotes: Bool = false) {
|
public func setCurrentStep(_ step: Int, timeOffset: Int = 0, playNotes: Bool = false) {
|
||||||
Sequence.api.setCurrentStep.unsafelyUnwrapped(pointer, Int32(step),
|
Sequence.api.pointee.setCurrentStep.unsafelyUnwrapped(pointer, Int32(step),
|
||||||
Int32(timeOffset), playNotes ? 1 : 0)
|
Int32(timeOffset), playNotes ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Tracks
|
// MARK: Tracks
|
||||||
|
|
||||||
public var trackCount: Int {
|
public var trackCount: Int {
|
||||||
Int(Sequence.api.getTrackCount.unsafelyUnwrapped(pointer))
|
Int(Sequence.api.pointee.getTrackCount.unsafelyUnwrapped(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new track to the sequence. The track is owned by the
|
/// Adds a new track to the sequence. The track is owned by the
|
||||||
@@ -585,7 +585,7 @@ extension Sound {
|
|||||||
@discardableResult
|
@discardableResult
|
||||||
public func addTrack() -> SequenceTrack {
|
public func addTrack() -> SequenceTrack {
|
||||||
let track = SequenceTrack(
|
let track = SequenceTrack(
|
||||||
pointer: Sequence.api.addTrack.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
pointer: Sequence.api.pointee.addTrack.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
||||||
isOwned: false)
|
isOwned: false)
|
||||||
retainedTracks.append(track)
|
retainedTracks.append(track)
|
||||||
return track
|
return track
|
||||||
@@ -593,7 +593,7 @@ extension Sound {
|
|||||||
|
|
||||||
/// The track at `index`. Owned by the sequence.
|
/// The track at `index`. Owned by the sequence.
|
||||||
public func track(at index: Int) -> SequenceTrack? {
|
public func track(at index: Int) -> SequenceTrack? {
|
||||||
guard let track = Sequence.api.getTrackAtIndex.unsafelyUnwrapped(
|
guard let track = Sequence.api.pointee.getTrackAtIndex.unsafelyUnwrapped(
|
||||||
pointer, UInt32(index)) else { return nil }
|
pointer, UInt32(index)) else { return nil }
|
||||||
return SequenceTrack(pointer: track, isOwned: false)
|
return SequenceTrack(pointer: track, isOwned: false)
|
||||||
}
|
}
|
||||||
@@ -603,12 +603,12 @@ extension Sound {
|
|||||||
if !retainedTracks.contains(where: { $0 === track }) {
|
if !retainedTracks.contains(where: { $0 === track }) {
|
||||||
retainedTracks.append(track)
|
retainedTracks.append(track)
|
||||||
}
|
}
|
||||||
Sequence.api.setTrackAtIndex.unsafelyUnwrapped(pointer, track.pointer, UInt32(index))
|
Sequence.api.pointee.setTrackAtIndex.unsafelyUnwrapped(pointer, track.pointer, UInt32(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases every playing note in the sequence.
|
/// Releases every playing note in the sequence.
|
||||||
public func allNotesOff() {
|
public func allNotesOff() {
|
||||||
Sequence.api.allNotesOff.unsafelyUnwrapped(pointer)
|
Sequence.api.pointee.allNotesOff.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
internal import CPlaydate
|
internal import CPlaydate
|
||||||
|
|
||||||
private var spriteAPI: playdate_sprite { Playdate.api.sprite.pointee }
|
private var spriteAPI: UnsafePointer<playdate_sprite> { Playdate.spriteAPI }
|
||||||
|
|
||||||
/// A floating-point rectangle mirroring `PDRect`.
|
/// A floating-point rectangle mirroring `PDRect`.
|
||||||
public struct Rect: Sendable {
|
public struct Rect: Sendable {
|
||||||
@@ -55,25 +55,25 @@ public final class Sprite {
|
|||||||
init(pointer: OpaquePointer, isOwned: Bool) {
|
init(pointer: OpaquePointer, isOwned: Bool) {
|
||||||
self.pointer = pointer
|
self.pointer = pointer
|
||||||
self.isOwned = isOwned
|
self.isOwned = isOwned
|
||||||
spriteAPI.setUserdata.unsafelyUnwrapped(pointer, Unmanaged.passUnretained(self).toOpaque())
|
spriteAPI.pointee.setUserdata.unsafelyUnwrapped(pointer, Unmanaged.passUnretained(self).toOpaque())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a new sprite.
|
/// Allocates a new sprite.
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(pointer: spriteAPI.newSprite.unsafelyUnwrapped().unsafelyUnwrapped, isOwned: true)
|
self.init(pointer: spriteAPI.pointee.newSprite.unsafelyUnwrapped().unsafelyUnwrapped, isOwned: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if isOwned {
|
if isOwned {
|
||||||
spriteAPI.setUserdata.unsafelyUnwrapped(pointer, nil)
|
spriteAPI.pointee.setUserdata.unsafelyUnwrapped(pointer, nil)
|
||||||
spriteAPI.freeSprite.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.freeSprite.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the Swift wrapper stored in the sprite's userdata, or a
|
/// Returns the Swift wrapper stored in the sprite's userdata, or a
|
||||||
/// transient unowned wrapper for sprites created outside the binding.
|
/// transient unowned wrapper for sprites created outside the binding.
|
||||||
static func wrapper(for pointer: OpaquePointer) -> Sprite {
|
static func wrapper(for pointer: OpaquePointer) -> Sprite {
|
||||||
if let userdata = spriteAPI.getUserdata.unsafelyUnwrapped(pointer) {
|
if let userdata = spriteAPI.pointee.getUserdata.unsafelyUnwrapped(pointer) {
|
||||||
return Unmanaged<Sprite>.fromOpaque(userdata).takeUnretainedValue()
|
return Unmanaged<Sprite>.fromOpaque(userdata).takeUnretainedValue()
|
||||||
}
|
}
|
||||||
return Sprite(pointer: pointer, isOwned: false)
|
return Sprite(pointer: pointer, isOwned: false)
|
||||||
@@ -82,7 +82,7 @@ public final class Sprite {
|
|||||||
/// Copies the sprite. Callbacks and retained resources are carried
|
/// Copies the sprite. Callbacks and retained resources are carried
|
||||||
/// over to the copy.
|
/// over to the copy.
|
||||||
public func copy() -> Sprite {
|
public func copy() -> Sprite {
|
||||||
let copy = Sprite(pointer: spriteAPI.copy.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
let copy = Sprite(pointer: spriteAPI.pointee.copy.unsafelyUnwrapped(pointer).unsafelyUnwrapped,
|
||||||
isOwned: true)
|
isOwned: true)
|
||||||
copy.updateFunction = updateFunction
|
copy.updateFunction = updateFunction
|
||||||
copy.drawFunction = drawFunction
|
copy.drawFunction = drawFunction
|
||||||
@@ -174,32 +174,32 @@ public final class Sprite {
|
|||||||
/// When `true`, all sprites redraw every frame instead of only when
|
/// When `true`, all sprites redraw every frame instead of only when
|
||||||
/// marked dirty.
|
/// marked dirty.
|
||||||
public static func setAlwaysRedraw(_ flag: Bool) {
|
public static func setAlwaysRedraw(_ flag: Bool) {
|
||||||
spriteAPI.setAlwaysRedraw.unsafelyUnwrapped(flag ? 1 : 0)
|
spriteAPI.pointee.setAlwaysRedraw.unsafelyUnwrapped(flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks the given screen region as needing a redraw.
|
/// Marks the given screen region as needing a redraw.
|
||||||
public static func addDirtyRect(_ rect: Graphics.Rect) {
|
public static func addDirtyRect(_ rect: Graphics.Rect) {
|
||||||
spriteAPI.addDirtyRect.unsafelyUnwrapped(rect.cValue)
|
spriteAPI.pointee.addDirtyRect.unsafelyUnwrapped(rect.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws every sprite in the display list.
|
/// Draws every sprite in the display list.
|
||||||
public static func drawAll() {
|
public static func drawAll() {
|
||||||
spriteAPI.drawSprites.unsafelyUnwrapped()
|
spriteAPI.pointee.drawSprites.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates and then draws every sprite in the display list.
|
/// Updates and then draws every sprite in the display list.
|
||||||
public static func updateAndDrawAll() {
|
public static func updateAndDrawAll() {
|
||||||
spriteAPI.updateAndDrawSprites.unsafelyUnwrapped()
|
spriteAPI.pointee.updateAndDrawSprites.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of sprites in the display list.
|
/// The number of sprites in the display list.
|
||||||
public static var count: Int {
|
public static var count: Int {
|
||||||
Int(spriteAPI.getSpriteCount.unsafelyUnwrapped())
|
Int(spriteAPI.pointee.getSpriteCount.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the sprite to the display list.
|
/// Adds the sprite to the display list.
|
||||||
public func add() {
|
public func add() {
|
||||||
spriteAPI.addSprite.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.addSprite.unsafelyUnwrapped(pointer)
|
||||||
if !Sprite.displayList.contains(where: { $0 === self }) {
|
if !Sprite.displayList.contains(where: { $0 === self }) {
|
||||||
Sprite.displayList.append(self)
|
Sprite.displayList.append(self)
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ public final class Sprite {
|
|||||||
|
|
||||||
/// Removes the sprite from the display list.
|
/// Removes the sprite from the display list.
|
||||||
public func remove() {
|
public func remove() {
|
||||||
spriteAPI.removeSprite.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.removeSprite.unsafelyUnwrapped(pointer)
|
||||||
Sprite.displayList.removeAll { $0 === self }
|
Sprite.displayList.removeAll { $0 === self }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ public final class Sprite {
|
|||||||
|
|
||||||
/// Removes every sprite from the display list.
|
/// Removes every sprite from the display list.
|
||||||
public static func removeAll() {
|
public static func removeAll() {
|
||||||
spriteAPI.removeAllSprites.unsafelyUnwrapped()
|
spriteAPI.pointee.removeAllSprites.unsafelyUnwrapped()
|
||||||
displayList = []
|
displayList = []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,30 +226,30 @@ public final class Sprite {
|
|||||||
|
|
||||||
/// The sprite's bounds. Setting this positions and sizes the sprite.
|
/// The sprite's bounds. Setting this positions and sizes the sprite.
|
||||||
public var bounds: Rect {
|
public var bounds: Rect {
|
||||||
get { Rect(spriteAPI.getBounds.unsafelyUnwrapped(pointer)) }
|
get { Rect(spriteAPI.pointee.getBounds.unsafelyUnwrapped(pointer)) }
|
||||||
set { spriteAPI.setBounds.unsafelyUnwrapped(pointer, newValue.cValue) }
|
set { spriteAPI.pointee.setBounds.unsafelyUnwrapped(pointer, newValue.cValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the sprite so its anchor point is at (x, y).
|
/// Moves the sprite so its anchor point is at (x, y).
|
||||||
public func moveTo(x: Float, y: Float) {
|
public func moveTo(x: Float, y: Float) {
|
||||||
spriteAPI.moveTo.unsafelyUnwrapped(pointer, x, y)
|
spriteAPI.pointee.moveTo.unsafelyUnwrapped(pointer, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the sprite by (dx, dy).
|
/// Moves the sprite by (dx, dy).
|
||||||
public func moveBy(dx: Float, dy: Float) {
|
public func moveBy(dx: Float, dy: Float) {
|
||||||
spriteAPI.moveBy.unsafelyUnwrapped(pointer, dx, dy)
|
spriteAPI.pointee.moveBy.unsafelyUnwrapped(pointer, dx, dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sprite's anchor position.
|
/// The sprite's anchor position.
|
||||||
public var position: (x: Float, y: Float) {
|
public var position: (x: Float, y: Float) {
|
||||||
var x: Float = 0, y: Float = 0
|
var x: Float = 0, y: Float = 0
|
||||||
spriteAPI.getPosition.unsafelyUnwrapped(pointer, &x, &y)
|
spriteAPI.pointee.getPosition.unsafelyUnwrapped(pointer, &x, &y)
|
||||||
return (x, y)
|
return (x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the sprite's size without changing its image.
|
/// Sets the sprite's size without changing its image.
|
||||||
public func setSize(width: Float, height: Float) {
|
public func setSize(width: Float, height: Float) {
|
||||||
spriteAPI.setSize.unsafelyUnwrapped(pointer, width, height)
|
spriteAPI.pointee.setSize.unsafelyUnwrapped(pointer, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The anchor point used for positioning, where (0, 0) is the top
|
/// The anchor point used for positioning, where (0, 0) is the top
|
||||||
@@ -257,16 +257,16 @@ public final class Sprite {
|
|||||||
public var center: (x: Float, y: Float) {
|
public var center: (x: Float, y: Float) {
|
||||||
get {
|
get {
|
||||||
var x: Float = 0, y: Float = 0
|
var x: Float = 0, y: Float = 0
|
||||||
spriteAPI.getCenter.unsafelyUnwrapped(pointer, &x, &y)
|
spriteAPI.pointee.getCenter.unsafelyUnwrapped(pointer, &x, &y)
|
||||||
return (x, y)
|
return (x, y)
|
||||||
}
|
}
|
||||||
set { spriteAPI.setCenter.unsafelyUnwrapped(pointer, newValue.x, newValue.y) }
|
set { spriteAPI.pointee.setCenter.unsafelyUnwrapped(pointer, newValue.x, newValue.y) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw order: higher values draw on top.
|
/// Draw order: higher values draw on top.
|
||||||
public var zIndex: Int16 {
|
public var zIndex: Int16 {
|
||||||
get { spriteAPI.getZIndex.unsafelyUnwrapped(pointer) }
|
get { spriteAPI.pointee.getZIndex.unsafelyUnwrapped(pointer) }
|
||||||
set { spriteAPI.setZIndex.unsafelyUnwrapped(pointer, newValue) }
|
set { spriteAPI.pointee.setZIndex.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Appearance
|
// MARK: - Appearance
|
||||||
@@ -274,13 +274,13 @@ public final class Sprite {
|
|||||||
/// Sets the sprite's image, resizing its bounds to match.
|
/// Sets the sprite's image, resizing its bounds to match.
|
||||||
public func setImage(_ image: Graphics.Bitmap?, flip: Graphics.BitmapFlip = .unflipped) {
|
public func setImage(_ image: Graphics.Bitmap?, flip: Graphics.BitmapFlip = .unflipped) {
|
||||||
retainedImage = image
|
retainedImage = image
|
||||||
spriteAPI.setImage.unsafelyUnwrapped(pointer, image?.pointer, flip.cValue)
|
spriteAPI.pointee.setImage.unsafelyUnwrapped(pointer, image?.pointer, flip.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sprite's image.
|
/// The sprite's image.
|
||||||
public var image: Graphics.Bitmap? {
|
public var image: Graphics.Bitmap? {
|
||||||
if let retainedImage { return retainedImage }
|
if let retainedImage { return retainedImage }
|
||||||
guard let image = spriteAPI.getImage.unsafelyUnwrapped(pointer) else { return nil }
|
guard let image = spriteAPI.pointee.getImage.unsafelyUnwrapped(pointer) else { return nil }
|
||||||
return Graphics.Bitmap(pointer: image, isOwned: false)
|
return Graphics.Bitmap(pointer: image, isOwned: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,104 +289,104 @@ public final class Sprite {
|
|||||||
get { retainedTilemap }
|
get { retainedTilemap }
|
||||||
set {
|
set {
|
||||||
retainedTilemap = newValue
|
retainedTilemap = newValue
|
||||||
spriteAPI.setTilemap.unsafelyUnwrapped(pointer, newValue?.pointer)
|
spriteAPI.pointee.setTilemap.unsafelyUnwrapped(pointer, newValue?.pointer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The mode used to draw the sprite's image.
|
/// The mode used to draw the sprite's image.
|
||||||
public func setDrawMode(_ mode: Graphics.DrawMode) {
|
public func setDrawMode(_ mode: Graphics.DrawMode) {
|
||||||
spriteAPI.setDrawMode.unsafelyUnwrapped(pointer, mode.cValue)
|
spriteAPI.pointee.setDrawMode.unsafelyUnwrapped(pointer, mode.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How the sprite's image is mirrored when drawn.
|
/// How the sprite's image is mirrored when drawn.
|
||||||
public var imageFlip: Graphics.BitmapFlip {
|
public var imageFlip: Graphics.BitmapFlip {
|
||||||
get { Graphics.BitmapFlip(spriteAPI.getImageFlip.unsafelyUnwrapped(pointer)) }
|
get { Graphics.BitmapFlip(spriteAPI.pointee.getImageFlip.unsafelyUnwrapped(pointer)) }
|
||||||
set { spriteAPI.setImageFlip.unsafelyUnwrapped(pointer, newValue.cValue) }
|
set { spriteAPI.pointee.setImageFlip.unsafelyUnwrapped(pointer, newValue.cValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the stencil applied when drawing the sprite. If `tile` is
|
/// Sets the stencil applied when drawing the sprite. If `tile` is
|
||||||
/// `true` the image width must be a multiple of 32.
|
/// `true` the image width must be a multiple of 32.
|
||||||
public func setStencil(_ stencil: Graphics.Bitmap?, tile: Bool = false) {
|
public func setStencil(_ stencil: Graphics.Bitmap?, tile: Bool = false) {
|
||||||
retainedStencil = stencil
|
retainedStencil = stencil
|
||||||
spriteAPI.setStencilImage.unsafelyUnwrapped(pointer, stencil?.pointer, tile ? 1 : 0)
|
spriteAPI.pointee.setStencilImage.unsafelyUnwrapped(pointer, stencil?.pointer, tile ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets an 8×8 stencil pattern (8 rows of image data).
|
/// Sets an 8×8 stencil pattern (8 rows of image data).
|
||||||
public func setStencilPattern(_ rows: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)) {
|
public func setStencilPattern(_ rows: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)) {
|
||||||
var pattern: [UInt8] = [rows.0, rows.1, rows.2, rows.3, rows.4, rows.5, rows.6, rows.7]
|
var pattern: [UInt8] = [rows.0, rows.1, rows.2, rows.3, rows.4, rows.5, rows.6, rows.7]
|
||||||
pattern.withUnsafeMutableBufferPointer { buffer in
|
pattern.withUnsafeMutableBufferPointer { buffer in
|
||||||
spriteAPI.setStencilPattern.unsafelyUnwrapped(pointer, buffer.baseAddress)
|
spriteAPI.pointee.setStencilPattern.unsafelyUnwrapped(pointer, buffer.baseAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearStencil() {
|
public func clearStencil() {
|
||||||
retainedStencil = nil
|
retainedStencil = nil
|
||||||
spriteAPI.clearStencil.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.clearStencil.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clips the sprite's drawing to `rect` (screen coordinates).
|
/// Clips the sprite's drawing to `rect` (screen coordinates).
|
||||||
public func setClipRect(_ rect: Graphics.Rect) {
|
public func setClipRect(_ rect: Graphics.Rect) {
|
||||||
spriteAPI.setClipRect.unsafelyUnwrapped(pointer, rect.cValue)
|
spriteAPI.pointee.setClipRect.unsafelyUnwrapped(pointer, rect.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearClipRect() {
|
public func clearClipRect() {
|
||||||
spriteAPI.clearClipRect.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.clearClipRect.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clips all sprites with z-index in `startZ...endZ` to `rect`.
|
/// Clips all sprites with z-index in `startZ...endZ` to `rect`.
|
||||||
public static func setClipRectsInRange(_ rect: Graphics.Rect, startZ: Int, endZ: Int) {
|
public static func setClipRectsInRange(_ rect: Graphics.Rect, startZ: Int, endZ: Int) {
|
||||||
spriteAPI.setClipRectsInRange.unsafelyUnwrapped(rect.cValue, Int32(startZ), Int32(endZ))
|
spriteAPI.pointee.setClipRectsInRange.unsafelyUnwrapped(rect.cValue, Int32(startZ), Int32(endZ))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func clearClipRectsInRange(startZ: Int, endZ: Int) {
|
public static func clearClipRectsInRange(startZ: Int, endZ: Int) {
|
||||||
spriteAPI.clearClipRectsInRange.unsafelyUnwrapped(Int32(startZ), Int32(endZ))
|
spriteAPI.pointee.clearClipRectsInRange.unsafelyUnwrapped(Int32(startZ), Int32(endZ))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Behavior flags
|
// MARK: - Behavior flags
|
||||||
|
|
||||||
/// Whether the sprite's update function is called by `updateAndDrawAll()`.
|
/// Whether the sprite's update function is called by `updateAndDrawAll()`.
|
||||||
public var updatesEnabled: Bool {
|
public var updatesEnabled: Bool {
|
||||||
get { spriteAPI.updatesEnabled.unsafelyUnwrapped(pointer) != 0 }
|
get { spriteAPI.pointee.updatesEnabled.unsafelyUnwrapped(pointer) != 0 }
|
||||||
set { spriteAPI.setUpdatesEnabled.unsafelyUnwrapped(pointer, newValue ? 1 : 0) }
|
set { spriteAPI.pointee.setUpdatesEnabled.unsafelyUnwrapped(pointer, newValue ? 1 : 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public var collisionsEnabled: Bool {
|
public var collisionsEnabled: Bool {
|
||||||
get { spriteAPI.collisionsEnabled.unsafelyUnwrapped(pointer) != 0 }
|
get { spriteAPI.pointee.collisionsEnabled.unsafelyUnwrapped(pointer) != 0 }
|
||||||
set { spriteAPI.setCollisionsEnabled.unsafelyUnwrapped(pointer, newValue ? 1 : 0) }
|
set { spriteAPI.pointee.setCollisionsEnabled.unsafelyUnwrapped(pointer, newValue ? 1 : 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public var isVisible: Bool {
|
public var isVisible: Bool {
|
||||||
get { spriteAPI.isVisible.unsafelyUnwrapped(pointer) != 0 }
|
get { spriteAPI.pointee.isVisible.unsafelyUnwrapped(pointer) != 0 }
|
||||||
set { spriteAPI.setVisible.unsafelyUnwrapped(pointer, newValue ? 1 : 0) }
|
set { spriteAPI.pointee.setVisible.unsafelyUnwrapped(pointer, newValue ? 1 : 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marking a sprite opaque tells the system it does not need to redraw
|
/// Marking a sprite opaque tells the system it does not need to redraw
|
||||||
/// anything behind it.
|
/// anything behind it.
|
||||||
public func setOpaque(_ flag: Bool) {
|
public func setOpaque(_ flag: Bool) {
|
||||||
spriteAPI.setOpaque.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
spriteAPI.pointee.setOpaque.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forces the sprite to redraw this frame.
|
/// Forces the sprite to redraw this frame.
|
||||||
public func markDirty() {
|
public func markDirty() {
|
||||||
spriteAPI.markDirty.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.markDirty.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks part of the sprite (in sprite-local coordinates) as needing
|
/// Marks part of the sprite (in sprite-local coordinates) as needing
|
||||||
/// a redraw.
|
/// a redraw.
|
||||||
public func markDirty(rect: Rect) {
|
public func markDirty(rect: Rect) {
|
||||||
spriteAPI.markDirtyRect.unsafelyUnwrapped(pointer, rect.cValue)
|
spriteAPI.pointee.markDirtyRect.unsafelyUnwrapped(pointer, rect.cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An integer tag for identifying sprites (e.g. in collisions).
|
/// An integer tag for identifying sprites (e.g. in collisions).
|
||||||
public var tag: UInt8 {
|
public var tag: UInt8 {
|
||||||
get { spriteAPI.getTag.unsafelyUnwrapped(pointer) }
|
get { spriteAPI.pointee.getTag.unsafelyUnwrapped(pointer) }
|
||||||
set { spriteAPI.setTag.unsafelyUnwrapped(pointer, newValue) }
|
set { spriteAPI.pointee.setTag.unsafelyUnwrapped(pointer, newValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true`, the sprite draws in screen coordinates, ignoring the
|
/// When `true`, the sprite draws in screen coordinates, ignoring the
|
||||||
/// global draw offset.
|
/// global draw offset.
|
||||||
public func setIgnoresDrawOffset(_ flag: Bool) {
|
public func setIgnoresDrawOffset(_ flag: Bool) {
|
||||||
spriteAPI.setIgnoresDrawOffset.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
spriteAPI.pointee.setIgnoresDrawOffset.unsafelyUnwrapped(pointer, flag ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Callbacks
|
// MARK: - Callbacks
|
||||||
@@ -395,13 +395,13 @@ public final class Sprite {
|
|||||||
public func setUpdateFunction(_ update: ((Sprite) -> Void)?) {
|
public func setUpdateFunction(_ update: ((Sprite) -> Void)?) {
|
||||||
updateFunction = update
|
updateFunction = update
|
||||||
if update != nil {
|
if update != nil {
|
||||||
spriteAPI.setUpdateFunction.unsafelyUnwrapped(pointer, { spritePointer in
|
spriteAPI.pointee.setUpdateFunction.unsafelyUnwrapped(pointer, { spritePointer in
|
||||||
guard let spritePointer else { return }
|
guard let spritePointer else { return }
|
||||||
let sprite = Sprite.wrapper(for: spritePointer)
|
let sprite = Sprite.wrapper(for: spritePointer)
|
||||||
sprite.updateFunction?(sprite)
|
sprite.updateFunction?(sprite)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
spriteAPI.setUpdateFunction.unsafelyUnwrapped(pointer, nil)
|
spriteAPI.pointee.setUpdateFunction.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,13 +411,13 @@ public final class Sprite {
|
|||||||
public func setDrawFunction(_ draw: ((Sprite, _ bounds: Rect, _ drawRect: Rect) -> Void)?) {
|
public func setDrawFunction(_ draw: ((Sprite, _ bounds: Rect, _ drawRect: Rect) -> Void)?) {
|
||||||
drawFunction = draw
|
drawFunction = draw
|
||||||
if draw != nil {
|
if draw != nil {
|
||||||
spriteAPI.setDrawFunction.unsafelyUnwrapped(pointer, { spritePointer, bounds, drawRect in
|
spriteAPI.pointee.setDrawFunction.unsafelyUnwrapped(pointer, { spritePointer, bounds, drawRect in
|
||||||
guard let spritePointer else { return }
|
guard let spritePointer else { return }
|
||||||
let sprite = Sprite.wrapper(for: spritePointer)
|
let sprite = Sprite.wrapper(for: spritePointer)
|
||||||
sprite.drawFunction?(sprite, Rect(bounds), Rect(drawRect))
|
sprite.drawFunction?(sprite, Rect(bounds), Rect(drawRect))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
spriteAPI.setDrawFunction.unsafelyUnwrapped(pointer, nil)
|
spriteAPI.pointee.setDrawFunction.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,17 +425,17 @@ public final class Sprite {
|
|||||||
|
|
||||||
/// Clears the collision world. Call when changing scenes.
|
/// Clears the collision world. Call when changing scenes.
|
||||||
public static func resetCollisionWorld() {
|
public static func resetCollisionWorld() {
|
||||||
spriteAPI.resetCollisionWorld.unsafelyUnwrapped()
|
spriteAPI.pointee.resetCollisionWorld.unsafelyUnwrapped()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rect (in sprite-local coordinates) used for collisions.
|
/// The rect (in sprite-local coordinates) used for collisions.
|
||||||
public var collideRect: Rect {
|
public var collideRect: Rect {
|
||||||
get { Rect(spriteAPI.getCollideRect.unsafelyUnwrapped(pointer)) }
|
get { Rect(spriteAPI.pointee.getCollideRect.unsafelyUnwrapped(pointer)) }
|
||||||
set { spriteAPI.setCollideRect.unsafelyUnwrapped(pointer, newValue.cValue) }
|
set { spriteAPI.pointee.setCollideRect.unsafelyUnwrapped(pointer, newValue.cValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearCollideRect() {
|
public func clearCollideRect() {
|
||||||
spriteAPI.clearCollideRect.unsafelyUnwrapped(pointer)
|
spriteAPI.pointee.clearCollideRect.unsafelyUnwrapped(pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the function deciding how this sprite responds when it
|
/// Sets the function deciding how this sprite responds when it
|
||||||
@@ -443,14 +443,14 @@ public final class Sprite {
|
|||||||
public func setCollisionResponseFunction(_ filter: ((Sprite, _ other: Sprite) -> CollisionResponse)?) {
|
public func setCollisionResponseFunction(_ filter: ((Sprite, _ other: Sprite) -> CollisionResponse)?) {
|
||||||
collisionResponseFunction = filter
|
collisionResponseFunction = filter
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
spriteAPI.setCollisionResponseFunction.unsafelyUnwrapped(pointer, { spritePointer, otherPointer in
|
spriteAPI.pointee.setCollisionResponseFunction.unsafelyUnwrapped(pointer, { spritePointer, otherPointer in
|
||||||
guard let spritePointer, let otherPointer else { return kCollisionTypeFreeze }
|
guard let spritePointer, let otherPointer else { return kCollisionTypeFreeze }
|
||||||
let sprite = Sprite.wrapper(for: spritePointer)
|
let sprite = Sprite.wrapper(for: spritePointer)
|
||||||
let other = Sprite.wrapper(for: otherPointer)
|
let other = Sprite.wrapper(for: otherPointer)
|
||||||
return sprite.collisionResponseFunction?(sprite, other).cValue ?? kCollisionTypeFreeze
|
return sprite.collisionResponseFunction?(sprite, other).cValue ?? kCollisionTypeFreeze
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
spriteAPI.setCollisionResponseFunction.unsafelyUnwrapped(pointer, nil)
|
spriteAPI.pointee.setCollisionResponseFunction.unsafelyUnwrapped(pointer, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ public final class Sprite {
|
|||||||
public func checkCollisions(goalX: Float, goalY: Float)
|
public func checkCollisions(goalX: Float, goalY: Float)
|
||||||
-> (actual: (x: Float, y: Float), collisions: [CollisionInfo]) {
|
-> (actual: (x: Float, y: Float), collisions: [CollisionInfo]) {
|
||||||
var actualX: Float = 0, actualY: Float = 0, count: Int32 = 0
|
var actualX: Float = 0, actualY: Float = 0, count: Int32 = 0
|
||||||
let result = spriteAPI.checkCollisions.unsafelyUnwrapped(
|
let result = spriteAPI.pointee.checkCollisions.unsafelyUnwrapped(
|
||||||
pointer, goalX, goalY, &actualX, &actualY, &count)
|
pointer, goalX, goalY, &actualX, &actualY, &count)
|
||||||
return ((actualX, actualY), Sprite.collisionInfos(result, count: count))
|
return ((actualX, actualY), Sprite.collisionInfos(result, count: count))
|
||||||
}
|
}
|
||||||
@@ -483,7 +483,7 @@ public final class Sprite {
|
|||||||
public func moveWithCollisions(goalX: Float, goalY: Float)
|
public func moveWithCollisions(goalX: Float, goalY: Float)
|
||||||
-> (actual: (x: Float, y: Float), collisions: [CollisionInfo]) {
|
-> (actual: (x: Float, y: Float), collisions: [CollisionInfo]) {
|
||||||
var actualX: Float = 0, actualY: Float = 0, count: Int32 = 0
|
var actualX: Float = 0, actualY: Float = 0, count: Int32 = 0
|
||||||
let result = spriteAPI.moveWithCollisions.unsafelyUnwrapped(
|
let result = spriteAPI.pointee.moveWithCollisions.unsafelyUnwrapped(
|
||||||
pointer, goalX, goalY, &actualX, &actualY, &count)
|
pointer, goalX, goalY, &actualX, &actualY, &count)
|
||||||
return ((actualX, actualY), Sprite.collisionInfos(result, count: count))
|
return ((actualX, actualY), Sprite.collisionInfos(result, count: count))
|
||||||
}
|
}
|
||||||
@@ -506,21 +506,21 @@ public final class Sprite {
|
|||||||
/// Sprites with collision rects containing the point.
|
/// Sprites with collision rects containing the point.
|
||||||
public static func query(atPoint x: Float, _ y: Float) -> [Sprite] {
|
public static func query(atPoint x: Float, _ y: Float) -> [Sprite] {
|
||||||
var count: Int32 = 0
|
var count: Int32 = 0
|
||||||
let result = spriteAPI.querySpritesAtPoint.unsafelyUnwrapped(x, y, &count)
|
let result = spriteAPI.pointee.querySpritesAtPoint.unsafelyUnwrapped(x, y, &count)
|
||||||
return sprites(result, count: count)
|
return sprites(result, count: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sprites with collision rects intersecting the rect.
|
/// Sprites with collision rects intersecting the rect.
|
||||||
public static func query(inRect x: Float, _ y: Float, width: Float, height: Float) -> [Sprite] {
|
public static func query(inRect x: Float, _ y: Float, width: Float, height: Float) -> [Sprite] {
|
||||||
var count: Int32 = 0
|
var count: Int32 = 0
|
||||||
let result = spriteAPI.querySpritesInRect.unsafelyUnwrapped(x, y, width, height, &count)
|
let result = spriteAPI.pointee.querySpritesInRect.unsafelyUnwrapped(x, y, width, height, &count)
|
||||||
return sprites(result, count: count)
|
return sprites(result, count: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sprites with collision rects intersecting the line segment.
|
/// Sprites with collision rects intersecting the line segment.
|
||||||
public static func query(alongLine x1: Float, _ y1: Float, _ x2: Float, _ y2: Float) -> [Sprite] {
|
public static func query(alongLine x1: Float, _ y1: Float, _ x2: Float, _ y2: Float) -> [Sprite] {
|
||||||
var count: Int32 = 0
|
var count: Int32 = 0
|
||||||
let result = spriteAPI.querySpritesAlongLine.unsafelyUnwrapped(x1, y1, x2, y2, &count)
|
let result = spriteAPI.pointee.querySpritesAlongLine.unsafelyUnwrapped(x1, y1, x2, y2, &count)
|
||||||
return sprites(result, count: count)
|
return sprites(result, count: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,7 +528,7 @@ public final class Sprite {
|
|||||||
public static func queryInfo(alongLine x1: Float, _ y1: Float,
|
public static func queryInfo(alongLine x1: Float, _ y1: Float,
|
||||||
_ x2: Float, _ y2: Float) -> [QueryInfo] {
|
_ x2: Float, _ y2: Float) -> [QueryInfo] {
|
||||||
var count: Int32 = 0
|
var count: Int32 = 0
|
||||||
guard let result = spriteAPI.querySpriteInfoAlongLine.unsafelyUnwrapped(
|
guard let result = spriteAPI.pointee.querySpriteInfoAlongLine.unsafelyUnwrapped(
|
||||||
x1, y1, x2, y2, &count) else { return [] }
|
x1, y1, x2, y2, &count) else { return [] }
|
||||||
var infos = [QueryInfo]()
|
var infos = [QueryInfo]()
|
||||||
infos.reserveCapacity(Int(count))
|
infos.reserveCapacity(Int(count))
|
||||||
@@ -542,14 +542,14 @@ public final class Sprite {
|
|||||||
/// Sprites whose collision rects overlap this sprite's.
|
/// Sprites whose collision rects overlap this sprite's.
|
||||||
public var overlappingSprites: [Sprite] {
|
public var overlappingSprites: [Sprite] {
|
||||||
var count: Int32 = 0
|
var count: Int32 = 0
|
||||||
let result = spriteAPI.overlappingSprites.unsafelyUnwrapped(pointer, &count)
|
let result = spriteAPI.pointee.overlappingSprites.unsafelyUnwrapped(pointer, &count)
|
||||||
return Sprite.sprites(result, count: count)
|
return Sprite.sprites(result, count: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All sprites in the display list that overlap another sprite.
|
/// All sprites in the display list that overlap another sprite.
|
||||||
public static var allOverlappingSprites: [Sprite] {
|
public static var allOverlappingSprites: [Sprite] {
|
||||||
var count: Int32 = 0
|
var count: Int32 = 0
|
||||||
let result = spriteAPI.allOverlappingSprites.unsafelyUnwrapped(&count)
|
let result = spriteAPI.pointee.allOverlappingSprites.unsafelyUnwrapped(&count)
|
||||||
return sprites(result, count: count)
|
return sprites(result, count: count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,34 @@ extension String {
|
|||||||
self.init(playdateCString: pointer)
|
self.init(playdateCString: pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls `body` with a temporary null-terminated UTF-8 copy of the string.
|
/// Calls `body` with a temporary null-terminated UTF-8 copy of the
|
||||||
|
/// string. The copy lives on the stack for short strings, so calling
|
||||||
|
/// this in the update loop does not churn the heap.
|
||||||
func withPlaydateCString<Result>(_ body: (UnsafePointer<CChar>) -> Result) -> Result {
|
func withPlaydateCString<Result>(_ body: (UnsafePointer<CChar>) -> Result) -> Result {
|
||||||
var utf8 = ContiguousArray(self.utf8)
|
let count = utf8.count
|
||||||
utf8.append(0)
|
return withUnsafeTemporaryAllocation(of: CChar.self, capacity: count + 1) { buffer in
|
||||||
return utf8.withUnsafeBufferPointer { buffer in
|
var index = 0
|
||||||
buffer.withMemoryRebound(to: CChar.self) { rebound in
|
for byte in utf8 {
|
||||||
body(rebound.baseAddress.unsafelyUnwrapped)
|
buffer[index] = CChar(bitPattern: byte)
|
||||||
|
index += 1
|
||||||
}
|
}
|
||||||
|
buffer[count] = 0
|
||||||
|
return body(buffer.baseAddress.unsafelyUnwrapped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls `body` with a temporary buffer of the string's UTF-8 bytes (not
|
||||||
|
/// null-terminated) and its length, for the `(const void*, size_t)` text
|
||||||
|
/// APIs. Stack-allocated for short strings.
|
||||||
|
func withPlaydateUTF8<Result>(_ body: (UnsafeRawPointer, Int) -> Result) -> Result {
|
||||||
|
let count = utf8.count
|
||||||
|
return withUnsafeTemporaryAllocation(of: UInt8.self, capacity: count + 1) { buffer in
|
||||||
|
var index = 0
|
||||||
|
for byte in utf8 {
|
||||||
|
buffer[index] = byte
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
return body(UnsafeRawPointer(buffer.baseAddress.unsafelyUnwrapped), count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ internal import CPlaydate
|
|||||||
public enum System {}
|
public enum System {}
|
||||||
|
|
||||||
extension System {
|
extension System {
|
||||||
private static var api: playdate_sys { Playdate.api.system.pointee }
|
private static var api: UnsafePointer<playdate_sys> { Playdate.systemAPI }
|
||||||
|
|
||||||
// MARK: - Types
|
// MARK: - Types
|
||||||
|
|
||||||
@@ -114,13 +114,13 @@ extension System {
|
|||||||
/// The system allocator. Pass `nil` to allocate, `size` 0 to free.
|
/// The system allocator. Pass `nil` to allocate, `size` 0 to free.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func realloc(_ pointer: UnsafeMutableRawPointer?, size: Int) -> UnsafeMutableRawPointer? {
|
public static func realloc(_ pointer: UnsafeMutableRawPointer?, size: Int) -> UnsafeMutableRawPointer? {
|
||||||
api.realloc.unsafelyUnwrapped(pointer, size)
|
api.pointee.realloc.unsafelyUnwrapped(pointer, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Frees memory that the Playdate OS handed to the caller (e.g. strings
|
/// Frees memory that the Playdate OS handed to the caller (e.g. strings
|
||||||
/// returned by `localizedText(forKey:)`).
|
/// returned by `localizedText(forKey:)`).
|
||||||
static func systemFree(_ pointer: UnsafeMutableRawPointer?) {
|
static func systemFree(_ pointer: UnsafeMutableRawPointer?) {
|
||||||
_ = api.realloc.unsafelyUnwrapped(pointer, 0)
|
_ = api.pointee.realloc.unsafelyUnwrapped(pointer, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Logging
|
// MARK: - Logging
|
||||||
@@ -137,48 +137,48 @@ extension System {
|
|||||||
|
|
||||||
// MARK: - Time
|
// MARK: - Time
|
||||||
|
|
||||||
public static var language: Language { Language(api.getLanguage.unsafelyUnwrapped()) }
|
public static var language: Language { Language(api.pointee.getLanguage.unsafelyUnwrapped()) }
|
||||||
|
|
||||||
/// Milliseconds since the game launched. Wraps around after about 49 days.
|
/// Milliseconds since the game launched. Wraps around after about 49 days.
|
||||||
public static var currentTimeMilliseconds: UInt32 {
|
public static var currentTimeMilliseconds: UInt32 {
|
||||||
UInt32(api.getCurrentTimeMilliseconds.unsafelyUnwrapped())
|
UInt32(api.pointee.getCurrentTimeMilliseconds.unsafelyUnwrapped())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Seconds (and sub-second milliseconds) since midnight 2000-01-01 UTC.
|
/// Seconds (and sub-second milliseconds) since midnight 2000-01-01 UTC.
|
||||||
public static var secondsSinceEpoch: (seconds: UInt32, milliseconds: UInt32) {
|
public static var secondsSinceEpoch: (seconds: UInt32, milliseconds: UInt32) {
|
||||||
var milliseconds: UInt32 = 0
|
var milliseconds: UInt32 = 0
|
||||||
let seconds = withUnsafeMutablePointer(to: &milliseconds) {
|
let seconds = withUnsafeMutablePointer(to: &milliseconds) {
|
||||||
api.getSecondsSinceEpoch.unsafelyUnwrapped($0)
|
api.pointee.getSecondsSinceEpoch.unsafelyUnwrapped($0)
|
||||||
}
|
}
|
||||||
return (UInt32(seconds), milliseconds)
|
return (UInt32(seconds), milliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// High-resolution timer value, in seconds.
|
/// High-resolution timer value, in seconds.
|
||||||
public static var elapsedTime: Float { api.getElapsedTime.unsafelyUnwrapped() }
|
public static var elapsedTime: Float { api.pointee.getElapsedTime.unsafelyUnwrapped() }
|
||||||
|
|
||||||
public static func resetElapsedTime() { api.resetElapsedTime.unsafelyUnwrapped() }
|
public static func resetElapsedTime() { api.pointee.resetElapsedTime.unsafelyUnwrapped() }
|
||||||
|
|
||||||
/// Offset from UTC of the user-set timezone, in seconds.
|
/// Offset from UTC of the user-set timezone, in seconds.
|
||||||
public static var timezoneOffset: Int32 { api.getTimezoneOffset.unsafelyUnwrapped() }
|
public static var timezoneOffset: Int32 { api.pointee.getTimezoneOffset.unsafelyUnwrapped() }
|
||||||
|
|
||||||
public static var shouldDisplay24HourTime: Bool {
|
public static var shouldDisplay24HourTime: Bool {
|
||||||
api.shouldDisplay24HourTime.unsafelyUnwrapped() != 0
|
api.pointee.shouldDisplay24HourTime.unsafelyUnwrapped() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func convertEpochToDateTime(_ epoch: UInt32) -> DateTime {
|
public static func convertEpochToDateTime(_ epoch: UInt32) -> DateTime {
|
||||||
var dateTime = PDDateTime()
|
var dateTime = PDDateTime()
|
||||||
api.convertEpochToDateTime.unsafelyUnwrapped(epoch, &dateTime)
|
api.pointee.convertEpochToDateTime.unsafelyUnwrapped(epoch, &dateTime)
|
||||||
return DateTime(dateTime)
|
return DateTime(dateTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func convertDateTimeToEpoch(_ dateTime: DateTime) -> UInt32 {
|
public static func convertDateTimeToEpoch(_ dateTime: DateTime) -> UInt32 {
|
||||||
var cValue = dateTime.cValue
|
var cValue = dateTime.cValue
|
||||||
return api.convertDateTimeToEpoch.unsafelyUnwrapped(&cValue)
|
return api.pointee.convertDateTimeToEpoch.unsafelyUnwrapped(&cValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blocks execution for the given number of milliseconds.
|
/// Blocks execution for the given number of milliseconds.
|
||||||
public static func delay(milliseconds: UInt32) {
|
public static func delay(milliseconds: UInt32) {
|
||||||
api.delay.unsafelyUnwrapped(milliseconds)
|
api.pointee.delay.unsafelyUnwrapped(milliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests the server time. The completion receives the time string or
|
/// Requests the server time. The completion receives the time string or
|
||||||
@@ -186,7 +186,7 @@ extension System {
|
|||||||
/// before the first completes replaces the stored completion.
|
/// before the first completes replaces the stored completion.
|
||||||
public static func getServerTime(_ completion: @escaping (_ time: String?, _ error: String?) -> Void) {
|
public static func getServerTime(_ completion: @escaping (_ time: String?, _ error: String?) -> Void) {
|
||||||
serverTimeCompletion = completion
|
serverTimeCompletion = completion
|
||||||
api.getServerTime.unsafelyUnwrapped { time, error in
|
api.pointee.getServerTime.unsafelyUnwrapped { time, error in
|
||||||
let completion = System.serverTimeCompletion
|
let completion = System.serverTimeCompletion
|
||||||
System.serverTimeCompletion = nil
|
System.serverTimeCompletion = nil
|
||||||
completion?(String(playdateCString: time), String(playdateCString: error))
|
completion?(String(playdateCString: time), String(playdateCString: error))
|
||||||
@@ -200,7 +200,7 @@ extension System {
|
|||||||
/// Sets the per-frame update callback. Return `true` to redraw the display.
|
/// Sets the per-frame update callback. Return `true` to redraw the display.
|
||||||
public static func setUpdateCallback(_ callback: @escaping () -> Bool) {
|
public static func setUpdateCallback(_ callback: @escaping () -> Bool) {
|
||||||
updateCallback = callback
|
updateCallback = callback
|
||||||
api.setUpdateCallback.unsafelyUnwrapped({ _ in
|
api.pointee.setUpdateCallback.unsafelyUnwrapped({ _ in
|
||||||
System.updateCallback?() == true ? 1 : 0
|
System.updateCallback?() == true ? 1 : 0
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ extension System {
|
|||||||
|
|
||||||
/// Draws the current frames-per-second value at the given point.
|
/// Draws the current frames-per-second value at the given point.
|
||||||
public static func drawFPS(x: Int = 0, y: Int = 0) {
|
public static func drawFPS(x: Int = 0, y: Int = 0) {
|
||||||
api.drawFPS.unsafelyUnwrapped(Int32(x), Int32(y))
|
api.pointee.drawFPS.unsafelyUnwrapped(Int32(x), Int32(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Input
|
// MARK: - Input
|
||||||
@@ -217,7 +217,7 @@ extension System {
|
|||||||
/// The current button state: held, pressed this frame, released this frame.
|
/// The current button state: held, pressed this frame, released this frame.
|
||||||
public static var buttonState: (current: Buttons, pushed: Buttons, released: Buttons) {
|
public static var buttonState: (current: Buttons, pushed: Buttons, released: Buttons) {
|
||||||
var current = PDButtons(0), pushed = PDButtons(0), released = PDButtons(0)
|
var current = PDButtons(0), pushed = PDButtons(0), released = PDButtons(0)
|
||||||
api.getButtonState.unsafelyUnwrapped(¤t, &pushed, &released)
|
api.pointee.getButtonState.unsafelyUnwrapped(¤t, &pushed, &released)
|
||||||
return (Buttons(current), Buttons(pushed), Buttons(released))
|
return (Buttons(current), Buttons(pushed), Buttons(released))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,47 +228,47 @@ extension System {
|
|||||||
_ callback: ((_ button: Buttons, _ isDown: Bool, _ when: UInt32) -> Int32)?) {
|
_ callback: ((_ button: Buttons, _ isDown: Bool, _ when: UInt32) -> Int32)?) {
|
||||||
buttonCallback = callback
|
buttonCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
api.setButtonCallback.unsafelyUnwrapped({ button, down, when, _ in
|
api.pointee.setButtonCallback.unsafelyUnwrapped({ button, down, when, _ in
|
||||||
System.buttonCallback?(Buttons(button), down != 0, when) ?? 0
|
System.buttonCallback?(Buttons(button), down != 0, when) ?? 0
|
||||||
}, nil, Int32(queueSize))
|
}, nil, Int32(queueSize))
|
||||||
} else {
|
} else {
|
||||||
api.setButtonCallback.unsafelyUnwrapped(nil, nil, Int32(queueSize))
|
api.pointee.setButtonCallback.unsafelyUnwrapped(nil, nil, Int32(queueSize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated(unsafe) private static var buttonCallback: ((Buttons, Bool, UInt32) -> Int32)?
|
nonisolated(unsafe) private static var buttonCallback: ((Buttons, Bool, UInt32) -> Int32)?
|
||||||
|
|
||||||
public static func setPeripheralsEnabled(_ peripherals: Peripherals) {
|
public static func setPeripheralsEnabled(_ peripherals: Peripherals) {
|
||||||
api.setPeripheralsEnabled.unsafelyUnwrapped(PDPeripherals(peripherals.rawValue))
|
api.pointee.setPeripheralsEnabled.unsafelyUnwrapped(PDPeripherals(peripherals.rawValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The most recent accelerometer reading, in g. Enable the accelerometer
|
/// The most recent accelerometer reading, in g. Enable the accelerometer
|
||||||
/// with `setPeripheralsEnabled(.accelerometer)` first.
|
/// with `setPeripheralsEnabled(.accelerometer)` first.
|
||||||
public static var accelerometer: (x: Float, y: Float, z: Float) {
|
public static var accelerometer: (x: Float, y: Float, z: Float) {
|
||||||
var x: Float = 0, y: Float = 0, z: Float = 0
|
var x: Float = 0, y: Float = 0, z: Float = 0
|
||||||
api.getAccelerometer.unsafelyUnwrapped(&x, &y, &z)
|
api.pointee.getAccelerometer.unsafelyUnwrapped(&x, &y, &z)
|
||||||
return (x, y, z)
|
return (x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Degrees the crank moved since the last frame.
|
/// Degrees the crank moved since the last frame.
|
||||||
public static var crankChange: Float { api.getCrankChange.unsafelyUnwrapped() }
|
public static var crankChange: Float { api.pointee.getCrankChange.unsafelyUnwrapped() }
|
||||||
|
|
||||||
/// The crank position in degrees; 0 points along the +Y axis.
|
/// The crank position in degrees; 0 points along the +Y axis.
|
||||||
public static var crankAngle: Float { api.getCrankAngle.unsafelyUnwrapped() }
|
public static var crankAngle: Float { api.pointee.getCrankAngle.unsafelyUnwrapped() }
|
||||||
|
|
||||||
public static var isCrankDocked: Bool { api.isCrankDocked.unsafelyUnwrapped() != 0 }
|
public static var isCrankDocked: Bool { api.pointee.isCrankDocked.unsafelyUnwrapped() != 0 }
|
||||||
|
|
||||||
/// Disables or enables the crank dock/undock sounds. Returns the previous setting.
|
/// Disables or enables the crank dock/undock sounds. Returns the previous setting.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func setCrankSoundsDisabled(_ disabled: Bool) -> Bool {
|
public static func setCrankSoundsDisabled(_ disabled: Bool) -> Bool {
|
||||||
api.setCrankSoundsDisabled.unsafelyUnwrapped(disabled ? 1 : 0) != 0
|
api.pointee.setCrankSoundsDisabled.unsafelyUnwrapped(disabled ? 1 : 0) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the user has the "flipped" system setting enabled.
|
/// Whether the user has the "flipped" system setting enabled.
|
||||||
public static var isFlipped: Bool { api.getFlipped.unsafelyUnwrapped() != 0 }
|
public static var isFlipped: Bool { api.pointee.getFlipped.unsafelyUnwrapped() != 0 }
|
||||||
|
|
||||||
public static func setAutoLockDisabled(_ disabled: Bool) {
|
public static func setAutoLockDisabled(_ disabled: Bool) {
|
||||||
api.setAutoLockDisabled.unsafelyUnwrapped(disabled ? 1 : 0)
|
api.pointee.setAutoLockDisabled.unsafelyUnwrapped(disabled ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Installs a callback invoked when a message is received on the serial port
|
/// Installs a callback invoked when a message is received on the serial port
|
||||||
@@ -276,12 +276,12 @@ extension System {
|
|||||||
public static func setSerialMessageCallback(_ callback: ((String) -> Void)?) {
|
public static func setSerialMessageCallback(_ callback: ((String) -> Void)?) {
|
||||||
serialMessageCallback = callback
|
serialMessageCallback = callback
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
api.setSerialMessageCallback.unsafelyUnwrapped { data in
|
api.pointee.setSerialMessageCallback.unsafelyUnwrapped { data in
|
||||||
guard let message = String(playdateCString: data) else { return }
|
guard let message = String(playdateCString: data) else { return }
|
||||||
System.serialMessageCallback?(message)
|
System.serialMessageCallback?(message)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
api.setSerialMessageCallback.unsafelyUnwrapped(nil)
|
api.pointee.setSerialMessageCallback.unsafelyUnwrapped(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,11 +311,11 @@ extension System {
|
|||||||
/// The menu item's title.
|
/// The menu item's title.
|
||||||
public var title: String {
|
public var title: String {
|
||||||
get {
|
get {
|
||||||
String(playdateCString: Playdate.api.system.pointee.getMenuItemTitle.unsafelyUnwrapped(pointer)) ?? ""
|
String(playdateCString: Playdate.systemAPI.pointee.getMenuItemTitle.unsafelyUnwrapped(pointer)) ?? ""
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
newValue.withPlaydateCString {
|
newValue.withPlaydateCString {
|
||||||
Playdate.api.system.pointee.setMenuItemTitle.unsafelyUnwrapped(pointer, $0)
|
Playdate.systemAPI.pointee.setMenuItemTitle.unsafelyUnwrapped(pointer, $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,8 +323,8 @@ extension System {
|
|||||||
/// For checkmark items this is 0 or 1; for option items it is the
|
/// For checkmark items this is 0 or 1; for option items it is the
|
||||||
/// index of the selected option.
|
/// index of the selected option.
|
||||||
public var value: Int {
|
public var value: Int {
|
||||||
get { Int(Playdate.api.system.pointee.getMenuItemValue.unsafelyUnwrapped(pointer)) }
|
get { Int(Playdate.systemAPI.pointee.getMenuItemValue.unsafelyUnwrapped(pointer)) }
|
||||||
set { Playdate.api.system.pointee.setMenuItemValue.unsafelyUnwrapped(pointer, Int32(newValue)) }
|
set { Playdate.systemAPI.pointee.setMenuItemValue.unsafelyUnwrapped(pointer, Int32(newValue)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience view of `value` for checkmark items.
|
/// Convenience view of `value` for checkmark items.
|
||||||
@@ -352,7 +352,7 @@ extension System {
|
|||||||
public static func addMenuItem(title: String, onSelect: @escaping (MenuItem) -> Void) -> MenuItem? {
|
public static func addMenuItem(title: String, onSelect: @escaping (MenuItem) -> Void) -> MenuItem? {
|
||||||
var item: MenuItem?
|
var item: MenuItem?
|
||||||
title.withPlaydateCString { cTitle in
|
title.withPlaydateCString { cTitle in
|
||||||
let pointer = api.addMenuItem.unsafelyUnwrapped(cTitle, menuItemTrampoline, nil)
|
let pointer = api.pointee.addMenuItem.unsafelyUnwrapped(cTitle, menuItemTrampoline, nil)
|
||||||
item = MenuItem(pointer: pointer, onSelect: onSelect)
|
item = MenuItem(pointer: pointer, onSelect: onSelect)
|
||||||
}
|
}
|
||||||
return registered(item)
|
return registered(item)
|
||||||
@@ -364,7 +364,7 @@ extension System {
|
|||||||
onSelect: @escaping (MenuItem) -> Void) -> MenuItem? {
|
onSelect: @escaping (MenuItem) -> Void) -> MenuItem? {
|
||||||
var item: MenuItem?
|
var item: MenuItem?
|
||||||
title.withPlaydateCString { cTitle in
|
title.withPlaydateCString { cTitle in
|
||||||
let pointer = api.addCheckmarkMenuItem.unsafelyUnwrapped(
|
let pointer = api.pointee.addCheckmarkMenuItem.unsafelyUnwrapped(
|
||||||
cTitle, isChecked ? 1 : 0, menuItemTrampoline, nil)
|
cTitle, isChecked ? 1 : 0, menuItemTrampoline, nil)
|
||||||
item = MenuItem(pointer: pointer, onSelect: onSelect)
|
item = MenuItem(pointer: pointer, onSelect: onSelect)
|
||||||
}
|
}
|
||||||
@@ -382,7 +382,7 @@ extension System {
|
|||||||
var item: MenuItem?
|
var item: MenuItem?
|
||||||
title.withPlaydateCString { cTitle in
|
title.withPlaydateCString { cTitle in
|
||||||
cOptions.withUnsafeMutableBufferPointer { buffer in
|
cOptions.withUnsafeMutableBufferPointer { buffer in
|
||||||
let pointer = api.addOptionsMenuItem.unsafelyUnwrapped(
|
let pointer = api.pointee.addOptionsMenuItem.unsafelyUnwrapped(
|
||||||
cTitle, buffer.baseAddress, Int32(options.count), menuItemTrampoline, nil)
|
cTitle, buffer.baseAddress, Int32(options.count), menuItemTrampoline, nil)
|
||||||
item = MenuItem(pointer: pointer, retainedOptionTitles: copies, onSelect: onSelect)
|
item = MenuItem(pointer: pointer, retainedOptionTitles: copies, onSelect: onSelect)
|
||||||
}
|
}
|
||||||
@@ -393,20 +393,20 @@ extension System {
|
|||||||
/// Registers the wrapper as the item's userdata and keeps it alive.
|
/// Registers the wrapper as the item's userdata and keeps it alive.
|
||||||
private static func registered(_ item: MenuItem?) -> MenuItem? {
|
private static func registered(_ item: MenuItem?) -> MenuItem? {
|
||||||
guard let item else { return nil }
|
guard let item else { return nil }
|
||||||
api.setMenuItemUserdata.unsafelyUnwrapped(
|
api.pointee.setMenuItemUserdata.unsafelyUnwrapped(
|
||||||
item.pointer, Unmanaged.passUnretained(item).toOpaque())
|
item.pointer, Unmanaged.passUnretained(item).toOpaque())
|
||||||
liveMenuItems.append(item)
|
liveMenuItems.append(item)
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func removeMenuItem(_ item: MenuItem) {
|
public static func removeMenuItem(_ item: MenuItem) {
|
||||||
api.removeMenuItem.unsafelyUnwrapped(item.pointer)
|
api.pointee.removeMenuItem.unsafelyUnwrapped(item.pointer)
|
||||||
item.deallocateRetainedTitles()
|
item.deallocateRetainedTitles()
|
||||||
liveMenuItems.removeAll { $0 === item }
|
liveMenuItems.removeAll { $0 === item }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func removeAllMenuItems() {
|
public static func removeAllMenuItems() {
|
||||||
api.removeAllMenuItems.unsafelyUnwrapped()
|
api.pointee.removeAllMenuItems.unsafelyUnwrapped()
|
||||||
for item in liveMenuItems { item.deallocateRetainedTitles() }
|
for item in liveMenuItems { item.deallocateRetainedTitles() }
|
||||||
liveMenuItems = []
|
liveMenuItems = []
|
||||||
}
|
}
|
||||||
@@ -414,35 +414,35 @@ extension System {
|
|||||||
/// Sets a custom image for the pause menu, optionally shifted left by
|
/// Sets a custom image for the pause menu, optionally shifted left by
|
||||||
/// `xOffset` (0...200).
|
/// `xOffset` (0...200).
|
||||||
public static func setMenuImage(_ bitmap: Graphics.Bitmap?, xOffset: Int = 0) {
|
public static func setMenuImage(_ bitmap: Graphics.Bitmap?, xOffset: Int = 0) {
|
||||||
api.setMenuImage.unsafelyUnwrapped(bitmap?.pointer, Int32(xOffset))
|
api.pointee.setMenuImage.unsafelyUnwrapped(bitmap?.pointer, Int32(xOffset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Device state
|
// MARK: - Device state
|
||||||
|
|
||||||
/// Whether the user has enabled the "reduce flashing" accessibility setting.
|
/// Whether the user has enabled the "reduce flashing" accessibility setting.
|
||||||
public static var reduceFlashing: Bool { api.getReduceFlashing.unsafelyUnwrapped() != 0 }
|
public static var reduceFlashing: Bool { api.pointee.getReduceFlashing.unsafelyUnwrapped() != 0 }
|
||||||
|
|
||||||
/// Battery charge, 0...100.
|
/// Battery charge, 0...100.
|
||||||
public static var batteryPercentage: Float { api.getBatteryPercentage.unsafelyUnwrapped() }
|
public static var batteryPercentage: Float { api.pointee.getBatteryPercentage.unsafelyUnwrapped() }
|
||||||
|
|
||||||
public static var batteryVoltage: Float { api.getBatteryVoltage.unsafelyUnwrapped() }
|
public static var batteryVoltage: Float { api.pointee.getBatteryVoltage.unsafelyUnwrapped() }
|
||||||
|
|
||||||
/// Flushes the CPU instruction cache after loading code at runtime.
|
/// Flushes the CPU instruction cache after loading code at runtime.
|
||||||
public static func clearICache() { api.clearICache.unsafelyUnwrapped() }
|
public static func clearICache() { api.pointee.clearICache.unsafelyUnwrapped() }
|
||||||
|
|
||||||
/// Quits the current game and restarts it with the given launch arguments.
|
/// Quits the current game and restarts it with the given launch arguments.
|
||||||
public static func restartGame(launchArguments: String? = nil) {
|
public static func restartGame(launchArguments: String? = nil) {
|
||||||
if let launchArguments {
|
if let launchArguments {
|
||||||
launchArguments.withPlaydateCString { api.restartGame.unsafelyUnwrapped($0) }
|
launchArguments.withPlaydateCString { api.pointee.restartGame.unsafelyUnwrapped($0) }
|
||||||
} else {
|
} else {
|
||||||
api.restartGame.unsafelyUnwrapped(nil)
|
api.pointee.restartGame.unsafelyUnwrapped(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The arguments the game was launched with, and the path of the pdx.
|
/// The arguments the game was launched with, and the path of the pdx.
|
||||||
public static var launchArguments: (arguments: String?, path: String?) {
|
public static var launchArguments: (arguments: String?, path: String?) {
|
||||||
var path: UnsafePointer<CChar>?
|
var path: UnsafePointer<CChar>?
|
||||||
let arguments = api.getLaunchArgs.unsafelyUnwrapped(&path)
|
let arguments = api.pointee.getLaunchArgs.unsafelyUnwrapped(&path)
|
||||||
return (String(playdateCString: arguments), String(playdateCString: path))
|
return (String(playdateCString: arguments), String(playdateCString: path))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,12 +450,12 @@ extension System {
|
|||||||
/// not active or the send fails.
|
/// not active or the send fails.
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func sendMirrorData(command: UInt8, data: UnsafeMutableRawBufferPointer) -> Bool {
|
public static func sendMirrorData(command: UInt8, data: UnsafeMutableRawBufferPointer) -> Bool {
|
||||||
api.sendMirrorData.unsafelyUnwrapped(command, data.baseAddress, Int32(data.count))
|
api.pointee.sendMirrorData.unsafelyUnwrapped(command, data.baseAddress, Int32(data.count))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OS, language, and pdx version information.
|
/// OS, language, and pdx version information.
|
||||||
public static var info: Info {
|
public static var info: Info {
|
||||||
let info = api.getSystemInfo.unsafelyUnwrapped().unsafelyUnwrapped.pointee
|
let info = api.pointee.getSystemInfo.unsafelyUnwrapped().unsafelyUnwrapped.pointee
|
||||||
return Info(osVersion: info.osversion,
|
return Info(osVersion: info.osversion,
|
||||||
language: Language(info.language),
|
language: Language(info.language),
|
||||||
pdxVersion: info.pdxversion)
|
pdxVersion: info.pdxversion)
|
||||||
@@ -464,7 +464,7 @@ extension System {
|
|||||||
/// Looks up a localized string by key from the game's strings files.
|
/// Looks up a localized string by key from the game's strings files.
|
||||||
public static func localizedText(forKey key: String, language: Language = .system) -> String? {
|
public static func localizedText(forKey key: String, language: Language = .system) -> String? {
|
||||||
key.withPlaydateCString { cKey in
|
key.withPlaydateCString { cKey in
|
||||||
guard let cString = api.getLocalizedText.unsafelyUnwrapped(cKey, language.cValue) else {
|
guard let cString = api.pointee.getLocalizedText.unsafelyUnwrapped(cKey, language.cValue) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let text = String(playdateCString: cString)
|
let text = String(playdateCString: cString)
|
||||||
@@ -474,12 +474,12 @@ extension System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The system volume, 0...1.
|
/// The system volume, 0...1.
|
||||||
public static var volume: Float { api.getVolume.unsafelyUnwrapped() }
|
public static var volume: Float { api.pointee.getVolume.unsafelyUnwrapped() }
|
||||||
|
|
||||||
public static var powerStatus: PowerStatus {
|
public static var powerStatus: PowerStatus {
|
||||||
PowerStatus(rawValue: api.getPowerStatus.unsafelyUnwrapped().rawValue)
|
PowerStatus(rawValue: api.pointee.getPowerStatus.unsafelyUnwrapped().rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quits the game and returns to the launcher.
|
/// Quits the game and returns to the launcher.
|
||||||
public static func exitToLauncher() { api.exitToLauncher.unsafelyUnwrapped() }
|
public static func exitToLauncher() { api.pointee.exitToLauncher.unsafelyUnwrapped() }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user