badhouseplants-net/src/content/posts/developing-a-free-alternati...

4.1 KiB

title date draft ShowToc cover
Developing a Free Alternative for Splice 2023-05-31T12:05:44+02:00 true true
image caption relative responsiveImages
cover.png Developing a Free Alternative for Splice false false

Intro

I think that almost everybody knows what Splice is. Basically, it's just a huge library of sounds and VST presets with some additional sweets. I can't say that I'm not satisfied by Splice, it's an applications that is doing pretty good, until you want to use it on Linux. That's something that I don't understand, (I'm almost sure that )it's an Electron application with and some binary running a gRPC server in a background, that I believe is written in GO. Both technologies are working on Linux, so basically, they could have just built a version without promising any real support for that. But they haven't. I've decided to try running it with WINE, but it didn't work. And then I though: There is awesome freesound, and why wouldn't I use it?

Freesound is a collaborative database of Creative Commons Licensed sounds. Browse, download and share sounds.

But downloading samples using a browser it not something I'd like to do. I love Splice for their drag-n-drop app. And I've decided to develop one that will work with Freesound.

Starting the project

I've decided to use Rust and try the Iced for the UI. Here you will find the project git repository: https://git.badhouseplants.net/allanger/frice

Basically, there are two things to do so the MVP is ready

  • Make correct API requests to the Freesound
  • Create a UI

So the very first thing that I'm doing, I'm initializing a project and creating a very simple Iced app using examples

cargo init
cargo add iced
# Cargo.toml
[package]
name = "frice"
version = "0.1.0"
edition = "2021"

[dependencies]
iced = "0.9.0"
// ./src/main.rs
use iced::{Sandbox, Settings, widget::Container};

fn main() -> Result<(), iced::Error>  {
    Frice::run(Settings::default())
}

struct Frice {}

impl Sandbox for Frice {
    type Message = String;

    fn new() -> Self {
        Frice {}
    }

    fn title(&self) -> String {
        "Frice".to_string()
    }

    fn update(&mut self, message: Self::Message) {
        println!("Updating")
    }

    fn view(&self) -> iced::Element<'_, Self::Message> {
        Container::new("frice").center_x().center_y().width(iced::Length::Fill).height(iced::Length::Fill).into()    }
}

API

And now I want to switch to the API, because the UI without API requests won't be able to do anything. As I see now, I'll need to implement two API calls for the MVP:

  1. Search sounds
  2. Download a sound

So let's start with the first one. They have a basic example of searching on their documentation page

curl "https://freesound.org/apiv2/search/text/?query=dogs&token=YOUR_API_KEY"

API key can be created here: https://freesound.org/apiv2/apply

So let's create a FreesoundAPI struct and add two methods there

struct FreesoundAPI {}

impl FreesoundAPI {
    fn new() -> Self {
        Self {}
    }
    
    fn search() {
        todo!()
    }
    
    fn download() {
        todo!()
    }
}

To create an API call I'll need a token, so I need to add a new field to the FreesoundAPI struct

struct FreesoundAPI {
  token: String
}
impl FreesoundAPI {
    fn new(token: String) -> Self {
        Self { token }
    }
...
}

I also need a library for making API calls cargo add reqwest

    pub(crate) fn search(&self) {
        let client = reqwest::blocking::Client::builder().build().unwrap();
        let res = client.get("https://freesound.org/apiv2/search/text")
        .query(&[("token", self.token.as_str()), ("query", "dogs")])
        .send().unwrap();
        println!("{:?}", res.text());
    }

Let's leave it like this for a moment, and try to implement the download method. Freesound API sais that we need to use Oauth to download sounds. Let's try.

cargo add oauth2