From 734d539a7dbef428402fb232ca7623a215ac3f64 Mon Sep 17 00:00:00 2001 From: Guilherme Felipe Date: Tue, 5 May 2015 15:34:40 -0300 Subject: [PATCH 01/15] Change the order of the filter --- core/globals.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/globals.cpp b/core/globals.cpp index b128914de5..23d8c16ace 100644 --- a/core/globals.cpp +++ b/core/globals.cpp @@ -1381,7 +1381,7 @@ Globals::Globals() { set("application/name","" ); set("application/main_scene",""); - custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"xml,res,scn,xscn"); + custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"scn,res,xscn,xml"); set("application/disable_stdout",false); set("application/use_shared_user_dir",true); From 670d77813f8ded38685eee98f83dc796227a59b7 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:41:41 +0200 Subject: [PATCH 02/15] PhysicsServerSW::body_is_shape_set_as_trigger - missing return statement --- servers/physics/physics_server_sw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 2b4a137e11..03d5b7afa1 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -551,7 +551,7 @@ bool PhysicsServerSW::body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) ERR_FAIL_COND_V(!body,false); ERR_FAIL_INDEX_V(p_shape_idx,body->get_shape_count(),false); - body->is_shape_set_as_trigger(p_shape_idx); + return body->is_shape_set_as_trigger(p_shape_idx); } From edce27fc0328531461f68dd974a72c759e4bcc85 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:43:24 +0200 Subject: [PATCH 03/15] minor fixes in drivers mpc and vorbis. --- drivers/mpc/mpc_reader.c | 1 + drivers/vorbis/psy.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mpc/mpc_reader.c b/drivers/mpc/mpc_reader.c index e1d151fe50..550c5ecb54 100644 --- a/drivers/mpc/mpc_reader.c +++ b/drivers/mpc/mpc_reader.c @@ -36,6 +36,7 @@ #include #include "internal.h" #include +#include // memset() #define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value... typedef struct mpc_reader_stdio_t { diff --git a/drivers/vorbis/psy.c b/drivers/vorbis/psy.c index 9a86151cec..29d2824372 100644 --- a/drivers/vorbis/psy.c +++ b/drivers/vorbis/psy.c @@ -1160,7 +1160,7 @@ void _vp_couple_quantize_normalize(int blobno, However, this is a temporary patch. by Aoyumi @ 2004/04/18 */ - /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit))); + /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit))); */ /* elliptical if(reM[j]+reA[j]<0){ reM[j] = - (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate); From d177e0f64a03fdafd3401456639834c76dfbf32b Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:46:02 +0200 Subject: [PATCH 04/15] fixed issue with format string in PCKPacker::flush --- tools/pck/pck_packer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pck/pck_packer.cpp b/tools/pck/pck_packer.cpp index 09611b3a93..d398fefb5f 100644 --- a/tools/pck/pck_packer.cpp +++ b/tools/pck/pck_packer.cpp @@ -136,7 +136,7 @@ Error PCKPacker::flush(bool p_verbose) { count += 1; if (p_verbose) { if (count % 100 == 0) { - printf("%i/%i (%.2f\%)\r", count, files.size(), float(count) / files.size() * 100); + printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100); fflush(stdout); }; }; From dcc93a33fdc8c1362545107a604e67e60a061489 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:49:00 +0200 Subject: [PATCH 05/15] fixed SpatialEditor::_init_indications. loopcounter "i" used ambiguous --- tools/editor/plugins/spatial_editor_plugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 4dae60399b..ac2ea9799e 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -3172,11 +3172,11 @@ void SpatialEditor::_init_indicators() { int arrow_sides=6; - for(int i = 0; i < 7 ; i++) { + for(int k = 0; k < 7 ; k++) { - Matrix3 ma(ivec,Math_PI*2*float(i)/arrow_sides); - Matrix3 mb(ivec,Math_PI*2*float(i+1)/arrow_sides); + Matrix3 ma(ivec,Math_PI*2*float(k)/arrow_sides); + Matrix3 mb(ivec,Math_PI*2*float(k+1)/arrow_sides); for(int j=0;j Date: Wed, 6 May 2015 00:51:49 +0200 Subject: [PATCH 06/15] added notes to resolve undefined behavior of calculations in tweening interpolators in future. --- scene/animation/tween_interpolaters.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scene/animation/tween_interpolaters.cpp b/scene/animation/tween_interpolaters.cpp index c052d752f8..9128d220de 100644 --- a/scene/animation/tween_interpolaters.cpp +++ b/scene/animation/tween_interpolaters.cpp @@ -285,18 +285,18 @@ namespace cubic { namespace circ { static real_t in(real_t t, real_t b, real_t c, real_t d) { - return -c * (sqrt(1 - (t /= d) * t) - 1) + b; + return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined } static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * sqrt(1 - (t = t / d - 1) * t) + b; + return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; - return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; + return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined } static real_t out_in(real_t t, real_t b, real_t c, real_t d) @@ -364,15 +364,15 @@ namespace back { static real_t out(real_t t, real_t b, real_t c, real_t d) { float s = 1.70158f; - return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b; + return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { float s = 1.70158f; - if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; + if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined float postFix = t -= 2; - return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; + return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined } static real_t out_in(real_t t, real_t b, real_t c, real_t d) From 897a1aade5332753d9fda950d80495798cdc85b4 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 00:56:59 +0200 Subject: [PATCH 07/15] optional formal changes --- core/io/resource_format_xml.cpp | 2 +- core/math/math_funcs.cpp | 7 ++++--- platform/x11/os_x11.cpp | 4 ++-- scene/2d/camera_2d.cpp | 3 +-- scene/gui/line_edit.cpp | 2 +- scene/gui/text_edit.cpp | 4 ++-- servers/physics/collision_object_sw.h | 4 +++- servers/visual/rasterizer.h | 10 +++++----- servers/visual/visual_server_raster.cpp | 2 +- tools/docdump/doc_dump.cpp | 2 +- tools/editor/animation_editor.cpp | 2 +- tools/editor/editor_file_system.cpp | 8 ++++---- .../editor/io_plugins/editor_texture_import_plugin.cpp | 2 ++ tools/editor/plugins/shader_graph_editor_plugin.cpp | 1 - tools/editor/spatial_editor_gizmos.cpp | 3 ++- 15 files changed, 30 insertions(+), 26 deletions(-) diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index 9de33e7ef3..3e625ba6fd 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -1850,7 +1850,7 @@ void ResourceFormatSaverXMLInstance::escape(String& p_str) { p_str=p_str.replace(">","<"); p_str=p_str.replace("'","'"); p_str=p_str.replace("\"","""); - for (int i=1;i<32;i++) { + for (char i=1;i<32;i++) { char chr[2]={i,0}; const char hexn[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 6ad5c7499b..3c94ac5bc7 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -36,8 +36,9 @@ uint32_t Math::default_seed=1; #define PHI 0x9e3779b9 -static uint32_t Q[4096], c = 362436; - +#if 0 +static uint32_t Q[4096]; +#endif uint32_t Math::rand_from_seed(uint32_t *seed) { @@ -269,7 +270,7 @@ bool Math::is_inf(double p_val) { uint32_t Math::larger_prime(uint32_t p_val) { - static const int primes[] = { + static const uint32_t primes[] = { 5, 13, 23, diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 67ec33f3a3..28427fa2f0 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -317,8 +317,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi /* set the name and class hints for the window manager to use */ classHint = XAllocClassHint(); if (classHint) { - classHint->res_name = "Godot"; - classHint->res_class = "Godot"; + classHint->res_name = (char *)"Godot"; + classHint->res_class = (char *)"Godot"; } XSetClassHint(x11_display, x11_window, classHint); XFree(classHint); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 27a512845c..70b88a6611 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -132,8 +132,7 @@ Matrix32 Camera2D::get_camera_transform() { } - Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());; - screen_offset; + Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2()); float angle = get_global_transform().get_rotation(); if(rotating){ diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 14aa3da85f..fec9e401f1 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -272,7 +272,7 @@ void LineEdit::_input_event(InputEvent p_event) { if (editable) { selection_delete(); - CharType ucodestr[2]={k.unicode,0}; + CharType ucodestr[2]={(CharType)k.unicode,0}; append_at_cursor(ucodestr); emit_signal("text_changed",text); _change_notify("text"); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 681c33652e..db8fbf7a63 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1440,7 +1440,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } else { //different char, go back - const CharType chr[2] = {k.unicode, 0}; + const CharType chr[2] = {(CharType)k.unicode, 0}; if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); } else { @@ -2062,7 +2062,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (readonly) break; - const CharType chr[2] = {k.unicode, 0}; + const CharType chr[2] = {(CharType)k.unicode, 0}; if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index 70fc3e8fcb..c018ab6224 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -34,8 +34,10 @@ #include "self_list.h" #include "broad_phase_sw.h" -#define MAX_OBJECT_DISTANCE 10000000 +#ifdef DEBUG_ENABLED +#define MAX_OBJECT_DISTANCE 10000000.0 #define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE*MAX_OBJECT_DISTANCE) +#endif class SpaceSW; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 81862fb3a6..79365f7db6 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -863,17 +863,17 @@ public: if (polygon->indices != NULL) { r.pos=polygon->points[polygon->indices[0]]; - for (int i=1; icount; i++) { + for (int i=1; ipoints[polygon->indices[i]]); - }; + } } else { r.pos=polygon->points[0]; - for (int i=1; icount; i++) { + for (int i=1; ipoints[i]); - }; - }; + } + } } break; case CanvasItem::Command::TYPE_CIRCLE: { diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 6556f8bc42..a547da9b61 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -7281,7 +7281,7 @@ void VisualServerRaster::_draw_viewports() { if (r.size.width==0) r.size.width=window_w; if (r.size.height==0) - r.size.height=window_w; + r.size.height=window_h; _draw_viewport(vp,r.pos.x,r.pos.y,r.size.width,r.size.height); diff --git a/tools/docdump/doc_dump.cpp b/tools/docdump/doc_dump.cpp index d10f6c9ce3..17aff3dc74 100644 --- a/tools/docdump/doc_dump.cpp +++ b/tools/docdump/doc_dump.cpp @@ -65,7 +65,7 @@ static String _escape_string(const String& p_str) { ret=ret.replace(">","<"); ret=ret.replace("'","'"); ret=ret.replace("\"","""); - for (int i=1;i<32;i++) { + for (char i=1;i<32;i++) { char chr[2]={i,0}; ret=ret.replace(chr,"&#"+String::num(i)+";"); diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index 39eec4e69b..63ab186a38 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -1375,7 +1375,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { if (p_input.is_action("ui_up")) selected_track--; if (v_scroll->is_visible() && p_input.is_action("ui_page_up")) - selected_track--;; + selected_track--; if (selected_track<0) selected_track=0; diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index 94e887c3e7..8e96123c36 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -940,19 +940,19 @@ String EditorFileSystem::get_file_type(const String& p_file) const { EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) { if (!filesystem || scanning) - return false; + return NULL; String f = Globals::get_singleton()->localize_path(p_path); if (!f.begins_with("res://")) - return false; + return NULL; f=f.substr(6,f.length()); f=f.replace("\\","/"); if (f==String()) - return filesystem; + return filesystem; if (f.ends_with("/")) f=f.substr(0,f.length()-1); @@ -960,7 +960,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) { Vector path = f.split("/"); if (path.size()==0) - return false; + return NULL; EditorFileSystemDirectory *fs=filesystem; diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 64b5d5b337..3add30d81e 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -51,6 +51,7 @@ static const char *flag_names[]={ NULL }; +#if 0 // not used static const char *flag_short_names[]={ "Stream", "FixBorder", @@ -65,6 +66,7 @@ static const char *flag_short_names[]={ "Anisoropic", NULL }; +#endif void EditorImportTextureOptions::set_format(EditorTextureImportPlugin::ImageFormat p_format) { diff --git a/tools/editor/plugins/shader_graph_editor_plugin.cpp b/tools/editor/plugins/shader_graph_editor_plugin.cpp index 1db901e56b..03fcbffa24 100644 --- a/tools/editor/plugins/shader_graph_editor_plugin.cpp +++ b/tools/editor/plugins/shader_graph_editor_plugin.cpp @@ -539,7 +539,6 @@ void GraphCurveMapEdit::_plot_curve(const Vector2& p_a,const Vector2& p_b,const if ((lastx != newx) || (lasty != newy)) { #if 0 - /* if(fix255) { /* use fixed array size (for the curve graph) */ diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index f9d92c8d81..521a10bbd0 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -1257,7 +1257,8 @@ void SkeletonSpatialGizmo::redraw() { //find closest axis int closest=-1; - float closest_d; + float closest_d = 0.0; + for(int j=0;j<3;j++) { float dp = Math::abs(grests[parent].basis[j].normalized().dot(d)); if (j==0 || dp>closest_d) From b89cd136a9ce85d1ecf397e8129897a5bd2dd839 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 01:03:05 +0200 Subject: [PATCH 08/15] fixed ColorRgb attribute init order of struct --- drivers/pvr/ColorRgba.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pvr/ColorRgba.h b/drivers/pvr/ColorRgba.h index 6b46d65e3c..0701420566 100644 --- a/drivers/pvr/ColorRgba.h +++ b/drivers/pvr/ColorRgba.h @@ -11,21 +11,21 @@ public: ColorRgb() - : r(0) + : b(0) , g(0) - , b(0) { + , r(0) { } ColorRgb(T red, T green, T blue) - : r(red) + : b(blue) , g(green) - , b(blue) { + , r(red) { } ColorRgb(const ColorRgb &x) - : r(x.r) + : b(x.b) , g(x.g) - , b(x.b) { + , r(x.r) { } ColorRgb operator *(int x) { From ac9263c680076eed36887a681cb59fdcce6c6f73 Mon Sep 17 00:00:00 2001 From: ehriche Date: Wed, 6 May 2015 01:39:42 +0200 Subject: [PATCH 09/15] clearified parenthesis of if construct --- scene/gui/label.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 1751d335ee..dac21275dc 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -433,7 +433,7 @@ void Label::regenerate_word_cache() { } - if ((autowrap && line_width>=width && (last && last->char_pos >= 0 || not_latin)) || insert_newline) { + if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || not_latin)) || insert_newline) { if (not_latin) { if (current_word_size>0) { WordCache *wc = memnew( WordCache ); From 2f4c435bfaf4bf8c9353433ef00eff228169c013 Mon Sep 17 00:00:00 2001 From: yg2f Date: Wed, 6 May 2015 23:08:06 +0200 Subject: [PATCH 10/15] update rtaudio to latest version update rtaudio from latest version availbale on github --- drivers/rtaudio/RtAudio.cpp | 364 ++++++++++++++++++++++-------------- drivers/rtaudio/RtAudio.h | 3 +- 2 files changed, 230 insertions(+), 137 deletions(-) diff --git a/drivers/rtaudio/RtAudio.cpp b/drivers/rtaudio/RtAudio.cpp index 04e7b4422e..8876f72e21 100644 --- a/drivers/rtaudio/RtAudio.cpp +++ b/drivers/rtaudio/RtAudio.cpp @@ -46,6 +46,7 @@ #include #include #include +#include // Static variable definitions. const unsigned int RtApi::MAX_SAMPLE_RATES = 14; @@ -63,6 +64,22 @@ const unsigned int RtApi::SAMPLE_RATES[] = { #define MUTEX_DESTROY(A) DeleteCriticalSection(A) #define MUTEX_LOCK(A) EnterCriticalSection(A) #define MUTEX_UNLOCK(A) LeaveCriticalSection(A) + + #include "tchar.h" + + static std::string convertCharPointerToStdString(const char *text) + { + return std::string(text); + } + + static std::string convertCharPointerToStdString(const wchar_t *text) + { + int length = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL); + std::string s( length-1, '\0' ); + WideCharToMultiByte(CP_UTF8, 0, text, -1, &s[0], length, NULL, NULL); + return s; + } + #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) // pthread API #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) @@ -184,7 +201,7 @@ RtAudio :: RtAudio( RtAudio::Api api ) getCompiledApi( apis ); for ( unsigned int i=0; igetDeviceCount() ) break; + if ( rtapi_ && rtapi_->getDeviceCount() ) break; } if ( rtapi_ ) return; @@ -766,9 +783,14 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) bool haveValueRange = false; info.sampleRates.clear(); for ( UInt32 i=0; i info.preferredSampleRate ) ) + info.preferredSampleRate = tmpSr; + + } else { haveValueRange = true; if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum; if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum; @@ -777,8 +799,12 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) if ( haveValueRange ) { for ( unsigned int k=0; k= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) + if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) { info.sampleRates.push_back( SAMPLE_RATES[k] ); + + if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + } } } @@ -1385,6 +1411,18 @@ void RtApiCore :: closeStream( void ) CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { + if (handle) { + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + property.mSelector = kAudioDeviceProcessorOverload; + property.mScope = kAudioObjectPropertyScopeGlobal; + if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) { + errorText_ = "RtApiCore::closeStream(): error removing property listener!"; + error( RtAudioError::WARNING ); + } + } if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[0], callbackHandler ); #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) @@ -1396,6 +1434,18 @@ void RtApiCore :: closeStream( void ) } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { + if (handle) { + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + property.mSelector = kAudioDeviceProcessorOverload; + property.mScope = kAudioObjectPropertyScopeGlobal; + if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) { + errorText_ = "RtApiCore::closeStream(): error removing property listener!"; + error( RtAudioError::WARNING ); + } + } if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[1], callbackHandler ); #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) @@ -1989,7 +2039,9 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) // Get the current jack server sample rate. info.sampleRates.clear(); - info.sampleRates.push_back( jack_get_sample_rate( client ) ); + + info.preferredSampleRate = jack_get_sample_rate( client ); + info.sampleRates.push_back( info.preferredSampleRate ); // Count the available ports containing the client name as device // channels. Jack "input ports" equal RtAudio output channels. @@ -2769,8 +2821,12 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) info.sampleRates.clear(); for ( unsigned int i=0; i info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[i]; + } } // Determine supported data types ... just check first channel and assume rest are the same. @@ -2829,9 +2885,12 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) -{ +{//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool isDuplexInput = mode == INPUT && stream_.mode == OUTPUT; + // For ASIO, a duplex stream MUST use the same driver. - if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) { + if ( isDuplexInput && stream_.device[0] != device ) { errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!"; return FAILURE; } @@ -2845,7 +2904,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } // Only load the driver once for duplex stream. - if ( mode != INPUT || stream_.mode != OUTPUT ) { + if ( !isDuplexInput ) { // The getDeviceInfo() function will not work when a stream is open // because ASIO does not allow multiple devices to run at the same // time. Thus, we'll probe the system before opening a stream and @@ -2866,22 +2925,26 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } } + // keep them before any "goto error", they are used for error cleanup + goto device boundary checks + bool buffersAllocated = false; + AsioHandle *handle = (AsioHandle *) stream_.apiHandle; + unsigned int nChannels; + + // Check the device channel count. long inputChannels, outputChannels; result = ASIOGetChannels( &inputChannels, &outputChannels ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) || ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; @@ -2890,30 +2953,27 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Verify the sample rate is supported. result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Get the current sample rate ASIOSampleRate currentRate; result = ASIOGetSampleRate( ¤tRate ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Set the sample rate only if necessary if ( currentRate != sampleRate ) { result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } } @@ -2924,10 +2984,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne else channelInfo.isInput = true; result = ASIOGetChannelInfo( &channelInfo ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Assuming WINDOWS host is always little-endian. @@ -2956,10 +3015,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } if ( stream_.deviceFormat[mode] == 0 ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } // Set the buffer size. For a duplex stream, this will end up @@ -2968,49 +3026,63 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne long minSize, maxSize, preferSize, granularity; result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity ); if ( result != ASE_OK ) { - drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size."; errorText_ = errorStream_.str(); - return FAILURE; + goto error; } - if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; - else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; - else if ( granularity == -1 ) { - // Make sure bufferSize is a power of two. - int log2_of_min_size = 0; - int log2_of_max_size = 0; + if ( isDuplexInput ) { + // When this is the duplex input (output was opened before), then we have to use the same + // buffersize as the output, because it might use the preferred buffer size, which most + // likely wasn't passed as input to this. The buffer sizes have to be identically anyway, + // So instead of throwing an error, make them equal. The caller uses the reference + // to the "bufferSize" param as usual to set up processing buffers. - for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { - if ( minSize & ((long)1 << i) ) log2_of_min_size = i; - if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; - } + *bufferSize = stream_.bufferSize; - long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); - int min_delta_num = log2_of_min_size; - - for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { - long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); - if (current_delta < min_delta) { - min_delta = current_delta; - min_delta_num = i; - } - } - - *bufferSize = ( (unsigned int)1 << min_delta_num ); - if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; + } else { + if ( *bufferSize == 0 ) *bufferSize = preferSize; + else if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; - } - else if ( granularity != 0 ) { - // Set to an even multiple of granularity, rounding up. - *bufferSize = (*bufferSize + granularity-1) / granularity * granularity; + else if ( granularity == -1 ) { + // Make sure bufferSize is a power of two. + int log2_of_min_size = 0; + int log2_of_max_size = 0; + + for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { + if ( minSize & ((long)1 << i) ) log2_of_min_size = i; + if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; + } + + long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); + int min_delta_num = log2_of_min_size; + + for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { + long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); + if (current_delta < min_delta) { + min_delta = current_delta; + min_delta_num = i; + } + } + + *bufferSize = ( (unsigned int)1 << min_delta_num ); + if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; + else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; + } + else if ( granularity != 0 ) { + // Set to an even multiple of granularity, rounding up. + *bufferSize = (*bufferSize + granularity-1) / granularity * granularity; + } } - if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) { - drivers.removeCurrentDriver(); + /* + // we don't use it anymore, see above! + // Just left it here for the case... + if ( isDuplexInput && stream_.bufferSize != *bufferSize ) { errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!"; - return FAILURE; + goto error; } + */ stream_.bufferSize = *bufferSize; stream_.nBuffers = 2; @@ -3022,16 +3094,13 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.deviceInterleaved[mode] = false; // Allocate, if necessary, our AsioHandle structure for the stream. - AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( handle == 0 ) { try { handle = new AsioHandle; } catch ( std::bad_alloc& ) { - //if ( handle == NULL ) { - drivers.removeCurrentDriver(); errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory."; - return FAILURE; + goto error; } handle->bufferInfos = 0; @@ -3046,15 +3115,14 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Create the ASIO internal buffers. Since RtAudio sets up input // and output separately, we'll have to dispose of previously // created output buffers for a duplex stream. - long inputLatency, outputLatency; if ( mode == INPUT && stream_.mode == OUTPUT ) { ASIODisposeBuffers(); if ( handle->bufferInfos ) free( handle->bufferInfos ); } // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure. - bool buffersAllocated = false; - unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; + unsigned int i; + nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) ); if ( handle->bufferInfos == NULL ) { errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ")."; @@ -3075,18 +3143,37 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne infos->buffers[0] = infos->buffers[1] = 0; } + // prepare for callbacks + stream_.sampleRate = sampleRate; + stream_.device[mode] = device; + stream_.mode = isDuplexInput ? DUPLEX : mode; + + // store this class instance before registering callbacks, that are going to use it + asioCallbackInfo = &stream_.callbackInfo; + stream_.callbackInfo.object = (void *) this; + // Set up the ASIO callback structure and create the ASIO data buffers. asioCallbacks.bufferSwitch = &bufferSwitch; asioCallbacks.sampleRateDidChange = &sampleRateChanged; asioCallbacks.asioMessage = &asioMessages; asioCallbacks.bufferSwitchTimeInfo = NULL; result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks ); + if ( result != ASE_OK ) { + // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges + // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver + // in that case, let's be naïve and try that instead + *bufferSize = preferSize; + stream_.bufferSize = *bufferSize; + result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks ); + } + if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers."; errorText_ = errorStream_.str(); goto error; } - buffersAllocated = true; + buffersAllocated = true; + stream_.state = STREAM_STOPPED; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; @@ -3109,11 +3196,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); - if ( mode == INPUT ) { - if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { - unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); - if ( bufferBytes <= bytesOut ) makeBuffer = false; - } + if ( isDuplexInput && stream_.deviceBuffer ) { + unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); + if ( bufferBytes <= bytesOut ) makeBuffer = false; } if ( makeBuffer ) { @@ -3127,18 +3212,8 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } } - stream_.sampleRate = sampleRate; - stream_.device[mode] = device; - stream_.state = STREAM_STOPPED; - asioCallbackInfo = &stream_.callbackInfo; - stream_.callbackInfo.object = (void *) this; - if ( stream_.mode == OUTPUT && mode == INPUT ) - // We had already set up an output stream. - stream_.mode = DUPLEX; - else - stream_.mode = mode; - // Determine device latencies + long inputLatency, outputLatency; result = ASIOGetLatencies( &inputLatency, &outputLatency ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency."; @@ -3158,32 +3233,38 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne return SUCCESS; error: - if ( buffersAllocated ) - ASIODisposeBuffers(); - drivers.removeCurrentDriver(); + if ( !isDuplexInput ) { + // the cleanup for error in the duplex input, is done by RtApi::openStream + // So we clean up for single channel only - if ( handle ) { - CloseHandle( handle->condition ); - if ( handle->bufferInfos ) - free( handle->bufferInfos ); - delete handle; - stream_.apiHandle = 0; - } + if ( buffersAllocated ) + ASIODisposeBuffers(); - for ( int i=0; i<2; i++ ) { - if ( stream_.userBuffer[i] ) { - free( stream_.userBuffer[i] ); - stream_.userBuffer[i] = 0; + drivers.removeCurrentDriver(); + + if ( handle ) { + CloseHandle( handle->condition ); + if ( handle->bufferInfos ) + free( handle->bufferInfos ); + + delete handle; + stream_.apiHandle = 0; + } + + + if ( stream_.userBuffer[mode] ) { + free( stream_.userBuffer[mode] ); + stream_.userBuffer[mode] = 0; + } + + if ( stream_.deviceBuffer ) { + free( stream_.deviceBuffer ); + stream_.deviceBuffer = 0; } } - if ( stream_.deviceBuffer ) { - free( stream_.deviceBuffer ); - stream_.deviceBuffer = 0; - } - return FAILURE; -} +}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RtApiAsio :: closeStream() { @@ -3635,12 +3716,12 @@ public: outIndex_( 0 ) {} ~WasapiBuffer() { - delete buffer_; + free( buffer_ ); } // sets the length of the internal ring buffer void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) { - delete buffer_; + free( buffer_ ); buffer_ = ( char* ) calloc( bufferSize, formatBytes ); @@ -3799,7 +3880,7 @@ void convertBufferWasapi( char* outBuffer, float sampleStep = 1.0f / sampleRatio; float inSampleFraction = 0.0f; - outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio ); + outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio ); // frame-by-frame, copy each relative input sample into it's corresponding output sample for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ ) @@ -3945,7 +4026,6 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) RtAudio::DeviceInfo info; unsigned int captureDeviceCount = 0; unsigned int renderDeviceCount = 0; - std::wstring deviceName; std::string defaultDeviceName; bool isCaptureDevice = false; @@ -4048,8 +4128,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) goto Exit; } - deviceName = defaultDeviceNameProp.pwszVal; - defaultDeviceName = std::string( deviceName.begin(), deviceName.end() ); + defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal); // name hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore ); @@ -4066,8 +4145,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) goto Exit; } - deviceName = deviceNameProp.pwszVal; - info.name = std::string( deviceName.begin(), deviceName.end() ); + info.name =convertCharPointerToStdString(deviceNameProp.pwszVal); // is default if ( isCaptureDevice ) { @@ -4110,6 +4188,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) { info.sampleRates.push_back( SAMPLE_RATES[i] ); } + info.preferredSampleRate = deviceFormat->nSamplesPerSec; // native format info.nativeFormats = 0; @@ -5245,14 +5324,11 @@ unsigned int RtApiDs :: getDeviceCount( void ) error( RtAudioError::WARNING ); } - // Clean out any devices that may have disappeared. - std::vector< int > indices; - for ( unsigned int i=0; i(dsDevices.size()); } @@ -5308,8 +5384,12 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device ) info.sampleRates.clear(); for ( unsigned int k=0; k= (unsigned int) outCaps.dwMinSecondarySampleRate && - SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) + SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) { info.sampleRates.push_back( SAMPLE_RATES[k] ); + + if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + } } // Get format information. @@ -6264,6 +6344,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6271,6 +6352,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6279,6 +6361,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6286,6 +6369,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6307,6 +6391,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6399,6 +6484,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6412,6 +6498,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6448,6 +6535,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6509,6 +6597,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6523,6 +6612,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6544,6 +6634,7 @@ void RtApiDs :: callbackEvent() if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!"; errorText_ = errorStream_.str(); + MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } @@ -6582,21 +6673,6 @@ static unsigned __stdcall callbackHandler( void *ptr ) return 0; } -#include "tchar.h" - -static std::string convertTChar( LPCTSTR name ) -{ -#if defined( UNICODE ) || defined( _UNICODE ) - int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); - std::string s( length-1, '\0' ); - WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL); -#else - std::string s( name ); -#endif - - return s; -} - static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR description, LPCTSTR /*module*/, @@ -6638,7 +6714,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, } // If good device, then save its name and guid. - std::string name = convertTChar( description ); + std::string name = convertCharPointerToStdString( description ); //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" ) if ( lpguid == NULL ) name = "Default Device"; @@ -6820,6 +6896,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) // Count cards and devices card = -1; + subdevice = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); @@ -7033,8 +7110,12 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) // Test our discrete set of sample rate values. info.sampleRates.clear(); for ( unsigned int i=0; i info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[i]; + } } if ( info.sampleRates.size() == 0 ) { snd_pcm_close( phandle ); @@ -7959,6 +8040,8 @@ void RtApiAlsa :: callbackEvent() errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } + else + errorText_ = "RtApiAlsa::callbackEvent: audio write error, underrun."; } else { errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << "."; @@ -8067,6 +8150,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ ) for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) info.sampleRates.push_back( *sr ); + info.preferredSampleRate = 48000; info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32; return info; @@ -8429,7 +8513,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, pah = static_cast( stream_.apiHandle ); int error; - if ( !options->streamName.empty() ) streamName = options->streamName; + if ( options && !options->streamName.empty() ) streamName = options->streamName; switch ( mode ) { case INPUT: pa_buffer_attr buffer_attr; @@ -8635,6 +8719,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) for ( unsigned int k=0; k info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + break; } } @@ -8643,8 +8731,12 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) else { // Check min and max rate values; for ( unsigned int k=0; k= (int) SAMPLE_RATES[k] ) + if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) { info.sampleRates.push_back( SAMPLE_RATES[k] ); + + if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) ) + info.preferredSampleRate = SAMPLE_RATES[k]; + } } } diff --git a/drivers/rtaudio/RtAudio.h b/drivers/rtaudio/RtAudio.h index 1f1b63072c..7d45d36529 100644 --- a/drivers/rtaudio/RtAudio.h +++ b/drivers/rtaudio/RtAudio.h @@ -310,12 +310,13 @@ class RtAudio bool isDefaultOutput; /*!< true if this is the default output device. */ bool isDefaultInput; /*!< true if this is the default input device. */ std::vector sampleRates; /*!< Supported sample rates (queried from list of standard rates). */ + unsigned int preferredSampleRate; /*!< Preferred sample rate, eg. for WASAPI the system sample rate. */ RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */ // Default constructor. DeviceInfo() :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0), - isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {} + isDefaultOutput(false), isDefaultInput(false), preferredSampleRate(0), nativeFormats(0) {} }; //! The structure for specifying input or ouput stream parameters. From 93095014fd87f1a33bdeaeb1f05eaab9342320bc Mon Sep 17 00:00:00 2001 From: "Daniel T. Borelli" Date: Wed, 6 May 2015 20:37:25 -0300 Subject: [PATCH 11/15] Fix segment violation MINIZIP_ENABLED --- core/io/file_access_pack.cpp | 4 +++- main/main.cpp | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index bf1211f2b3..339a6d0528 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -92,7 +92,9 @@ void PackedData::add_path(const String& pkg_path, const String& path, uint64_t o void PackedData::add_pack_source(PackSource *p_source) { - sources.push_back(p_source); + if (p_source != NULL) { + sources.push_back(p_source); + } }; PackedData *PackedData::singleton=NULL; diff --git a/main/main.cpp b/main/main.cpp index aa4a4b8919..1469ce4618 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -251,7 +251,14 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas packed_data = memnew(PackedData); #ifdef MINIZIP_ENABLED + + //XXX: always get_singleton() == 0x0 zip_packed_data = ZipArchive::get_singleton(); + //TODO: remove this temporary fix + if (!zip_packed_data) { + zip_packed_data = memnew(ZipArchive); + } + packed_data->add_pack_source(zip_packed_data); #endif @@ -748,10 +755,12 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas if (file_access_network_client) memdelete(file_access_network_client); -#ifdef MINIZIP_ENABLED - if (zip_packed_data) - memdelete( zip_packed_data ); -#endif +// Note 1: *zip_packed_data live into *packed_data +// Note 2: PackedData::~PackedData destroy this. +//#ifdef MINIZIP_ENABLED +// if (zip_packed_data) +// memdelete( zip_packed_data ); +//#endif unregister_core_types(); From ead2dd3db59d22b013da608c002e31603be16169 Mon Sep 17 00:00:00 2001 From: Nicolas Laurito Date: Wed, 6 May 2015 23:53:20 -0300 Subject: [PATCH 12/15] Delete line without functionality --- demos/2d/kinematic_char/player.gd | 2 -- 1 file changed, 2 deletions(-) diff --git a/demos/2d/kinematic_char/player.gd b/demos/2d/kinematic_char/player.gd index ddc0271de0..329382408b 100644 --- a/demos/2d/kinematic_char/player.gd +++ b/demos/2d/kinematic_char/player.gd @@ -34,8 +34,6 @@ func _fixed_process(delta): #create forces var force = Vector2(0,GRAVITY) - - var stop = velocity.x!=0.0 var walk_left = Input.is_action_pressed("move_left") var walk_right = Input.is_action_pressed("move_right") From 48afa1d2847bdf7d23c21a76494c4789d3bdc9e1 Mon Sep 17 00:00:00 2001 From: hurikhan Date: Wed, 6 May 2015 23:07:11 -0400 Subject: [PATCH 13/15] window_management input fix --- demos/misc/window_management/control.gd | 10 +++++++++- .../window_management/window_management.scn | Bin 5129 -> 5132 bytes 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/demos/misc/window_management/control.gd b/demos/misc/window_management/control.gd index 5eb5817619..1609dda699 100644 --- a/demos/misc/window_management/control.gd +++ b/demos/misc/window_management/control.gd @@ -1,6 +1,8 @@ extends Control +var mousepos + func _fixed_process(delta): var modetext = "Mode:\n" @@ -31,7 +33,7 @@ func _fixed_process(delta): get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) ) - get_node("Label_MousePosition").set_text(str("Mouse Position:\n", Input.get_mouse_pos() ) ) + get_node("Label_MousePosition").set_text(str("Mouse Position:\n", mousepos ) ) get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) ) @@ -126,6 +128,12 @@ func check_wm_api(): func _ready(): if( check_wm_api() ): set_fixed_process(true) + set_process_input(true) + + +func _input(ev): + if (ev.type==InputEvent.MOUSE_MOTION): + mousepos = ev.pos func _on_Button_MoveTo_pressed(): diff --git a/demos/misc/window_management/window_management.scn b/demos/misc/window_management/window_management.scn index c7d6260df620d50d0960fb0dcf6e8df43db9eadc..8db43b6638bc3aac053622591dacb4f0d6893eb4 100644 GIT binary patch delta 2243 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 AegFUf From 786b5e3545ea45557c699d74732d62cbcb2337a0 Mon Sep 17 00:00:00 2001 From: yg2f Date: Thu, 7 May 2015 18:10:30 +0200 Subject: [PATCH 14/15] fixes_demo3d_shaders_materials_missing_light add the missing animated light to the demo 3d "shaders materials" --- .../3d/shader_materials/shader_materials.scn | Bin 5494 -> 6382 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/3d/shader_materials/shader_materials.scn b/demos/3d/shader_materials/shader_materials.scn index d6a3efe73f74c8beb0118f2ebb420da894fbc4da..243c6c8f06b728ecc2e990f872d2aeecb70799ee 100644 GIT binary patch delta 6118 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 VWME-nU@$f|whsypat00V0|4iJIGq3h delta 5215 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 O8ynjP1qV5UMil|u#vwxh From 32c0a962491fd6d4125688b03b33efda20f5600d Mon Sep 17 00:00:00 2001 From: yg2f Date: Thu, 7 May 2015 18:29:38 +0200 Subject: [PATCH 15/15] add_missing_textures_to_particles --- demos/3d/platformer/coin.scn | Bin 6013 -> 6791 bytes demos/3d/platformer/enemy.scn | Bin 36976 -> 37784 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/3d/platformer/coin.scn b/demos/3d/platformer/coin.scn index 449bb0f89589a0b122bc635c9d84b97d268f98ce..a4148b406079a3cdd922232a5980d4feb280365e 100644 GIT binary patch delta 5657 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 delta 10657 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