Skip to content

Commit

Permalink
Merge branch 'master' into unsafe-textures-feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Cobrand authored Sep 5, 2017
2 parents 842f174 + 3f856cb commit 2c967ac
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 15 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ If you want a library compatible with earlier versions of SDL, please see
# Documentation

* [crates.io documentation](https://docs.rs/sdl2/), witn no features at all.
* [master documentation](http://angrylawyer.github.io/rust-sdl2/sdl2/) with the following features:
* [master documentation](https://rust-sdl2.github.io/rust-sdl2/sdl2/) with the following features:
* gfx
* image
* mixer
Expand Down Expand Up @@ -383,8 +383,8 @@ Any Pull Request is welcome, however small your contribution may be ! There are,
[changelog]: ./changelog.md
[crates-io-badge]: https://img.shields.io/crates/v/sdl2.svg
[crates-io-url]: https://crates.io/crates/sdl2
[trav-ci-img]: https://travis-ci.org/AngryLawyer/rust-sdl2.png?branch=master
[trav-ci]: https://travis-ci.org/AngryLawyer/rust-sdl2
[trav-ci-img]: https://travis-ci.org/Rust-SDL2/rust-sdl2.png?branch=master
[trav-ci]: https://travis-ci.org/Rust-SDL2/rust-sdl2
[early-sdl]: https://github.com/brson/rust-sdl
[homebrew]: http://brew.sh/
[crates]: http://crates.io/
Expand Down
136 changes: 136 additions & 0 deletions examples/audio-capture-and-replay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
extern crate sdl2;

use sdl2::audio::{AudioCallback, AudioSpecDesired};
use sdl2::AudioSubsystem;
use std::time::Duration;
use std::sync::mpsc;
use std::i16;

const RECORDING_LENGTH_SECONDS: usize = 3;


struct Recording {
record_buffer: Vec<i16>,
pos: usize,
done_sender: mpsc::Sender<Vec<i16>>,
done: bool,
}

// Append the input of the callback to the record_buffer.
// When the record_buffer is full, send it to the main thread via done_sender.
impl AudioCallback for Recording {
type Channel = i16;

fn callback(&mut self, input: &mut [i16]) {
if self.done {
return;
}

for x in input {
self.record_buffer[self.pos] = *x;
self.pos += 1;
if self.pos >= self.record_buffer.len() {
self.done = true;
self.done_sender.send(self.record_buffer.clone()).unwrap();
break;
}
}
}
}

fn record(audio_subsystem: &AudioSubsystem, desired_spec: &AudioSpecDesired) -> Vec<i16> {
println!("Capturing {:} seconds... Please rock!", RECORDING_LENGTH_SECONDS);

let (done_sender, done_receiver) = mpsc::channel();

let capture_device = audio_subsystem.open_capture(None, desired_spec, |spec| {
println!("Capture Spec = {:?}", spec);
Recording {
record_buffer: vec![0; spec.freq as usize * RECORDING_LENGTH_SECONDS * spec.channels as usize],
pos: 0,
done_sender,
done: false
}
}).unwrap();

println!("AudioDriver: {:?}", capture_device.subsystem().current_audio_driver());
capture_device.resume();

// Wait until the recording is done.
let recorded_vec = done_receiver.recv().unwrap();

capture_device.pause();

// Device is automatically closed when dropped.
// Depending on your system it might be even important that the capture_device is dropped
// before the playback starts.

recorded_vec
}


/// Returns a percent value
fn calculate_average_volume(recorded_vec: &[i16]) -> f32 {
let sum: i64 = recorded_vec.iter().map(|&x| (x as i64).abs()).sum();
(sum as f32) / (recorded_vec.len() as f32) / (i16::MAX as f32) * 100.0
}

/// Returns a percent value
fn calculate_max_volume(recorded_vec: &[i16]) -> f32 {
let max: i64 = recorded_vec.iter().map(|&x| (x as i64).abs()).max().unwrap();
(max as f32) / (i16::MAX as f32) * 100.0
}


struct SoundPlayback {
data: Vec<i16>,
pos: usize,
}

impl AudioCallback for SoundPlayback {
type Channel = i16;

fn callback(&mut self, out: &mut [i16]) {
for dst in out.iter_mut() {
*dst = *self.data.get(self.pos).unwrap_or(&0);
self.pos += 1;
}
}
}

fn replay_recorded_vec(audio_subsystem: &AudioSubsystem, desired_spec: &AudioSpecDesired, recorded_vec: Vec<i16>) {
println!("Playing...");

let playback_device = audio_subsystem.open_playback(None, desired_spec, |spec| {
println!("Playback Spec = {:?}", spec);
SoundPlayback {
data: recorded_vec,
pos: 0,
}
}).unwrap();

// Start playback
playback_device.resume();

std::thread::sleep(Duration::from_secs(RECORDING_LENGTH_SECONDS as u64));
// Device is automatically closed when dropped
}


fn main() {
let sdl_context = sdl2::init().unwrap();
let audio_subsystem = sdl_context.audio().unwrap();

let desired_spec = AudioSpecDesired {
freq: None,
channels: None,
samples: None
};

let recorded_vec = record(&audio_subsystem, &desired_spec);

println!("Average Volume of your Recording = {:?}%", calculate_average_volume(&recorded_vec));
println!("Max Volume of your Recording = {:?}%", calculate_max_volume(&recorded_vec));

replay_recorded_vec(&audio_subsystem, &desired_spec, recorded_vec);
}
19 changes: 16 additions & 3 deletions sdl2-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,29 @@
extern crate pkg_config;

fn main() {
if !build_pkgconfig() {
let target = ::std::env::var("TARGET").expect("Cargo build scripts always have TARGET");
let target_os = target.splitn(3, "-").nth(2).unwrap();
let target = ::std::env::var("TARGET").expect("Cargo build scripts always have TARGET");
let target_os = target.splitn(3, "-").nth(2).unwrap();

if !build_pkgconfig() {
if cfg!(feature="use_mac_framework") && target_os == "darwin" {
println!("cargo:rustc-flags=-l framework=SDL2");
} else {
println!("cargo:rustc-flags=-l SDL2");
}
}

if target_os == "ios" {
println!("cargo:rustc-flags=-l framework=AVFoundation");
println!("cargo:rustc-flags=-l framework=AudioToolbox");
println!("cargo:rustc-flags=-l framework=CoreAudio");
println!("cargo:rustc-flags=-l framework=CoreGraphics");
println!("cargo:rustc-flags=-l framework=CoreMotion");
println!("cargo:rustc-flags=-l framework=Foundation");
println!("cargo:rustc-flags=-l framework=GameController");
println!("cargo:rustc-flags=-l framework=OpenGLES");
println!("cargo:rustc-flags=-l framework=QuartzCore");
println!("cargo:rustc-flags=-l framework=UIKit");
}
}

#[cfg(not(feature="pkg-config"))]
Expand Down
33 changes: 33 additions & 0 deletions sdl2-sys/src/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ pub enum SDL_WindowFlags {
SDL_WINDOW_FOREIGN = 0x00000800,
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,
SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,
SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,
SDL_WINDOW_SKIP_TASKBAR = 0x00010000,
SDL_WINDOW_UTILITY = 0x00020000,
SDL_WINDOW_TOOLTIP = 0x00040000,
SDL_WINDOW_POPUP_MENU = 0x00080000,
SDL_WINDOW_VULKAN = 0x00100000,
}

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -142,6 +148,32 @@ pub enum SDL_GLprofile {
SDL_GL_CONTEXT_PROFILE_ES = 0x0004
}

#[repr(u32)]
pub enum SDL_SYSWM_TYPE {
SDL_SYSWM_UNKNOWN,
SDL_SYSWM_WINDOWS,
SDL_SYSWM_X11,
SDL_SYSWM_DIRECTFB,
SDL_SYSWM_COCOA,
SDL_SYSWM_UIKIT,
SDL_SYSWM_WAYLAND,
SDL_SYSWM_MIR,
SDL_SYSWM_WINRT,
SDL_SYSWM_ANDROID,
SDL_SYSWM_VIVANTE
}

#[repr(C)]
pub struct SDL_SysWMinfo {
pub version: ::version::SDL_version,
pub subsystem: SDL_SYSWM_TYPE,
// info should be an untagged union, but it has not it stable yet. Waiting for
// https://github.com/rust-lang/rust/issues/32836 to be closed.
//
// According to http://hg.libsdl.org/SDL/rev/69452f9839d5, this can at most be 64bytes.
pub info: [u8; 64],
}

//SDL_video.h
extern "C" {
pub fn SDL_GetNumVideoDrivers() -> c_int;
Expand Down Expand Up @@ -195,6 +227,7 @@ extern "C" {
pub fn SDL_GetWindowGrab(window: *mut SDL_Window) -> SDL_bool;
pub fn SDL_SetWindowBrightness(window: *mut SDL_Window, brightness: c_float) -> c_int;
pub fn SDL_GetWindowBrightness(window: *mut SDL_Window) -> c_float;
pub fn SDL_GetWindowWMInfo(window: *mut SDL_Window, info: *mut SDL_SysWMinfo) -> SDL_bool;
pub fn SDL_SetWindowGammaRamp(window: *mut SDL_Window, red: *const uint16_t, green: *const uint16_t, blue: *const uint16_t) -> c_int;
pub fn SDL_GetWindowGammaRamp(window: *mut SDL_Window, red: *mut uint16_t, green: *mut uint16_t, blue: *mut uint16_t) -> c_int;
pub fn SDL_DestroyWindow(window: *mut SDL_Window);
Expand Down
33 changes: 30 additions & 3 deletions src/sdl2/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ impl AudioSubsystem {
AudioDevice::open_playback(self, device, spec, get_callback)
}

/// Opens a new audio device for capture (given the desired parameters and callback).
/// Supported since SDL 2.0.5
pub fn open_capture<'a, CB, F, D>(&self, device: D, spec: &AudioSpecDesired, get_callback: F) -> Result<AudioDevice <CB>, String>
where CB: AudioCallback, F: FnOnce(AudioSpec) -> CB, D: Into<Option<&'a str>>,
{
AudioDevice::open_capture(self, device, spec, get_callback)
}

/// Opens a new audio device which uses queueing rather than older callback method.
#[inline]
pub fn open_queue<'a, Channel, D>(&self, device: D, spec: &AudioSpecDesired) -> Result<AudioQueue<Channel>, String>
Expand Down Expand Up @@ -588,8 +596,8 @@ pub struct AudioDevice<CB: AudioCallback> {
}

impl<CB: AudioCallback> AudioDevice<CB> {
/// Opens a new audio device given the desired parameters and callback.
pub fn open_playback<'a, F, D>(a: &AudioSubsystem, device: D, spec: &AudioSpecDesired, get_callback: F) -> Result<AudioDevice <CB>, String>
/// Opens a new audio device for playback or capture (given the desired parameters and callback).
fn open<'a, F, D>(a: &AudioSubsystem, device: D, spec: &AudioSpecDesired, get_callback: F, capture: bool) -> Result<AudioDevice <CB>, String>
where
F: FnOnce(AudioSpec) -> CB,
D: Into<Option<&'a str>>,
Expand All @@ -612,7 +620,7 @@ impl<CB: AudioCallback> AudioDevice<CB> {
};
let device_ptr = device.map_or(ptr::null(), |s| s.as_ptr());

let iscapture_flag = 0;
let iscapture_flag = if capture { 1 } else { 0 };
let device_id = ll::SDL_OpenAudioDevice(
device_ptr as *const c_char, iscapture_flag, &desired,
&mut obtained, 0
Expand Down Expand Up @@ -640,6 +648,25 @@ impl<CB: AudioCallback> AudioDevice<CB> {
}
}

/// Opens a new audio device for playback (given the desired parameters and callback).
pub fn open_playback<'a, F, D>(a: &AudioSubsystem, device: D, spec: &AudioSpecDesired, get_callback: F) -> Result<AudioDevice <CB>, String>
where
F: FnOnce(AudioSpec) -> CB,
D: Into<Option<&'a str>>,
{
AudioDevice::open(a, device, spec, get_callback, false)
}

/// Opens a new audio device for capture (given the desired parameters and callback).
/// Supported since SDL 2.0.5
pub fn open_capture<'a, F, D>(a: &AudioSubsystem, device: D, spec: &AudioSpecDesired, get_callback: F) -> Result<AudioDevice <CB>, String>
where
F: FnOnce(AudioSpec) -> CB,
D: Into<Option<&'a str>>,
{
AudioDevice::open(a, device, spec, get_callback, true)
}

#[inline]
pub fn subsystem(&self) -> &AudioSubsystem { &self.subsystem }

Expand Down
10 changes: 8 additions & 2 deletions src/sdl2/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ impl<T> RendererContext<T> {
Err(SdlError(get_error()))
}
}

unsafe fn get_raw_target(&self) -> *mut ll::SDL_Texture {
ll::SDL_GetRenderTarget(self.raw)
}
}

impl<T: RenderTarget> Deref for Canvas<T> {
Expand Down Expand Up @@ -493,10 +497,11 @@ impl<T: RenderTarget> Canvas<T> {
pub fn with_texture_canvas<F>(&mut self, texture: &mut Texture, f: F)
-> Result<(), TargetRenderError> where for<'r> F: FnOnce(&'r mut Canvas<T>,) {
if self.render_target_supported() {
let target = unsafe { self.get_raw_target() };
unsafe { self.set_raw_target(texture.raw) }
.map_err(|e| TargetRenderError::SdlError(e))?;
f(self);
unsafe { self.set_raw_target(ptr::null_mut()) }
unsafe { self.set_raw_target(target) }
.map_err(|e| TargetRenderError::SdlError(e))?;
Ok(())
} else {
Expand Down Expand Up @@ -565,13 +570,14 @@ impl<T: RenderTarget> Canvas<T> {
-> Result<(), TargetRenderError>
where for<'r> F: FnMut(&'r mut Canvas<T>, &U), I: Iterator<Item=&'s (&'a mut Texture<'t>, U)> {
if self.render_target_supported() {
let target = unsafe { self.get_raw_target() };
for &(ref texture, ref user_context) in textures {
unsafe { self.set_raw_target(texture.raw) }
.map_err(|e| TargetRenderError::SdlError(e))?;
f(self, &user_context);
}
// reset the target to its source
unsafe { self.set_raw_target(ptr::null_mut()) }
unsafe { self.set_raw_target(target) }
.map_err(|e| TargetRenderError::SdlError(e))?;
Ok(())
} else {
Expand Down
32 changes: 28 additions & 4 deletions src/sdl2/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,26 @@ impl WindowContext {
}
}

/// Represents a setting for vsync/swap interval.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[repr(i32)]
pub enum SwapInterval {
Immediate = 0,
VSync = 1,
LateSwapTearing = -1,
}

impl From<i32> for SwapInterval {
fn from(i: i32) -> Self {
match i {
-1 => SwapInterval::LateSwapTearing,
0 => SwapInterval::Immediate,
1 => SwapInterval::VSync,
other => panic!("Invalid value for SwapInterval: {}; valid values are -1, 0, 1", other),
}
}
}

/// Represents the "shell" of a `Window`.
///
/// You can set get and set many of the SDL_Window properties (i.e., border, size, `PixelFormat`, etc)
Expand Down Expand Up @@ -771,12 +791,16 @@ impl VideoSubsystem {
}
}

pub fn gl_set_swap_interval(&self, interval: i32) -> bool {
unsafe { ll::SDL_GL_SetSwapInterval(interval as c_int) == 0 }
pub fn gl_set_swap_interval<S: Into<SwapInterval>>(&self, interval: S) -> bool {
unsafe { ll::SDL_GL_SetSwapInterval(interval.into() as c_int) == 0 }
}

pub fn gl_get_swap_interval(&self) -> i32 {
unsafe { ll::SDL_GL_GetSwapInterval() as i32 }
pub fn gl_get_swap_interval(&self) -> SwapInterval {
unsafe {
let interval = ll::SDL_GL_GetSwapInterval() as i32;
assert!(interval == -1 || interval == 0 || interval == 1);
mem::transmute(interval)
}
}
}

Expand Down

0 comments on commit 2c967ac

Please sign in to comment.