Esempio n. 1
0
int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_VOLUME:
		set_volume(client, ctrl->value);
		break;
	case V4L2_CID_AUDIO_BASS:
		set_bass(client, ctrl->value);
		break;
	case V4L2_CID_AUDIO_TREBLE:
		set_treble(client, ctrl->value);
		break;
	case V4L2_CID_AUDIO_BALANCE:
		set_balance(client, ctrl->value);
		break;
	case V4L2_CID_AUDIO_MUTE:
		set_mute(client, ctrl->value);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Esempio n. 2
0
static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct v4l2_subdev *sd = to_sd(ctrl);
	struct cx25840_state *state = to_state(sd);
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_VOLUME:
		if (state->mute->val)
			set_volume(client, 0);
		else
			set_volume(client, state->volume->val);
		break;
	case V4L2_CID_AUDIO_BASS:
		/* PATH1_EQ_BASS_VOL */
		cx25840_and_or(client, 0x8d9, ~0x3f,
					48 - (ctrl->val * 48 / 0xffff));
		break;
	case V4L2_CID_AUDIO_TREBLE:
		/* PATH1_EQ_TREBLE_VOL */
		cx25840_and_or(client, 0x8db, ~0x3f,
					48 - (ctrl->val * 48 / 0xffff));
		break;
	case V4L2_CID_AUDIO_BALANCE:
		set_balance(client, ctrl->val);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Esempio n. 3
0
static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct mt9v011 *core =
		container_of(ctrl->handler, struct mt9v011, ctrls);
	struct v4l2_subdev *sd = &core->sd;

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		core->global_gain = ctrl->val;
		break;
	case V4L2_CID_EXPOSURE:
		core->exposure = ctrl->val;
		break;
	case V4L2_CID_RED_BALANCE:
		core->red_bal = ctrl->val;
		break;
	case V4L2_CID_BLUE_BALANCE:
		core->blue_bal = ctrl->val;
		break;
	case V4L2_CID_HFLIP:
		core->hflip = ctrl->val;
		set_read_mode(sd);
		return 0;
	case V4L2_CID_VFLIP:
		core->vflip = ctrl->val;
		set_read_mode(sd);
		return 0;
	default:
		return -EINVAL;
	}

	set_balance(sd);
	return 0;
}
Esempio n. 4
0
static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct v4l2_subdev *sd = to_sd(ctrl);
	struct cx18 *cx = v4l2_get_subdevdata(sd);

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_VOLUME:
		set_volume(cx, ctrl->val);
		break;
	case V4L2_CID_AUDIO_BASS:
		set_bass(cx, ctrl->val);
		break;
	case V4L2_CID_AUDIO_TREBLE:
		set_treble(cx, ctrl->val);
		break;
	case V4L2_CID_AUDIO_BALANCE:
		set_balance(cx, ctrl->val);
		break;
	case V4L2_CID_AUDIO_MUTE:
		set_mute(cx, ctrl->val);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Esempio n. 5
0
/* ARGSUSED1 */
void
key(unsigned char key, int x, int y)
{
  switch (key) {
  case 'b':
    set_brighten();
    break;
  case 's':
    set_saturate();
    break;
  case 'c':
    set_contrast();
    break;
  case 'z':
    set_sharpen();
    break;
  case 'a':
    set_balance();
    break;
  case 'h':
    help();
    break;
  case '\033':
    exit(0);
    break;
  default:
    return;
  }
  glutPostRedisplay();
}
Esempio n. 6
0
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
{
	struct v4l2_control *ctrl = arg;

	switch (cmd) {
	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
		return set_audclk_freq(client, *(u32 *)arg);

	case VIDIOC_G_CTRL:
		switch (ctrl->id) {
		case V4L2_CID_AUDIO_VOLUME:
			ctrl->value = get_volume(client);
			break;
		case V4L2_CID_AUDIO_BASS:
			ctrl->value = get_bass(client);
			break;
		case V4L2_CID_AUDIO_TREBLE:
			ctrl->value = get_treble(client);
			break;
		case V4L2_CID_AUDIO_BALANCE:
			ctrl->value = get_balance(client);
			break;
		case V4L2_CID_AUDIO_MUTE:
			ctrl->value = get_mute(client);
			break;
		default:
			return -EINVAL;
		}
		break;

	case VIDIOC_S_CTRL:
		switch (ctrl->id) {
		case V4L2_CID_AUDIO_VOLUME:
			set_volume(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_BASS:
			set_bass(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_TREBLE:
			set_treble(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_BALANCE:
			set_balance(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_MUTE:
			set_mute(client, ctrl->value);
			break;
		default:
			return -EINVAL;
		}
		break;

	default:
		return -EINVAL;
	}

	return 0;
}
Esempio n. 7
0
void
main( void )
{
	int i;

	for( i=0; i<39; i++ ) {
		set_balance( i );
		printf("Left: %d       Right: %d \r\n",left, right );
	}
}
Esempio n. 8
0
pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
    pa_assert(map);
    pa_assert(v);

    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
    pa_return_val_if_fail(new_balance >= -1.0f, NULL);
    pa_return_val_if_fail(new_balance <= 1.0f, NULL);

    if (!pa_channel_map_can_lfe_balance(map))
        return v;

    return set_balance(v, map, new_balance, on_hfe, on_lfe);
}
int check_audio_ioctls(int fd_audio)
{
	int err = 0;

	err += set_bits(fd_audio);
	err += set_channels(fd_audio);
	err += set_speed(fd_audio);
#ifndef CONFIG_MX21ADS
	err += set_adder(fd_audio);
	err += set_balance(fd_audio);
#endif
	return err;
}
Esempio n. 10
0
static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++)
		mt9v011_write(sd, mt9v011_init_default[i].reg,
			       mt9v011_init_default[i].value);

	set_balance(sd);
	set_res(sd);
	set_read_mode(sd);

	return 0;
};
Esempio n. 11
0
static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct mt9v011 *core = to_mt9v011(sd);
	u8 i, n;
	n = ARRAY_SIZE(mt9v011_qctrl);

	for (i = 0; i < n; i++) {
		if (ctrl->id != mt9v011_qctrl[i].id)
			continue;
		if (ctrl->value < mt9v011_qctrl[i].minimum ||
		    ctrl->value > mt9v011_qctrl[i].maximum)
			return -ERANGE;
		v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
					ctrl->id, ctrl->value);
		break;
	}

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		core->global_gain = ctrl->value;
		break;
	case V4L2_CID_EXPOSURE:
		core->exposure = ctrl->value;
		break;
	case V4L2_CID_RED_BALANCE:
		core->red_bal = ctrl->value;
		break;
	case V4L2_CID_BLUE_BALANCE:
		core->blue_bal = ctrl->value;
		break;
	case V4L2_CID_HFLIP:
		core->hflip = ctrl->value;
		set_read_mode(sd);
		return 0;
	case V4L2_CID_VFLIP:
		core->vflip = ctrl->value;
		set_read_mode(sd);
		return 0;
	default:
		return -EINVAL;
	}

	set_balance(sd);

	return 0;
}
Esempio n. 12
0
void Channel::set_controller(int con,int val)
{
	switch (con)
	{
		case 5:   set_portamento_time(val); break;
		case 7:   set_volume(val); break;
		case 8:   set_balance(val); break;
		case 65:  set_portamento(val); break;
		case 64:  set_hold_pedal(val>=64); break;
		case 66:  set_sostenuto_pedal(val>=64); break;
		case 67:  set_soft_pedal(val>=64); break;
		case 68:  set_legato_pedal(val>=64); break;
		case 119: set_quick_release(val);
		case 120: panic(); break;
		case 121: reset_controllers(); break;
		case 123: release_all(); break;
		case 126: set_n_voices(val); break;
		case 127: set_n_voices(999); break;
		default:  set_user_controller(con,val); break;
	}
}
Esempio n. 13
0
Channel::Channel()
{
	volume=ONE;
	set_program(0);
	curr_prg.controller[NO_CONT]=1;
	quick_release=0;
	portamento_frames2=portamento_frames=0;
	do_portamento=false;
	pitchbend=ONE;
	n_voices=0;
	
	max_pitchbend=1.0;
	
	set_balance(64);
	
	pressed_keys.clear();
	held_keys.clear();
	sostenuto_keys.clear();
	hold_pedal_pressed=false;
	legato_pedal_pressed=false;
	curr_vol_factor=1.0;
}
Esempio n. 14
0
int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
{
	switch (ctrl->id) {
	case V4L2_CID_AUDIO_VOLUME:
		set_volume(cx, ctrl->value);
		break;
	case V4L2_CID_AUDIO_BASS:
		set_bass(cx, ctrl->value);
		break;
	case V4L2_CID_AUDIO_TREBLE:
		set_treble(cx, ctrl->value);
		break;
	case V4L2_CID_AUDIO_BALANCE:
		set_balance(cx, ctrl->value);
		break;
	case V4L2_CID_AUDIO_MUTE:
		set_mute(cx, ctrl->value);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Esempio n. 15
0
/* Deletion might require up to log(n) rotations */
void avltree_remove(struct avltree_node *node, struct avltree *tree)
{
	struct avltree_node *parent = get_parent(node);
	struct avltree_node *left = node->left;
	struct avltree_node *right = node->right;
	struct avltree_node *next;
	int is_left = is_left;

	if (node == tree->first)
		tree->first = avltree_next(node);
	if (node == tree->last)
		tree->last = avltree_prev(node);

	if (!left)
		next = right;
	else if (!right)
		next = left;
	else
		next = get_first(right);

	if (parent) {
		is_left = parent->left == node;
		set_child(next, parent, is_left);
	} else
		tree->root = next;

	if (left && right) {
		set_balance(get_balance(node), next);

		next->left = left;
		set_parent(next, left);

		if (next != right) {
			parent = get_parent(next);
			set_parent(get_parent(node), next);

			node = next->right;
			parent->left = node;
			is_left = 1;

			next->right = right;
			set_parent(next, right);
		} else {
			set_parent(parent, next);
			parent = next;
			node = parent->right;
			is_left = 0;
		}
		assert(parent != NULL);
	} else
		node = next;

	if (node)
		set_parent(parent, node);

	/*
	 * At this point, 'parent' can only be null, if 'node' is the
	 * tree's root and has at most one child.
	 *
	 * case 1: the subtree is now balanced but its height has
	 * decreased.
	 *
	 * case 2: the subtree is mostly balanced and its height is
	 * unchanged.
	 *
	 * case 3: the subtree is unbalanced and its height may have
	 * been changed during the rebalancing process, see below.
	 *
	 * case 3.1: after a left rotation, the subtree becomes mostly
	 * balanced and its height is unchanged.
	 *
	 * case 3.2: after a left rotation, the subtree becomes
	 * balanced but its height has decreased.
	 *
	 * case 3.3: after a left and a right rotation, the subtree
	 * becomes balanced or mostly balanced but its height has
	 * decreased for all cases.
	 */
	while (parent) {
		int balance;
		node   = parent;
		parent = get_parent(parent);

		if (is_left) {
			is_left = parent && parent->left == node;

			balance = inc_balance(node);
			if (balance == 0)		/* case 1 */
				continue;
			if (balance == 1)		/* case 2 */
				return;
			right = node->right;		/* case 3 */
			switch (get_balance(right)) {
			case 0:				/* case 3.1 */
				set_balance( 1, node);
				set_balance(-1, right);
				rotate_left(node, tree);
				return;
			case 1:				/* case 3.2 */
				set_balance(0, node);
				set_balance(0, right);
				break;
			case -1:			/* case 3.3 */
				switch (get_balance(right->left)) {
				case 1:
					set_balance(-1, node);
					set_balance( 0, right);
					break;
				case 0:
					set_balance(0, node);
					set_balance(0, right);
					break;
				case -1:
					set_balance(0, node);
					set_balance(1, right);
					break;
				}
				set_balance(0, right->left);

				rotate_right(right, tree);
			}
			rotate_left(node, tree);
		} else {
			is_left = parent && parent->left == node;

			balance = dec_balance(node);
			if (balance == 0)
				continue;
			if (balance == -1)
				return;
			left = node->left;
			switch (get_balance(left)) {
			case 0:
				set_balance(-1, node);
				set_balance(1, left);
				rotate_right(node, tree);
				return;
			case -1:
				set_balance(0, node);
				set_balance(0, left);
				break;
			case 1:
				switch (get_balance(left->right)) {
				case 1:
					set_balance(0, node);
					set_balance(-1, left);
					break;
				case 0:
					set_balance(0, node);
					set_balance(0, left);
					break;
				case -1:
					set_balance(1, node);
					set_balance(0, left);
					break;
				}
				set_balance(0, left->right);

				rotate_left(left, tree);
			}
			rotate_right(node, tree);
		}
	}
	tree->height--;
}
Esempio n. 16
0
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
{
	struct cx25840_state *state = i2c_get_clientdata(client);
	struct v4l2_control *ctrl = arg;
	int retval;

	switch (cmd) {
	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
		if (!state->is_cx25836)
			cx25840_and_or(client, 0x810, ~0x1, 1);
		if (state->aud_input != CX25840_AUDIO_SERIAL) {
			cx25840_and_or(client, 0x803, ~0x10, 0);
			cx25840_write(client, 0x8d3, 0x1f);
		}
		retval = set_audclk_freq(client, *(u32 *)arg);
		if (state->aud_input != CX25840_AUDIO_SERIAL) {
			cx25840_and_or(client, 0x803, ~0x10, 0x10);
		}
		if (!state->is_cx25836)
			cx25840_and_or(client, 0x810, ~0x1, 0);
		return retval;

	case VIDIOC_G_CTRL:
		switch (ctrl->id) {
		case V4L2_CID_AUDIO_VOLUME:
			ctrl->value = get_volume(client);
			break;
		case V4L2_CID_AUDIO_BASS:
			ctrl->value = get_bass(client);
			break;
		case V4L2_CID_AUDIO_TREBLE:
			ctrl->value = get_treble(client);
			break;
		case V4L2_CID_AUDIO_BALANCE:
			ctrl->value = get_balance(client);
			break;
		case V4L2_CID_AUDIO_MUTE:
			ctrl->value = get_mute(client);
			break;
		default:
			return -EINVAL;
		}
		break;

	case VIDIOC_S_CTRL:
		switch (ctrl->id) {
		case V4L2_CID_AUDIO_VOLUME:
			set_volume(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_BASS:
			set_bass(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_TREBLE:
			set_treble(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_BALANCE:
			set_balance(client, ctrl->value);
			break;
		case V4L2_CID_AUDIO_MUTE:
			set_mute(client, ctrl->value);
			break;
		default:
			return -EINVAL;
		}
		break;

	default:
		return -EINVAL;
	}

	return 0;
}
Esempio n. 17
0
int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
{
	struct cx18_av_state *state = &cx->av_state;
	struct v4l2_control *ctrl = arg;
	int retval;

	switch (cmd) {
	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
		if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
			cx18_av_and_or(cx, 0x803, ~0x10, 0);
			cx18_av_write(cx, 0x8d3, 0x1f);
		}
		cx18_av_and_or(cx, 0x810, ~0x1, 1);
		retval = set_audclk_freq(cx, *(u32 *)arg);
		cx18_av_and_or(cx, 0x810, ~0x1, 0);
		if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
			cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
		return retval;

	case VIDIOC_G_CTRL:
		switch (ctrl->id) {
		case V4L2_CID_AUDIO_VOLUME:
			ctrl->value = get_volume(cx);
			break;
		case V4L2_CID_AUDIO_BASS:
			ctrl->value = get_bass(cx);
			break;
		case V4L2_CID_AUDIO_TREBLE:
			ctrl->value = get_treble(cx);
			break;
		case V4L2_CID_AUDIO_BALANCE:
			ctrl->value = get_balance(cx);
			break;
		case V4L2_CID_AUDIO_MUTE:
			ctrl->value = get_mute(cx);
			break;
		default:
			return -EINVAL;
		}
		break;

	case VIDIOC_S_CTRL:
		switch (ctrl->id) {
		case V4L2_CID_AUDIO_VOLUME:
			set_volume(cx, ctrl->value);
			break;
		case V4L2_CID_AUDIO_BASS:
			set_bass(cx, ctrl->value);
			break;
		case V4L2_CID_AUDIO_TREBLE:
			set_treble(cx, ctrl->value);
			break;
		case V4L2_CID_AUDIO_BALANCE:
			set_balance(cx, ctrl->value);
			break;
		case V4L2_CID_AUDIO_MUTE:
			set_mute(cx, ctrl->value);
			break;
		default:
			return -EINVAL;
		}
		break;

	default:
		return -EINVAL;
	}

	return 0;
}
Esempio n. 18
0
/* Insertion never needs more than 2 rotations */
struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree)
{
	struct avltree_node *key, *parent, *unbalanced;
	int is_left;

	key = do_lookup(node, tree, &parent, &unbalanced, &is_left);
	if (key)
		return key;

	INIT_NODE(node);

	if (!parent) {
		tree->root = node;
		tree->first = tree->last = node;
		tree->height++;
		return NULL;
	}
	if (is_left) {
		if (parent == tree->first)
			tree->first = node;
	} else {
		if (parent == tree->last)
			tree->last = node;
	}
	set_parent(parent, node);
	set_child(node, parent, is_left);

	for (;;) {
		if (parent->left == node)
			dec_balance(parent);
		else
			inc_balance(parent);

		if (parent == unbalanced)
			break;
		node = parent;
		parent = get_parent(parent);
	}

	switch (get_balance(unbalanced)) {
	case  1: case -1:
		tree->height++;
		/* fall through */
	case 0:
		break;
	case 2: {
		struct avltree_node *right = unbalanced->right;

		if (get_balance(right) == 1) {
			set_balance(0, unbalanced);
			set_balance(0, right);
		} else {
			switch (get_balance(right->left)) {
			case 1:
				set_balance(-1, unbalanced);
				set_balance( 0, right);
				break;
			case 0:
				set_balance(0, unbalanced);
				set_balance(0, right);
				break;
			case -1:
				set_balance(0, unbalanced);
				set_balance(1, right);
				break;
			}
			set_balance(0, right->left);

			rotate_right(right, tree);
		}
		rotate_left(unbalanced, tree);
		break;
	}
	case -2: {
		struct avltree_node *left = unbalanced->left;

		if (get_balance(left) == -1) {
			set_balance(0, unbalanced);
			set_balance(0, left);
		} else {
			switch (get_balance(left->right)) {
			case 1:
				set_balance( 0, unbalanced);
				set_balance(-1, left);
				break;
			case 0:
				set_balance(0, unbalanced);
				set_balance(0, left);
				break;
			case -1:
				set_balance(1, unbalanced);
				set_balance(0, left);
				break;
			}
			set_balance(0, left->right);

			rotate_left(left, tree);
		}
		rotate_right(unbalanced, tree);
		break;
	}
	}
	return NULL;
}
Esempio n. 19
0
int fwAvlInsert(uint32_t key, void* data, struct FwAvlTree* tree)
{
    int is_left;
    struct FwAvlNode* parent;
    struct FwAvlNode* right;
    struct FwAvlNode* left;
    struct FwAvlNode* unbalanced;
    struct FwAvlNode* node;

    if(do_lookup(key, tree, &parent, &unbalanced, &is_left) != NULL)
        return 1;

    if(!(node = new_node(key, data)))
        return -1;

    tree->count++;
    if(parent == NULL)
    {
        tree->root = node;
        tree->first = node;
        tree->last = node;
        return 0;
    }

    if(is_left != 0)
    {
        if(parent == tree->first)
            tree->first = node;
    }
    else
    {
        if(parent == tree->last)
            tree->last = node;
    }
    set_parent(parent, node);
    set_child(node, parent, is_left);

    while(1)
    {
        if(parent->left == node)
            dec_balance(parent);
        else
            inc_balance(parent);

        if(parent == unbalanced)
            break;

        node = parent;
        parent = get_parent(node);
    }

    switch(get_balance(unbalanced))
    {
        case 1:
        case -1:
            tree->height++;
            break;
        case 0:
            break;
        case 2:
            right = unbalanced->right;

            if(get_balance(right) == 1)
            {
                set_balance(0, unbalanced);
                set_balance(0, right);
            }
            else
            {
                switch(get_balance(right->left))
                {
                    case 1:
                        set_balance(-1, unbalanced);
                        set_balance(0, right);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, right);
                        break;
                    case -1:
                        set_balance(0, unbalanced);
                        set_balance(1, right);
                        break;
                }
                set_balance(0, right->left);
                rotate_right(right, tree);
            }
            rotate_left(unbalanced, tree);
            break;
        case -2:
            left = unbalanced->left;

            if(get_balance(left) == -1)
            {
                set_balance(0, unbalanced);
                set_balance(0, left);
            }
            else
            {
                switch(get_balance(left->right))
                {
                    case 1:
                        set_balance(0, unbalanced);
                        set_balance(-1, left);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, left);
                        break;
                    case -1:
                        set_balance(1, unbalanced);
                        set_balance(0, left);
                        break;
                }
                set_balance(0, left->right);
                rotate_left(left, tree);
            }
            rotate_right(unbalanced, tree);
            break;
    }
    return 0;
}
Esempio n. 20
0
/* Insertion never needs more than 2 rotations */
struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree) {
    struct avltree_node *parent = 0, *unbalanced = tree->root;
    bool is_left;

    // Find a suitable parent.
    for (struct avltree_node *next_parent = tree->root; next_parent != 0;) {
        parent = next_parent;
        if (get_balance(parent) != 0)
            unbalanced = parent;
        int cmp_r = tree->cmp_fn(parent, node);
        if (cmp_r == 0) {
            if (tree->unique_index)
                return parent;
            // For non unique indexes any insert direction is acceptable.
            if (parent->left == 0) {
                is_left = true;
                break;
            } else if (parent->right == 0) {
                is_left = false;
                break;
            } else {
                // Be smart and travel to the least balanced subtree to minimize balancing overhead.
                next_parent = (get_balance(parent) <= 0)? parent->left: parent->right;
            }
        } else {
            is_left = (cmp_r > 0);
            next_parent = is_left? parent->left: parent->right;
        }
    }

    INIT_NODE(node);

    if (!parent) {
        tree->root = node;
        tree->first = tree->last = node;
        tree->height++;
        return 0;
    }
    if (is_left) {
        if (parent == tree->first)
            tree->first = node;
    } else {
        if (parent == tree->last)
            tree->last = node;
    }
    set_parent(parent, node);
    set_child(node, parent, is_left);

    for (;;) {
        if (parent->left == node)
            dec_balance(parent);
        else
            inc_balance(parent);

        if (parent == unbalanced) {
            for (;;) {
                node = parent;
                node->count++;
                if (is_root(node))
                    break;
                parent = get_parent(parent);
            }
            break;
        }
        node = parent;
        node->count++;
        parent = get_parent(parent);
    }

    switch (get_balance(unbalanced)) {
        case 1: case -1:
            tree->height++;
            /* fall through */
        case 0:
            break;
        case 2:
        {
            struct avltree_node *right = unbalanced->right;

            if (get_balance(right) == 1) {
                set_balance(0, unbalanced);
                set_balance(0, right);
            } else {
                switch (get_balance(right->left)) {
                    case 1:
                        set_balance(-1, unbalanced);
                        set_balance(0, right);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, right);
                        break;
                    case -1:
                        set_balance(0, unbalanced);
                        set_balance(1, right);
                        break;
                }
                set_balance(0, right->left);

                rotate_right(right, tree);
            }
            rotate_left(unbalanced, tree);
            break;
        }
        case -2:
        {
            struct avltree_node *left = unbalanced->left;

            if (get_balance(left) == -1) {
                set_balance(0, unbalanced);
                set_balance(0, left);
            } else {
                switch (get_balance(left->right)) {
                    case 1:
                        set_balance(0, unbalanced);
                        set_balance(-1, left);
                        break;
                    case 0:
                        set_balance(0, unbalanced);
                        set_balance(0, left);
                        break;
                    case -1:
                        set_balance(1, unbalanced);
                        set_balance(0, left);
                        break;
                }
                set_balance(0, left->right);

                rotate_left(left, tree);
            }
            rotate_right(unbalanced, tree);
            break;
        }
    }
    return 0;
}