swift smooth (interpolate) between incoming continuous data - ios

Working in Swift I have a function which is called on arrival of new data (Double between 0 and 1). I need this function to go smoothly to the next value. In another language (MaxMSP) I could simply say go in 20 milliseconds from the previous value to the new one, this would even work if new data arrived before the set time was over. How could I achieve this in Swift? I've found vDSP.convolve() but I'd need an array of values to interpolate between, in my case data is real time and I have the latest value and previous value(s). The code I have is
var previousValue: Double = 0
var value: Double = 0 {
didSet {
valueDidChange()
}
}
private func valueDidChange() {
let valueSmooth = value * //smoothing magic with previousValue
}

Related

Get the current text inside of a textfield for IOS custom keyboard

I am developing a IOS custom keyboard. I was wondering if there was a way to fetch the current text inside of the text field and how it would work.
For example, we can use textDocumentProxy.hasText() to see if the textfield has text inside but I want to know the exact string that is inside the textfield.
The closest things would be textDocumentProxy.documentContextBeforeInput and textDocumentProxy.documentContextAfterInput. These will respect sentences and such, which means if the value is a paragraph, you will only get the current sentence. Users have been known to retrieve the entire string by repositioning the cursor multiple times until everything is retrieved.
Of course, you generally do not have to worry about this if the field expects a single value like a username, email, id number, etc. Combining the values of both before and after input contexts should suffice.
Sample Code
For the single phrase value, you would do:
let value = (textDocumentProxy.documentContextBeforeInput ?? "") + (textDocumentProxy.documentContextAfterInput ?? "")
For values that might contain sentence ending punctuation, it will be a little more complicated as you need to run it on a separate thread. Because of this, and the fact that you have to move the input cursor to get the full text, the cursor will visibly move. It is also unknown whether this will be accepted into the AppStore (after all, Apple probably did not add an easy way to get the full text on purpose in order to prevent official custom keyboards from invading a user's privacy).
Note: the below code is based off of this Stack Overflow answer except modified for Swift, removed unnecessary sleeps, uses strings with no custom categories, and uses a more efficient movement process.
func foo() {
dispatch_async(dispatch_queue_create("com.example.test", DISPATCH_QUEUE_SERIAL)) { () -> Void in
let string = self.fullDocumentContext()
}
}
func fullDocumentContext() {
let textDocumentProxy = self.textDocumentProxy
var before = textDocumentProxy.documentContextBeforeInput
var completePriorString = "";
// Grab everything before the cursor
while (before != nil && !before!.isEmpty) {
completePriorString = before! + completePriorString
let length = before!.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
textDocumentProxy.adjustTextPositionByCharacterOffset(-length)
NSThread.sleepForTimeInterval(0.01)
before = textDocumentProxy.documentContextBeforeInput
}
// Move the cursor back to the original position
self.textDocumentProxy.adjustTextPositionByCharacterOffset(completePriorString.characters.count)
NSThread.sleepForTimeInterval(0.01)
var after = textDocumentProxy.documentContextAfterInput
var completeAfterString = "";
// Grab everything after the cursor
while (after != nil && !after!.isEmpty) {
completeAfterString += after!
let length = after!.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
textDocumentProxy.adjustTextPositionByCharacterOffset(length)
NSThread.sleepForTimeInterval(0.01)
after = textDocumentProxy.documentContextAfterInput
}
// Go back to the original cursor position
self.textDocumentProxy.adjustTextPositionByCharacterOffset(-(completeAfterString.characters.count))
let completeString = completePriorString + completeAfterString
print(completeString)
return completeString
}

Why increment inside function isn't working?

I try to make function run only one time during runtime, but it fires every time instead
var requestCount: Int = 0
func JSONRequest() {
if self.requestCount == 0 {
...some stuff
self.requestCount = requestCount + 1
} else {
println("JSONRequest dismissed")
}
During debugging I figured out that every time JSONRequest() runs it has value of self.requestCount equal to zero. For some reason it doesn't save increment and every time i call the function the self.requestCount is 0.
Why ? What am I doing wrong ?
Could it be that your code is in a ViewController which is being re-created each time (and therefore the count is re-initialized to zero each time)?
If so, you can do one of the following:
use a singleton - not always the cleanest but it works
use persistence (e.g., CoreData or NSUserDefaults)

Basic Xcode - reference in random number generator not working

I am working on a very basic (I think) program in Xcode. I am trying to write an app for "drawing straws" where the last person who is chosen is the loser. There are a few things I'd like to do. First, see the code below:
import UIKit
let players = 4
var playerNames: [String] = ["John", "Tyler", "Pete", "Dave"]
var draw = Int(arc4random_uniform(4))
playerNames.removeAtIndex(draw)
print(playerNames)
let round2 = playerNames.count
var draw2 = Int(arc4random_uniform(2))
playerNames.removeAtIndex(draw2)
print(playerNames)
let round3 = playerNames.count
var draw3 = Int(arc4random_uniform(1))
playerNames.removeAtIndex(draw3)
print(playerNames)
The first thing that's wrong is I'm currently hard-coding the random integer being drawn in var draw = Int(arc4random_uniform(4)). When I try to reference players instead of just typing in 4, I get an error. Can someone please help explain the problem there?
I'll stop there for now to see if I can fix that, and I'll wait until that is fixed before posting a new question. Thank you.
The function arc4random_uniform() takes a UInt32, so you need to declare the variable players as UInt32
let players: UInt32 = 4
var draw = (arc4random_uniform(players))
For handling the round variables, you would cast the count to UInt32.
let round2 = UInt32(playerNames.count)
You can also refactor your code
let players: UInt32 = 4
var playerNames: [String] = ["John", "Tyler", "Pete", "Dave"]
println(playerNames)
for loop in 1...players {
RemovePlayer(&playerNames)
println(playerNames)
}
And the code for the RemovePlayer function
func RemovePlayer(inout names: [String]) {
// get the number of names in the array
var maxNames = UInt32(names.count)
var draw = Int((arc4random_uniform(maxNames)))
names.removeAtIndex(draw)
}
As Blackfrog already stated your randomization function requires a UInt32
Since you stated that you just started programing I would like to give you some other advice. Your code can be written as:
var playerNames = ["John", "Tyler", "Pete", "Dave"]
for var index = playerNames.count ; index > 1 ; index -= 1{
var random:Int = Int(arc4random_uniform(UInt32(index)))
playerNames.removeAtIndex(random)
}
println(playerNames[0])
This has a few advantages. At the moment you are hardcoding the values for how many players join a game. You will need to re-write an unnecessary amount of code if you want to add a player.
Let’s see what the above code does:
We start by declaring the playerNames adding a type declaration of [String] isn’t necessary, swift already knows that it is this type by its initial value.
for var index = playerNames.count; index > 1 ; index -= 1{
We create a new variable called index this will be set to the amount of items in the playerNames array (4 in this case)
After this we will declare that we want the loop as long as our index is greater than 1 this will make it run 3 times and make sure we are left with 1 item in our array
The index -=1 will subtract 1 from the index after each iteration through the loop.
var random:Int = Int(arc4random_uniform(UInt32(index)))
Here we declare a new variable random this will be of type Integer. Let’s work from the inside to the outside. UIt32(index) will convert our index which is of type Int to a type of UInt32, this is needed cause our random function requires a UInt32
Next up we request a random value which will lay between the index and 0 (thus between the bounds of the array). We want to remove the player who belongs to this random value in our array. To do this we need to convert our random Uint32 back to an Int we can do this by using Int().
Next we remove the player at the index using
playerNames.removeAtIndex(random)
Lastly we print the first (and only) item left in the array using
println(playerNames[0])

Swift: Slice startIndex always 0

I ran afoul of Swift Slice, thinking that firstIndex should be the first index of the slice, in the domain of the source (not sure what else it's useful for). Evidently this is not the case:
let ary = map(1...100) { i in i }
let s:Slice<Int> = ary[10..<20]
s.startIndex // 0
ary[10..<20].startIndex // 0
(10..<20).startIndex // 10 (half-open interval generated from a range, presumably)
Does this seem like a bug? If it's always 0, it seems totally useless.
NOTE: The following applies to Swift 2 or earlier. The behavior has changed since Swift 2.
If you dig around in the auto-generated Swift header file (where it seems most of the documentation is at the moment), you'll find this describing Slice:
/// The `Array`-like type that represents a sub-sequence of any
/// `Array`, `ContiguousArray`, or other `Slice`.
Since Slice is Array-like, it does make sense that startIndex would be returning 0 since an Array's startIndex is always going to be 0. Further down, where it defines startIndex, you'll also see:
/// Always zero, which is the index of the first element when non-empty.
var startIndex: Int { get }
If you're looking for the first entry in the Slice, just use: s.first:
/// The first element, or `nil` if the array is empty
var first: T? { get }
If you need to find the index in the original Array that where the Slice starts, you can do something like this:
if let startValue = s.first {
let index = find(ary, startValue)
/* ... do something with index ... */
}
This is fixed in Swift 2. If you slice an array with a range of 2...5, the startIndex of the slice will be 2. Very cool.

How do I get value of cell before it changes in Google spreadsheet?

This function seems not to be triggered until the cell is exited, as the value i'm getting is the post-change value. I need the pre-change value, but I only need it if in fact that particular column is edited.
Thank you
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
var columnNum = r.getColumn();
var msg;
if (columnNum == 11) {
var dateCell = s.getRange(r.getRow(), 11);
var v=dateCell.getValue();
msg = 'Value= ' + v;
Browser.msgBox (msg);
//dateCell.setValue(v);
}
}
This is a very old question, but in case anyone else needs the answer, it's quite easy to get both the old and new values of any edited cell with the event object:
function onEdit(e) {
let oldValue = e.oldValue;
let newValue = e.value;
console.log("The range's old value was: " + oldValue + ", and the updated value is: " + newValue);
}
Here are are the accessible properties of the Google Sheets event objects.
To the best of my knowledge, capturing the value of a cell before an edit is still not possible.
You might like to star this issue on the issue tracker; it is currently deemed a medium-priority enhancement request.
#AdamL Is there anyway to access the spreadsheets revision history programmatically?
Sorry this is beyond my noob abilities, but my question may hold the clue to a workaround for A B's issue.
#A B ANOTHER POSSIBLE WORKAROUND
You could set up a time based triggers to populate 2 arrays. 1 array from the current data in the column your checking for edits, and 1 array from a previous snapshot of the same data. Then by using a loop to test if any values have changed since your last trigger event, you can determine what value/values have changed(if any) If a value your testing for has changed then push the rowNumber() and colNumber() and getValue() of both previous and current instances of the same data to a new array, also include a timestamp new Date(). Have this new array data populate a new sheet or spreadsheet.
If used in conjunction with your onEdit function, yourll be able to see the before and after value changes, and the approximate time they occured.
Time based triggers can be set to run every minute, hour day etc

Resources